Zstandard 的 CMake 构建指南:从零编译 libzstd 到 FetchContent 与库集成实践
【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit
本指南以 zstd 1.5.7 官方 CMake 构建说明 为主体,系统讲解 Zstandard 压缩库在 CMake 体系下的完整构建流程:包括 out-of-source 与 in-source 两种构建方式、全部可配置构建选项、Apple Framework 打包、以及通过 FetchContent 将 libzstd 嵌入第三方项目的标准做法。读完本文,你将掌握libzstd_static/libzstd_shared目标的由来与取舍,并能像 Fluent Bit 一样把 zstd 作为静态子库集成进自己的工程。
仓库中的 zstd 源码位于 lib/zstd-1.5.7,CMake 构建入口为 build/cmake/CMakeLists.txt,库目标定义在 build/cmake/lib/CMakeLists.txt。本文所有命令与路径均以该仓库为准。
一、准备工作:构建方式与目录约定
zstd 的 CMake 工程不支持cmake clean这类"清理"命令(CMake 本身也没有官方 clean 子命令),因此官方 README 强烈推荐采用out-of-source(源码外)构建:把构建产物、CMake 缓存全部放在独立目录中,需要"清理"时直接删除该目录即可,不会污染源码树。
1.1 Out-of-source 构建(推荐)
cd lib/zstd-1.5.7/build/cmake mkdir builddir cd builddir cmake .. makemkdir builddir新建独立构建目录;cmake ..以build/cmake为源码目录生成构建系统;make执行编译。
清理缓存只需删除构建目录:
rm -rf build/cmake/builddir1.2 In-source 构建(可选)
也可以在build/cmake目录内直接构建,CMake 会就地生成缓存与产物:
cd lib/zstd-1.5.7/build/cmake cmake . make这种方式会把CMakeCache.txt、CMakeFiles/等中间产物写入源码目录,之后若要彻底清理,只能手动删除这些生成文件,不如 out-of-source 方式干净,故仅建议快速验证时使用。
1.3 查看全部构建选项
cd build/cmake/builddir cmake -LH ..-LH会列出当前工程所有可配置的 CMake 缓存选项(L表示 list,H表示 help),包括选项名、类型、默认值与说明文字,是快速了解 zstd 构建能力的最直接途径。从 build/cmake/CMakeLists.txt 源码可以看到,顶层入口首先通过 GetZstdLibraryVersion.cmake 从 lib/zstd.h 中解析出版本号,再以project(zstd VERSION ...)声明工程,随后用option()逐一声明各开关。
1.4 通过命令行开关配置选项
布尔选项统一使用-D[option]=ON/OFF语法传递:
cd build/cmake/builddir cmake -DZSTD_BUILD_TESTS=ON -DZSTD_LEGACY_SUPPORT=OFF .. makeZSTD_BUILD_TESTS控制是否编译测试套件,ZSTD_LEGACY_SUPPORT控制是否携带 v01~v07 旧格式解压支持(详见下文选项表格)。选项可多次叠加,未指定的选项保持默认值。
二、zstd CMake 构建选项全解析
所有与库本身相关的选项集中定义在 build/cmake/lib/CMakeLists.txt 的option()声明中,顶层 build/cmake/CMakeLists.txt 则负责工程级开关。核心选项整理如下:
| 选项 | 默认值 | 作用 |
|---|---|---|
ZSTD_BUILD_STATIC | ON | 是否构建静态库libzstd_static |
ZSTD_BUILD_SHARED | ON | 是否构建共享库libzstd_shared |
ZSTD_BUILD_COMPRESSION | ON | 是否编译lib/compress/压缩模块源码 |
ZSTD_BUILD_DECOMPRESSION | ON | 是否编译lib/decompress/解压模块源码 |
ZSTD_BUILD_DICTBUILDER | ON | 是否编译lib/dictBuilder/字典构建模块 |
ZSTD_BUILD_DEPRECATED | OFF | 是否编译lib/deprecated/已废弃 API 源码 |
ZSTD_LEGACY_SUPPORT | ON | 是否支持 v01~v07 旧格式解压(对应lib/legacy/zstd_v0*.c) |
ZSTD_MULTITHREAD_SUPPORT | ON(Android 为 OFF) | 多线程压缩支持,编译时定义ZSTD_MULTITHREAD并链接 pthread |
ZSTD_BUILD_PROGRAMS | ON | 是否构建 zstd CLI 可执行程序 |
ZSTD_BUILD_TESTS | 跟随BUILD_TESTING | 是否构建测试套件(依赖静态库) |
ZSTD_BUILD_CONTRIB | OFF | 是否构建 contrib 下的贡献代码 |
ZSTD_PROGRAMS_LINK_SHARED | OFF | CLI 程序链接共享库而非静态库 |
ZSTD_FRAMEWORK | OFF(仅 Apple 平台) | 是否以 Apple Framework 形式打包库 |
2.1 模块化编译:按需裁剪源码
从 lib/CMakeLists.txt 的实现可以看到,库的源码集合是按模块动态拼装的:
common/与所有头文件始终参与编译;- 打开
ZSTD_BUILD_COMPRESSION才追加compress/*.c; - 打开
ZSTD_BUILD_DECOMPRESSION才追加decompress/*.c(在 x86_64 且支持noexecstack时还会追加汇编文件huf_decompress_amd64.S,否则定义ZSTD_DISABLE_ASM); - 打开
ZSTD_BUILD_DICTBUILDER才追加dictBuilder/*.c; - 打开
ZSTD_BUILD_DEPRECATED才追加deprecated/*.c; - 打开
ZSTD_LEGACY_SUPPORT才追加legacy/zstd_v01.c~zstd_v07.c七个历史版本源码。
因此一个"仅解压、无字典、无旧格式"的精简 libzstd,可以只保留common+decompress两个目录的源码,显著减小二进制体积——这也是嵌入式与日志代理场景常用的裁剪手段。
2.2 静态 / 共享二选一与 INTERFACE 别名目标
lib/CMakeLists.txt中通过add_library(libzstd_shared SHARED ...)与add_library(libzstd_static STATIC ...)分别生成两个真实目标,并根据选项组合额外生成一个INTERFACE 别名目标libzstd:
- 仅
ZSTD_BUILD_SHARED时,libzstd转发到libzstd_shared; - 仅
ZSTD_BUILD_STATIC时,libzstd转发到libzstd_static; - 两者都开启时,由全局
BUILD_SHARED_LIBS决定转发方向。
同时,无论静态还是共享库,只要打开多线程支持(ZSTD_MULTITHREAD_SUPPORT),目标都会追加编译定义ZSTD_MULTITHREAD,在 Unix 上链接${THREADS_LIBS}(通过find_package(Threads)解析,HP-UX 有专门的处理函数)。MSVC 平台还会追加ZSTD_HEAPMODE=0、_CRT_SECURE_NO_WARNINGS等定义,并把静态库输出名改为zstd_static以避免与导入库冲突。
2.3 顶层约束与 clean-all / uninstall 目标
顶层 build/cmake/CMakeLists.txt 中有几处硬性约束值得注意:
- 想构建 zstd CLI 程序(
ZSTD_BUILD_PROGRAMS=ON),必须先构建静态库(或共享库 +ZSTD_PROGRAMS_LINK_SHARED),否则SEND_ERROR直接报错; - 想构建测试套件(
ZSTD_BUILD_TESTS=ON),同样必须存在静态库; - 工程额外提供了
clean-all自定义目标(等价于make clean+ 删除构建目录)与uninstall目标; - 工程会生成并安装 CMake 包配置文件:
zstdConfig.cmake、zstdConfigVersion.cmake(SameMajorVersion兼容策略)与带zstd::命名空间的zstdTargets.cmake,并安装libzstd.pc(pkg-config 文件),供下游find_package(zstd)使用。
三、Apple Framework 构建
在 Apple 平台(iOS/macOS)上,zstd 支持直接打包成Apple Framework形式,便于 Xcode 工程引用。
官方 README 建议:iOS 派生平台尽量使用 CMake 3.14 以上版本,此时可借助 CMake 内建 toolchain 能力直接交叉编译:
cmake -S. -B build-cmake -DZSTD_FRAMEWORK=ON -DCMAKE_SYSTEM_NAME=iOS若 CMake 版本低于 3.14,则需借助第三方 iOS-CMake toolchain 文件配合 Xcode 生成器:
cmake -B build -G Xcode -DCMAKE_TOOLCHAIN_FILE=<Path To ios.toolchain.cmake> -DPLATFORM=OS64 -DZSTD_FRAMEWORK=ON从 lib/CMakeLists.txt 的实现看,ZSTD_FRAMEWORK=ON会为目标设置FRAMEWORK TRUE、FRAMEWORK_VERSION、PRODUCT_BUNDLE_IDENTIFIER(github.com/facebook/zstd)与MACOSX_FRAMEWORK_IDENTIFIER等属性,并关闭代码签名(CODE_SIGNING_ALLOWED NO);PUBLIC_HEADER指向lib/目录下的全部公共头文件,最终 Framework 会随install目标安装到${CMAKE_INSTALL_LIBDIR}。
四、通过 CMake FetchContent 集成到第三方工程
对于不希望预先安装 zstd 的工程,官方 README 推荐使用FetchContent在配置期自动下载并构建 libzstd。完整示例(来自 README):
include(FetchContent) set(ZSTD_BUILD_STATIC ON) set(ZSTD_BUILD_SHARED OFF) FetchContent_Declare( zstd URL "https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz" DOWNLOAD_EXTRACT_TIMESTAMP TRUE SOURCE_SUBDIR build/cmake ) FetchContent_MakeAvailable(zstd) target_link_libraries( ${PROJECT_NAME} PRIVATE libzstd_static ) # On windows and macos this is needed target_include_directories( ${PROJECT_NAME} PRIVATE ${zstd_SOURCE_DIR}/lib )要点拆解:
set(ZSTD_BUILD_STATIC ON)/set(ZSTD_BUILD_SHARED OFF)必须在FetchContent_MakeAvailable之前设置,因为选项在子工程project()阶段就被读取;SOURCE_SUBDIR build/cmake指示 FetchContent 以build/cmake为实际 CMake 源码根(zstd 仓库根目录下还有 Makefile 构建体系,CMake 入口在build/cmake);- 链接目标名
libzstd_static来自 lib/CMakeLists.txt 中的add_library(libzstd_static STATIC ...);若同时构建共享库,也可链接libzstd_shared,或直接链接 INTERFACE 别名libzstd; - Windows 与 macOS 上需要手动补充
target_include_directories指向${zstd_SOURCE_DIR}/lib,这是因为静态目标仅通过$<BUILD_INTERFACE:...>暴露头文件路径,跨平台传递并不总是可靠。
若选择先安装 zstd 再以find_package(zstd)使用,则依赖上一步生成的zstdConfig.cmake与zstd::命名空间导出目标(见 zstdConfig.cmake.in 与顶层 CMakeLists 的install(EXPORT zstdExports ...))。
五、仓库实战:Fluent Bit 如何静态集成 libzstd
本仓库(Fluent Bit)正是"把 zstd 作为第三方静态子库集成"的典型实例,其集成方式与上文 FetchContent 思路一致,但改用了随源码一起 vendored 的 add_subdirectory 方案。
Fluent Bit 的 zstd 接入配置位于 cmake/zstd.cmake:
# zstd cmake set(ZSTD_BUILD_STATIC ON) set(ZSTD_BUILD_SHARED OFF) set(ZSTD_BUILD_COMPRESSION ON) set(ZSTD_BUILD_DECOMPRESSION ON) set(ZSTD_BUILD_DICTBUILDER OFF) set(ZSTD_BUILD_DEPRECATED OFF) include_directories(${FLB_PATH_ROOT_SOURCE}/${FLB_PATH_LIB_ZSTD}/lib) add_subdirectory(${FLB_PATH_LIB_ZSTD}/build/cmake EXCLUDE_FROM_ALL) set(LIBZSTD_LIBRARIES "libzstd_static")该文件展示了 zstd 各选项在真实项目中的裁剪策略:
- 只构建静态库(
ZSTD_BUILD_STATIC=ON、ZSTD_BUILD_SHARED=OFF),避免引入动态库部署负担; - 压缩、解压模块全开,关闭字典构建(
ZSTD_BUILD_DICTBUILDER=OFF)与废弃模块(ZSTD_BUILD_DEPRECATED=OFF),控制体积; - 通过
include_directories将 lib/zstd-1.5.7/lib 加入头文件搜索路径; - 用
add_subdirectory(... EXCLUDE_FROM_ALL)挂载 zstd 子工程,EXCLUDE_FROM_ALL保证只构建被显式依赖的目标; - 最终将链接目标统一记为
LIBZSTD_LIBRARIES="libzstd_static"供上层使用。
zstd 在 Fluent Bit 中的实际调用位于 src/flb_zstd.c:flb_zstd_compress()通过ZSTD_compressBound()预分配缓冲区后调用ZSTD_compress();flb_zstd_uncompress()先用ZSTD_getFrameContentSize()判断帧大小,未知大小时走ZSTD_decompressStream()流式解压(缓冲区从 64 KB 起步、按 2 倍扩容,并设有 100 MB 上限保护);相关封装被 src/flb_compression.c、src/flb_http_common.c 与 src/aws/flb_aws_compress.c 复用,用于 HTTP 报文压缩与 AWS 数据压缩等场景。可见"裁剪选项 + 静态链接 + 封装 API"正是大型 C 项目集成 zstd 的标准姿势。
六、为 zstd 贡献 CMake 配置:风格规范
zstd 官方欢迎社区向build/cmake贡献配置改进,并提出了明确的CMake 代码风格约定(详见 README "CMake Style Recommendations" 一节),主要包含三条:
6.1 正确缩进所有块体
以下命令的块体必须正确缩进:
if/else/endifforeach/endforeachwhile/endwhilemacro/endmacrofunction/endfunction
缩进使用空格(推荐 2、3 或 4 个,与文件其余部分保持一致),禁止使用 Tab。
6.2 大小写规范
最重要的一条是:同一文件内保持大小写风格一致。整体上优先采用全小写风格。
推荐写法:
add_executable(foo foo.c)不推荐写法:
ADD_EXECUTABLE(bar bar.c) Add_Executable(hello hello.c) aDd_ExEcUtAbLe(blub blub.c)同时 README 也提示:命名习惯应匹配现代 CMake(2.6 及以上)惯例——命令用小写、变量用大写。
6.3 空参数结束命令
为提升可读性,endforeach()、endif()、endfunction()、endmacro()、endwhile()一律使用空参数写法,else()同样留空:
推荐:
if(FOOVAR) some_command(...) else() another_command(...) endif()不推荐在结尾重复变量名:
if(BARVAR) some_other_command(...) endif(BARVAR)七、小结
围绕 zstd 1.5.7 的 CMake 构建文档,本文完整覆盖了:out-of-source 与 in-source 两种构建流程、cmake -LH查看选项、-D开关配置、全部构建选项的语义与源码级来源、Apple Framework 打包、FetchContent 集成范式,以及以 Fluent Bit 为代表的 vendored 静态集成实战。无论你是要单独编译 zstd CLI、按需裁剪 libzstd 模块,还是在自己的 CMake 工程中嵌入 zstd,都可以直接参考文中的命令与选项表;后续若计划向 zstd 贡献 CMake 改动,请务必遵守第六节的风格规范。
【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考