GmSSL 3.1.1 跨平台静态库编译:Linux、macOS、Windows(MinGW)一键构建
一、前言
在项目开发过程中,需要使用 GmSSL 提供的国密算法能力,并将其集成到不同操作系统下的应用程序中。为了方便后续进行静态链接,避免依赖 GmSSL 动态库,编写了一个简单的 Shell 脚本,用于在 Linux、macOS 和 Windows(MinGW 环境)下编译生成 GmSSL 静态库。
本文使用的 GmSSL 版本为 v3.1.1,通过 CMake 配置编译选项,根据操作系统自动选择对应的构建工具,并支持多核并行编译。
脚本主要实现以下功能:
- 支持 Linux、macOS、Windows(MinGW/MSYS)平台。
- 使用 CMake 配置生成静态库
libgmssl.a。 - Windows 使用
MinGW Makefiles生成器和mingw32-make编译。 - 自动检测 CPU 核心数量,进行并行编译。
- 每次编译前自动清理旧的构建目录,避免不同平台的编译缓存相互影响。
需要注意的是,这里的跨平台指的是同一份脚本可以分别在三个平台的本地环境中运行,并不是在任意一台机器上直接交叉编译出所有平台的静态库。
二、GmSSL 简介
GmSSL 是北京大学开发的国产商用密码开源库,支持多种国密算法、密码标准和安全通信协议。
GitHub 项目地址:
GitHub - guanzhi/GmSSL: 支持国密SM2/SM3/SM4/SM9/SSL的密码工具箱 · GitHub
本文使用版本:
GitHub - guanzhi/GmSSL at v3.1.1 · GitHub
GmSSL 支持的密码算法包括 SM2、SM3、SM4、SM9 等,同时提供 C 语言接口,方便其他语言通过 FFI、CGO、JNI 等方式调用。
GmSSL 3.x 使用 CMake 作为构建系统,可以根据不同操作系统和编译工具生成对应的构建文件。
本文主要编译静态库:
libgmssl.a
静态库可以在应用程序链接阶段参与链接,适用于需要减少运行时第三方动态库依赖的场景。
三、编译环境准备
编译前,需要确保各平台已安装 CMake、C 编译器及相应的构建工具。
3.1 Linux
以 Ubuntu/Debian 为例,可以执行:
sudo apt update
sudo apt install -y \
build-essential \
cmake \
git
检查安装情况:
gcc --version
cmake --version
make --version
其中:
gcc:C 语言编译器。cmake:负责生成构建文件。make:负责执行编译任务。
其他 Linux 发行版可通过对应的包管理器安装这些工具。
3.2 macOS
macOS 可以通过 Xcode Command Line Tools 和 Homebrew 安装编译环境。
首先安装命令行开发工具:
xcode-select --install
然后安装 CMake:
brew install cmake
检查环境:
clang --version
cmake --version
make --version
macOS 通常默认使用 Clang 编译器。本文脚本要求 CMake 默认生成器能够使用 make,如环境使用了其他默认生成器,需要对应调整。
3.3 Windows(MinGW)
Windows 平台这里使用 MinGW-w64 编译工具链,而不是 Visual Studio/MSVC 编译器。
可以使用 MSYS2 提供的 MinGW-w64 环境。
MSYS2 官网:
安装 MSYS2 后,建议使用 MSYS2 MinGW x64 终端进行编译。
在对应终端安装所需工具:
pacman -S --needed \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-make \
git
安装完成后检查:
gcc --version
cmake --version
mingw32-make --version
需要注意,Windows 环境中可能同时存在 MSYS、MinGW、UCRT 等多种工具链,建议保持 CMake、GCC 和 Make 的运行环境一致,避免编译器或生成器不匹配。
本文使用的 MinGW Makefiles 生成器,需要配套使用 mingw32-make。
四、获取 GmSSL v3.1.1 源码
通过 Git 下载 GmSSL 源码:
git clone https://github.com/guanzhi/GmSSL.git
cd GmSSL
切换到 v3.1.1:
git checkout v3.1.1
确认当前版本:
git describe --tags --exact-match
预期输出:
v3.1.1
后续所有编译操作均基于该版本进行。
五、跨平台静态库编译脚本
5.1 完整脚本
在 GmSSL 源码根目录下创建 build-static.sh 文件,内容如下:
#!/bin/bash
set -euo pipefail
# 简单的 GmSSL 构建脚本:生成静态库 libgmssl.a
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$ROOT_DIR/build"
UNAME_S="$(uname -s || echo Unknown)"
echo "清理旧的构建目录..."
rm -rf "$BUILD_DIR"
echo "创建构建目录: $BUILD_DIR"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
echo "检测平台: $UNAME_S"
if [[ "$UNAME_S" == MINGW* || "$UNAME_S" == MSYS* ]]; then
echo "使用 MinGW Makefiles 构建静态库"
cmake .. \
-G "MinGW Makefiles" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release
else
echo "使用默认生成器构建静态库"
cmake .. \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release
fi
echo "开始编译..."
if command -v nproc >/dev/null 2>&1; then
JOBS=$(nproc)
elif [[ "$(uname -s)" == "Darwin" ]]; then
JOBS=$(sysctl -n hw.ncpu)
else
JOBS=1
fi
if [[ "$UNAME_S" == MINGW* || "$UNAME_S" == MSYS* ]]; then
mingw32-make -j"${JOBS}"
else
make -j"${JOBS}"
fi
echo "构建完成: 静态库应位于 $BUILD_DIR/bin/libgmssl.a"
这里的核心目标是统一编译流程,而不是为每个平台分别维护一套复杂的构建脚本。
5.2 执行脚本
Linux、macOS:
chmod +x build-static.sh
./build-static.sh
Windows(MinGW/MSYS Bash 环境):
bash build-static.sh
脚本会自动识别当前操作系统,选择对应的构建命令。
注意: 脚本会直接删除源码根目录下已有的 build 文件夹,请确认该目录没有需要保留的文件。
六、脚本实现原理
6.1 严格错误处理
set -euo pipefail
这行命令启用了 Bash 的三个常用选项。
| 选项 | 作用 |
|---|---|
-e |
命令失败时退出脚本 |
-u |
使用未定义变量时报告错误 |
-o pipefail |
管道中任一命令失败时,使管道返回失败状态 |
这样可以减少编译失败后脚本继续执行的情况。
需要注意,set -e 在条件判断等语法结构中存在例外,并不意味着任何非零退出状态都会使脚本立即退出。
6.2 获取源码目录
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$ROOT_DIR/build"
其中:
$0表示当前脚本的调用路径。dirname "$0"获取脚本所在目录。pwd获取绝对路径。BUILD_DIR指定构建产物存放目录。
通过这种方式,避免使用固定的绝对路径,让脚本能够在不同机器上复用。
6.3 自动识别操作系统
UNAME_S="$(uname -s || echo Unknown)"
uname -s 用于获取操作系统名称。
不同平台常见返回值如下:
| 操作系统 | 返回值示例 |
|---|---|
| Linux | Linux |
| macOS | Darwin |
| Windows(MinGW) | MINGW64_NT-10.0 |
| Windows(MSYS) | MSYS_NT-10.0 |
Windows 环境下,脚本通过以下判断选择构建工具:
if [[ "$UNAME_S" == MINGW* || "$UNAME_S" == MSYS* ]]; then
其中的 * 表示通配符,因此可以匹配不同版本的 Windows 系统标识。
需要说明的是,识别出 MSYS 并不代表当前环境必然已经配置好 MinGW 编译器。如果 gcc 或 mingw32-make 不存在,仍需要先配置正确的 MinGW 工具链。
6.4 CMake 配置静态库
脚本中最重要的两个编译选项:
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_BUILD_TYPE=Release
BUILD_SHARED_LIBS=OFF 用于控制未显式指定类型的 add_library() 默认创建静态库。
GmSSL v3.1.1 的 CMake 配置中定义了:
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
add_library(gmssl ${src})
因此,关闭 BUILD_SHARED_LIBS 后,gmssl 目标会被构建为静态库。
而 CMAKE_BUILD_TYPE=Release 表示使用 Release 构建配置,通常会启用相应的编译优化。
需要注意,BUILD_SHARED_LIBS=OFF 并不会禁止项目中所有动态库的生成。GmSSL v3.1.1 中还存在显式使用 SHARED 定义的目标,因此该脚本主要保证 gmssl 目标生成静态库,并不是只构建静态库这一个目标。
6.5 Windows 使用 MinGW Makefiles
Windows 分支中使用:
cmake .. -G "MinGW Makefiles" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release
这里的 -G 用于指定 CMake 生成器。
MinGW Makefiles 会生成适用于 MinGW Make 工具的构建文件,因此后续使用:
mingw32-make
而 Linux 和 macOS 分支没有显式指定生成器,使用 CMake 默认生成器,并在后续执行:
make
需要特别注意:
在 Windows 上,CMake 生成器必须与当前 Make 工具及编译器环境匹配。
如果使用了 Ninja 或 Visual Studio 等生成器,就不能直接套用本文的 mingw32-make 编译命令。
6.6 自动获取 CPU 核心数
if command -v nproc >/dev/null 2>&1; then
JOBS=$(nproc)
elif [[ "$(uname -s)" == "Darwin" ]]; then
JOBS=$(sysctl -n hw.ncpu)
else
JOBS=1
fi
不同系统获取 CPU 核心数量的方法不同。
Linux 通常使用:
nproc
macOS 使用:
sysctl -n hw.ncpu
如果都不可用,则默认使用一个编译任务。
最后通过:
make -j"${JOBS}"
或者:
mingw32-make -j"${JOBS}"
实现并行编译,减少构建耗时。
其中 -j 指定同时执行的任务数量。
6.7 静态库输出目录
GmSSL v3.1.1 的 CMakeLists.txt 中定义了:
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
因此,正常构建后,GmSSL 静态库会生成在:
GmSSL/
├── build-static.sh
├── CMakeLists.txt
├── include/
├── src/
└── build/
└── bin/
└── libgmssl.a
该路径适用于本文选择的 Makefiles 构建方式。实际目录中还可能存在命令行工具、测试程序及其他构建产物。
七、验证编译结果
编译成功后,可以检查静态库是否存在。
Linux、macOS:
ls -lh build/bin/libgmssl.a
Windows(MinGW Bash):
ls -lh build/bin/libgmssl.a
也可以使用 ar 查看静态库中的目标文件:
ar -t build/bin/libgmssl.a
正常情况下,会列出静态库包含的多个 .o 目标文件。
如果还需要验证 GmSSL 功能,可以执行项目测试:
cd build
ctest --output-on-failure
需要注意,静态库文件存在仅表示构建生成了产物,并不能完全证明所有密码算法功能或外部项目链接过程都正常,建议根据实际使用场景进行进一步测试。
八、常见问题
8.1 Windows 提示找不到 mingw32-make
如果出现:
mingw32-make: command not found
一般是 MinGW Make 工具未安装,或者工具所在目录没有加入 PATH。
可在 MSYS2 MinGW x64 环境安装:
pacman -S mingw-w64-x86_64-make
然后通过以下命令检查:
which mingw32-make
确认可以找到对应的可执行文件。
8.2 CMake 提示生成器不匹配
例如:
Error: generator ... does not match the generator used previously
通常是同一个构建目录之前使用了其他生成器。
本文脚本在执行 CMake 之前会删除旧的 build 目录,因此可以避免大部分此类问题。
8.3 设置 BUILD_SHARED_LIBS=OFF 后仍有动态库
这是因为该选项只影响没有显式指定库类型的 add_library()。
如果项目使用:
add_library(example SHARED ...)
该目标仍然按照动态库进行构建。
对于 GmSSL v3.1.1,gmssl 目标使用:
add_library(gmssl ${src})
因此可以通过 BUILD_SHARED_LIBS=OFF 将其构建为静态库。
8.4 Windows 静态库能否直接在 Linux 或 macOS 使用?
不能直接通用。
虽然三个平台可能都生成名为 libgmssl.a 的文件,但不同平台的目标文件格式、ABI、工具链以及系统依赖存在差异。
例如:
- Linux 通常使用 ELF 对象文件。
- macOS 使用 Mach-O 对象文件。
- Windows MinGW 使用 COFF/PE 体系下的对象文件。
因此,需要在目标平台上分别编译生成对应的静态库。
另外,Windows 下使用 MinGW 编译生成的 .a 静态库,也不能保证直接兼容 MSVC 工具链。
8.5 静态链接后是否就不需要其他依赖?
不一定。
静态链接 GmSSL 可以减少对 GmSSL 共享库的运行时依赖,但仍可能需要链接操作系统提供的其他库。
例如,Windows 下使用 GmSSL 的网络相关功能时,可能需要链接:
ws2_32
macOS 下则可能涉及 Security 等系统框架。
最终需要根据目标程序调用的接口和链接工具链确定依赖。
九、总结
本文通过一个简单的 Shell 脚本,实现了 GmSSL v3.1.1 在 Linux、macOS 和 Windows(MinGW)环境下的静态库构建。
整体思路是:
- 使用 CMake 统一项目配置。
- 设置
BUILD_SHARED_LIBS=OFF,构建libgmssl.a。 - 根据平台选择 Make 工具。
- 自动检测 CPU 核心数,实现并行编译。
- 清理旧目录,避免构建缓存冲突。
这种方式比较适合需要在多个操作系统下维护 GmSSL 依赖的项目,也方便后续将静态库集成到 C/C++、Go CGO 或其他需要原生密码库的应用中。
参考资料:
- GmSSL GitHub:GitHub - guanzhi/GmSSL: 支持国密SM2/SM3/SM4/SM9/SSL的密码工具箱 · GitHub
- GmSSL v3.1.1:GitHub - guanzhi/GmSSL at v3.1.1 · GitHub
- CMake 官方文档:CMake Reference Documentation --- CMake 4.5.0-rc1 Documentation
- MSYS2 官网:Getting Started - MSYS2