注意:本文的内容不是介绍如何在Windows下编译OpenSSL,而是编译好以后,如何在Windows命令提示符界面下编译链接OpenSSL自带的一个示例程序base64.c。
以前已经把下载的 openssl 1.0.1c 源代码压缩包解压到了 F:\openssl 路径下,并在64位Win7下使用VS2010编译生成了64位的库文件。
发现 F:\openssl\demos\eay 目录下有一个名为 base64.c 的文件,想编译运行它,但又不想进入Visual Studio的IDE,想起来VS自带的cl.exe就可以编译链接C程序,就在F盘随手建立了一个test目录,把base64.c拷贝到 F:\test 路径下,然后启动Visual Studio命令提示符界面,执行 cl base64.c 命令,提示出错:
fatal error C1083: 无法打开包括文件:“openssl/bio.h”: No such file or directory
把bio.h复制过来,把base64.c文件中的语句 #include <openssl/bio.h> 改为 #include "bio.h",再试还是不行,提示找不到头文件evp.h,把evp.h也拷贝过来,再试,发现这两个头文件还包含了其他很多头文件,用最笨的办法:把那些文件都拷贝过来,再修改它们内部的 #include <openssl/*.h> 为 #include "*.h"。工作量很大,折腾了好久,头文件包含没有问题了,能编译,但是到链接时又出错,提示为:
base64.obj: error LNK2019: 无法解析的外部符号 BIO_...,该符号在函数 main 中被引用
这样的错误有7个。把openssl\out32 路径下的静态库文件libeay32.lib拷贝到test.c所在的 F:\test 目录下,还是不行,这下傻眼了。
同事帮我发现了问题:自己以前编译好的openssl库文件都是64位的,而现在启动命令提示符界面时,是在 “开始”菜单 -> Microsoft Visual Studio 2010 -> Visual Studio Tools 列表中选中Visual Studio 命令提示(2010),这时VC配置的环境是32位,所用到的cl.exe也是32位,当然与编译好的库文件不匹配了。
于是在“开始”菜单 -> Microsoft Visual Studio 2010 -> Visual Studio Tools 列表中选中 Visual Studio x64 Win64 命令提示(2010),这时弹出的命令提示符窗口中各种VC相关环境变量都是符合64位环境的,cl.exe程序也是64位版本的。执行命令:
cl base64.c libeay32.lib
还是出现error LNK2019错误,不过此时找不到的函数是show_fatal和is_services,在网上搜索函数showfatal()和isservices(),发现这两个函数分别在user32.lib advapi32.lib中,使用下面的命令
cl base64.c libeay32.lib user32.lib advapi32.lib
就能够顺利编译链接并生成base64.exe文件了。
在网上查了一下cl.exe的参数,发现前面把多个头文件拷贝到 F:\test 目录下并修改的做法太笨了,可以使用 /I 参数(I 是小写字母 i 对应的大写字母,在网页上看起来和大写字母 L 对应的小写字母几乎一样,别搞错了!),使用下面的命令
cl base64.c /I "F:\openssl\inc32" libeay32.lib user32.lib advapi32.lib
就能顺利编译链接并生成base64.exe文件。
/I 参数后面加上路径以后, cl.exe 在找包含的头文件时就会到该路径下去搜索。
openssl目录下和头文件相关的子目录有inc32和include,注意include\openssl 路径下的头文件有75个,大小都是 1KB,内容都是指向其他目录下的头文件,例如
头文件aes.h的内容是../../crypto/aes/aes.h,而 openssl\crypto\aes 路径下的aes.h的文件大小为6KB,openssl\inc32\openssl 路径下的aes.h文件大小也是6KB,这两个大小相同的文件其内容也相同。
因此我们在编程时,应该设置包含头文件的路径为 openssl\inc32,而不是 openssl\include。例如使用命令
cl base64.c /I "F:\openssl\include" libeay32.lib user32.lib advapi32.lib
会提示错误:error C2059: 语法错误:“.”
而使用命令
cl base64.c /I "F:\openssl\inc32" libeay32.lib user32.lib advapi32.lib
就不会出错。
如果不把openssl\out32 路径下的静态库文件libeay32.lib拷贝到test.c所在的 F:\test 目录下,就要用cl.exe的 /link /LIBPATH: 参数(注意:冒号不能少)来指定链接时库文件所在的目录,使用命令
cl base64.c /I "F:\openssl\inc32" /link /LIBPATH:"F:\openssl\out32" libeay32.lib user32.lib advapi32.lib
同样可以正确编译链接并生成base64.exe文件。