GmSSL 编译与 Qt 项目集成问题排查记录(-lssl-1_1-x64 -lcrypto-1_1-x64)

目录

  • [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. 重新构建)
    • 五、总结

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 源码和头文件,体现了跨平台开发的细致性。希望这份记录能为后续类似问题提供参考。

相关推荐
Sarvartha6 小时前
final 关键字
java·开发语言
程序员Sunday7 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Quz7 小时前
QML 动画选择:GIF与Lottie 的区别,以及 Qt 6.8 与 6.11 的 Lottie 实现差异
qt
zhangzeyuaaa8 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
谢亮_vipxieliang9 小时前
用 PHP 构建轻量级 REST API:从路由到鉴权的完整实践
开发语言·后端·php
思无邪669 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
H.莓飛10 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
零基础12310 小时前
Ubuntu 常用命令汇总
linux·运维·开发语言
外收内放11 小时前
Python基础语法练习题(57-58)
开发语言·python
时间的拾荒人11 小时前
Qt 界面美化实战:QSS 样式表
开发语言·qt·面试