目录
- [GmSSL 编译与 Qt 项目集成问题排查记录](#GmSSL 编译与 Qt 项目集成问题排查记录)
-
- 一、背景
- 二、环境
- 三、问题排查与解决步骤
-
- [1. 解决 OpenSSL 库文件缺失](#1. 解决 OpenSSL 库文件缺失)
- [2. 发现项目实际依赖 GmSSL](#2. 发现项目实际依赖 GmSSL)
- [3. 尝试 GmSSL 3.x 版本](#3. 尝试 GmSSL 3.x 版本)
- [4. 改用 GmSSL-gmbrowser-v0.1(老版本------重中之重!!!)](#4. 改用 GmSSL-gmbrowser-v0.1(老版本——重中之重!!!))
- [5. 修复 Perl 配置错误](#5. 修复 Perl 配置错误)
- [6. 修复 socket 函数参数类型不匹配](#6. 修复 socket 函数参数类型不匹配)
- [7. 修复 Windows 类型重定义](#7. 修复 Windows 类型重定义)
- [8. 修复原子操作类型不匹配](#8. 修复原子操作类型不匹配)
- [9. 修复哈希表函数参数错误](#9. 修复哈希表函数参数错误)
- [10. 修复测试代码类型错误](#10. 修复测试代码类型错误)
- [11. 最终编译成功](#11. 最终编译成功)
- [四、Qt 项目集成](#四、Qt 项目集成)
-
- [1. 修改 `.pro` 文件](#1. 修改
.pro文件) - [2. 部署运行时 DLL](#2. 部署运行时 DLL)
- [3. 重新构建](#3. 重新构建)
- [1. 修改 `.pro` 文件](#1. 修改
- 五、总结
GmSSL 编译与 Qt 项目集成问题排查记录
一、背景
接手一个 Qt 项目(protolib),该项目使用了国密 SM2 算法,头文件中声明了 SM2_compute_id_digest、SM2_do_sign 等函数,并在 .pro 文件中链接了 -lssl-1_1-x64 和 -lcrypto-1_1-x64。项目最初因找不到这些库而导致链接失败,后续又因缺少这些函数的实现而报 undefined reference。
主要问题:


二、环境
- 操作系统:Windows 10/11
- Qt 版本:5.13.0 MinGW 64-bit(自带 MinGW 7.3.0)
- 编译工具链:MSYS2 UCRT64(用于编译 GmSSL)
- Perl:MSYS2 自带 Perl 5.40
- GmSSL 版本:
- 尝试过 GmSSL 3.x(CMake 构建)
- 最终使用 GmSSL-gmbrowser-v0.1(基于 OpenSSL 1.0.2 风格)
三、问题排查与解决步骤
1. 解决 OpenSSL 库文件缺失
现象 :Qt 项目链接时提示 cannot find -lssl-1_1-x64。
原因 :项目要求的库名是带版本号的,而实际安装的 OpenSSL 库名为 libssl.dll.a。
解决:
- 使用 MSYS2 安装 OpenSSL 1.1.1,生成文件为
libssl.dll.a和libcrypto.dll.a。 - 在
.pro文件中修改为-lssl和-lcrypto,并添加库路径-LH:/openssl-install/lib。 - 或将导入库复制并重命名为
libssl-1_1-x64.dll.a。
2. 发现项目实际依赖 GmSSL
现象 :链接 OpenSSL 后,仍然出现 undefined reference to SM2_compute_id_digest 等。
原因 :项目中的 sm2.h 文件包含 GmSSL 版权声明,依赖 GmSSL 特有的国密接口,原生 OpenSSL 不提供这些函数。
解决:确认需编译并使用 GmSSL。
3. 尝试 GmSSL 3.x 版本
操作:
- 下载 GmSSL 3.x 源码,使用 CMake 配置编译。
- 生成
libgmssl.dll.a。
检查 :nm libgmssl.dll.a | grep SM2_compute_id_digest无输出,表明未导出所需函数。
结论:GmSSL 3.x 可能未包含这些特定接口,需改用老版本。
4. 改用 GmSSL-gmbrowser-v0.1(老版本------重中之重!!!)
下载源码解压至 H:/GM0.1/GmSSL-gmbrowser-v0.1。
在尝试了诸多版本之后在GMSSL网址的犄角旮旯里找到了第一版的gmssl,当时为什么会觉得是它,因为在它的介绍中出现了SM2的字样,让我 眼前一亮,贴一个网址https://github.com/guanzhi/GmSSL/releases,再附一张图片,以彰显我的坚持不懈和敏锐的嗅觉!

5. 修复 Perl 配置错误
错误 :运行 perl Configure mingw64 --prefix=/h/gmssl-old-install 时,报 "glob" is not exported by the File::Glob module。
原因 :老版本 Configure 中使用了 qw/glob/ 导入方式,新版 Perl 要求使用 :bsd_glob。
解决 :修改 Configure 文件,将所有 'File::Glob' => qw/glob/ 替换为 'File::Glob' => qw/:bsd_glob/。同样修改 test/build.info 中的类似语句。
6. 修复 socket 函数参数类型不匹配
错误 :crypto/bio/b_sock2.c 中 setsockopt 和 getsockopt 的参数类型错误(传递 int* 但需要 char*)。
解决:在调用处添加强制类型转换:
setsockopt(..., (const char *)&on, ...)getsockopt(..., (char *)&socktype, ...)
7. 修复 Windows 类型重定义
错误 :sgd.h 中定义的 BOOL、CHAR 等与 Windows 系统头文件冲突。
解决:
- 在
sgd.h开头添加#include <windows.h>。 - 修改文件末尾的 Windows 分支(
#else),将其中#ifndef _WINDEF_H内部的类型定义全部移除,因为这些类型已由windows.h提供。
8. 修复原子操作类型不匹配
错误 :crypto/threads_win.c 中 InterlockedExchangeAdd 需要 long volatile*,但传递的是 int*。
解决 :在调用处强制转换为 (long volatile *)val。
9. 修复哈希表函数参数错误
错误 :crypto/objects/o_names.c 中将 OBJ_NAME* 强制转换为 const char* 后传递给哈希表检索/删除函数。
解决 :移除错误强制转换,直接传递 &on。
10. 修复测试代码类型错误
错误 :test/threadstest.c 中 CRYPTO_THREAD_run_once 的参数被错误强制转换为 const char*。
解决 :移除强制转换,直接传递 &once_run。
11. 最终编译成功
执行 make 和 make install,生成的头文件和库位于 /h/gmssl-old-install:
- 头文件:
include/openssl/sm2.h等 - 库文件:
lib/libcrypto.a、lib/libssl.a(静态库)以及导入库和 DLL。 - 我的pro文件中明确有
-lssl-1_1-x64 -lcrypto-1_1-x64,所以需要把bin目录下的这俩文件复制且加个.a的后缀至lib文件夹下。


四、Qt 项目集成
1. 修改 .pro 文件
qmake
INCLUDEPATH += "H:/gmssl-old-install/include"
LIBS += -L"H:/gmssl-old-install/lib" -lssl-1_1-x64 -lcrypto-1_1-x64 -lws2_32
2. 部署运行时 DLL
将 H:/gmssl-old-install/bin 下的 libcrypto-1_1-x64.dll 和 libssl-1_1-x64.dll 复制到 Qt 项目的输出目录(如 Debug/)。
3. 重新构建
在 Qt Creator 中执行"清理所有"并重新构建,项目成功生成 protolib.dll。
五、总结
本次排查的核心是识别出项目对 GmSSL 老版本的依赖,并通过逐一手动修复老代码与现代工具链的兼容性问题,最终成功编译并集成。主要经验:
- 老旧开源库在新版编译环境中常会遇到类型严格检查、头文件依赖等问题,需耐心分析错误并针对性修改。
- 修改源码时尽量保持最小改动,避免引入新问题。
- 使用
nm工具检查库中符号可快速验证函数是否导出。
整个过程中共修改了 6 个文件,涉及 Perl 脚本、C 源码和头文件,体现了跨平台开发的细致性。希望这份记录能为后续类似问题提供参考。