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_digestSM2_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.alibcrypto.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.csetsockoptgetsockopt 的参数类型错误(传递 int* 但需要 char*)。
解决:在调用处添加强制类型转换:

  • setsockopt(..., (const char *)&on, ...)
  • getsockopt(..., (char *)&socktype, ...)

7. 修复 Windows 类型重定义

错误sgd.h 中定义的 BOOLCHAR 等与 Windows 系统头文件冲突。
解决

  • sgd.h 开头添加 #include <windows.h>
  • 修改文件末尾的 Windows 分支(#else),将其中 #ifndef _WINDEF_H 内部的类型定义全部移除,因为这些类型已由 windows.h 提供。

8. 修复原子操作类型不匹配

错误crypto/threads_win.cInterlockedExchangeAdd 需要 long volatile*,但传递的是 int*
解决 :在调用处强制转换为 (long volatile *)val

9. 修复哈希表函数参数错误

错误crypto/objects/o_names.c 中将 OBJ_NAME* 强制转换为 const char* 后传递给哈希表检索/删除函数。
解决 :移除错误强制转换,直接传递 &on

10. 修复测试代码类型错误

错误test/threadstest.cCRYPTO_THREAD_run_once 的参数被错误强制转换为 const char*
解决 :移除强制转换,直接传递 &once_run

11. 最终编译成功

执行 makemake install,生成的头文件和库位于 /h/gmssl-old-install

  • 头文件:include/openssl/sm2.h
  • 库文件:lib/libcrypto.alib/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.dlllibssl-1_1-x64.dll 复制到 Qt 项目的输出目录(如 Debug/)。

3. 重新构建

在 Qt Creator 中执行"清理所有"并重新构建,项目成功生成 protolib.dll

五、总结

本次排查的核心是识别出项目对 GmSSL 老版本的依赖,并通过逐一手动修复老代码与现代工具链的兼容性问题,最终成功编译并集成。主要经验:

  • 老旧开源库在新版编译环境中常会遇到类型严格检查、头文件依赖等问题,需耐心分析错误并针对性修改。
  • 修改源码时尽量保持最小改动,避免引入新问题。
  • 使用 nm 工具检查库中符号可快速验证函数是否导出。

整个过程中共修改了 6 个文件,涉及 Perl 脚本、C 源码和头文件,体现了跨平台开发的细致性。希望这份记录能为后续类似问题提供参考。

相关推荐
y = xⁿ1 小时前
【Java八股锁机制的认识】synchronized和reentrantlock区分,锁升级机制
java·开发语言·后端
free-elcmacom1 小时前
C++三种参数传递方式:从交换函数看值、指针与引用的区别
开发语言·c++
bubiyoushang8881 小时前
基于PSO的列车速度优化MATLAB实现
开发语言·人工智能·matlab
曹牧2 小时前
C#:线程中实现延时等待
开发语言·c#
蜜獾云2 小时前
java 异步编程
java·开发语言
xin^_^2 小时前
java基础学习
java·开发语言·python
坐吃山猪2 小时前
Tree-sitter语法树解析
开发语言·python·tree-sitter
清水白石0082 小时前
《解锁 Python 潜能:从内存模型看可变与不可变对象,及其实战最佳实践》
大数据·开发语言·python
IT19952 小时前
C++工作笔记-动态库中的单例类存储方式
开发语言·c++·笔记