Qt开发OpenSSL程序踩坑

背景

分别由两个人开发的代码需要被整合进入一个完整的项目并运行。

其中第一位同学使用Visual Studio开发基于C++和openSSL的加解密的程序,使用vcpkg安装和编译openSSL:x86-windows并且集成到Visual Studio中。另一位同学使用Qt Creator开发基于C++和Qt的GUI程序。

IDE选择

由于需要将两份代码合成一个完整的项目运行,我首先选择IDE为Visual Studio,但是由于并没有在VS中写过Qt程序,添加的QT VS TOOL插件总是无法正常编译。因此放弃使用Visual Studio作为项目IDE。选择Qt Creator作为开发环境。

编译

遇到的第一个问题是将openSSL集成到Qt Creator,从网上找到的资料都是从OpenSSL官网下载,并在Qt项目文件中添加库和头文件路径。如下代码所示

LIBS += \
    -Lpath/lib -lssl \
    -Lpath/lib -lcrypto
INCLUDEPATH += path/include

我遇到的问题是,添加头文件正常,但是在编译的时候会出现undefined reference to xxx的报错,仔细一看是openssl库中的函数,在代码中follow symbols可以跳转到头文件中对应的定义,因此猜测是头文件正常但库文件没有正常加载。

这里涉及到的我尝试过的库文件包括

libssl.lib
libcrypto.lib
libssl.a
libcrypto.a
libssl.dll.a
libcrypto.dll.a
libssl-1_1.dll
libcrypto-1_1.dll
libeay32.dll
ssleay32.dll
...

于是开始各种下载和添加库文件。包括但不限于

  1. 使用vcpkg编译x64-windows版本的openssl库并添加(考虑到32位和64位可能产生的冲突)
  2. 官网下载openssl安装包(由于下载速度太慢,我选择了64位light版本的安装包,但是light版本安装包没有lib文件,完整版本的安装包就不曾下载成功过)
  3. 将lib和include文件copy到项目目录下,再使用上述方法添加路径。

在这个时候,我查到一篇文章说qt本身是包括openssl的但是在编译的时候默认不安装,因此qt的环境下实际上是包括openssl对应的库文件和头文件的。经过一番查找我找到这个路径C:\Qt\Qt5.12.0\Tools\mingw730_64\opt

这个路径的lib目录下包括了libssl.a、libcrypto.a、libssl.dll.a、libcrypto.dll.a,bin目录下包括libeay32.dll、ssleay32.dll,include目录下包括openssl头文件目录。因此我修改.pro文件如下。

# 这里的$$quote我也没搞清啥意思,大概是双引号

LIBS += \
    -LC:\Qt\Qt5.12.0\Tools\mingw730_64\opt\lib -lssl \
    -LC:\Qt\Qt5.12.0\Tools\mingw730_64\opt\lib -lcrypto

INCLUDEPATH += \
    $$quote(C:\Qt\Qt5.12.0\Tools\mingw730_64\opt\include)

经过多次编译,并注释掉一些无用的函数,终于实现了0 warnigns, 0 errors,呜呼。

运行

接下来遇到的问题是,程序无法运行。在Qt Creator中直接运行,程序闪退并显示程序异常结束。在Qt Creator中开启Debugger,同样也是闪退,添加的断点直接被无视了。

刚开始考虑到可能是被杀毒软件杀掉了,因此经过一番操作关闭了Windows Defender,但是仍然无法运行,陷入停滞。

这个时候查到一篇文章,详细介绍了Qt Creator中的闪退的原因并给出了一个检查的方法,就是找到编译生成的exe文件,直接双击运行。程序自然无法运行并提示缺少许多dll文件,其中包括qt的依赖库例如QtCore.dll等等,因此使用windeployqt.exe(位于C:\Qt\Qt5.12.0\5.12.0\mingw73_64\bin)将Qt所有的依赖dll复制到exe对应的路径下,这个时候再次点击exe文件,显示缺少libeay32.dll于是将上述的libeay32.dll和ssleay32.dll(位于C:\Qt\Qt5.12.0\Tools\mingw730_64\opt\bin)复制到这个路径下。

双击exe,正常运行!!!经过测试,一切正常。每次使用qt编译后,将得到的exe文件拷贝到一个新的路径下,调用windeployqt和复制dll就可以正常运行。

总结反思

  1. 我使用Qt官网下载的安装包安装Qt时,IDE选择了QtCreator,编译环境我选择了MinGW和MSVC,因此在我的安装目录下(C:\Qt\Qt5.12.0\5.12.0)包括了如下四个编译环境,每一个环境中都包含了windeployqt等一系列exe文件,和完整的Qt编译环境(bin + lib + include)。

    mingw73_64

    msvc2015_64

    msvc2017

    msvc2017_64

    但是非常疑惑的一点是,在编译时我检查Qt Cretor的编译输出窗口,发现我编译使用的是Tools目录下的mingw730_64。进一步检查发现Tools目录下(C:\Qt\Qt5.12.0\Tools)包括如下目录。

    mingw730_64

    QtCreator

    前者不是一个完整的Qt编译环境,不包括qt的各种dll,而是包括了ar、ld、gcc、make、objdump等一系列工具,更像是一个编译环境。其opt目录下包括了openssl的编译环境(前文使用到的)。

    那么这两个不同的mingw环境究竟有什么区别呢?后者可不可以换成我之前自己手动安装的MinGW环境呢?

  2. 使用vcpkg编译得到的环境和使用官方安装包以及从GitHub直接下载手动编译的环境有什么区别。

  3. 对于库文件来说存不存在32位和64位的差异,如果不存在的话,那么vcpkg编译时为什么提供了x86-windows和x64-windows的不同的triplets(还包括了arm、linux等其他选择)。

  4. 函数静态库和动态库在使用时一定要同时存在么,即编译时指定lib文件,执行时exe文件路径中要包含对应的dll文件。

  5. vcpkg编译得到的libssl.lib和mingw730_64的opt路径下的libssl.a文件有什么差异,能不能简单通过改变后缀名来实现适配。同理还有.dll文件和.so文件之间的关系。

最后的最后,还是感觉任重而道远。上述问题大多都是操作系统和C语言编译的基础知识,还是要努力打好基础。

Lei Yang
Lei Yang
PhD candidate

My research interests include visual speech recognition and semantics segmentation.