Zstandard 的 CMake 构建指南:从零编译 libzstd 到 FetchContent 与库集成实践
2026/9/18 16:52:07 网站建设 项目流程

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 .. make
  • mkdir builddir新建独立构建目录;
  • cmake ..build/cmake为源码目录生成构建系统;
  • make执行编译。

清理缓存只需删除构建目录:

rm -rf build/cmake/builddir

1.2 In-source 构建(可选)

也可以在build/cmake目录内直接构建,CMake 会就地生成缓存与产物:

cd lib/zstd-1.5.7/build/cmake cmake . make

这种方式会把CMakeCache.txtCMakeFiles/等中间产物写入源码目录,之后若要彻底清理,只能手动删除这些生成文件,不如 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 .. make

ZSTD_BUILD_TESTS控制是否编译测试套件,ZSTD_LEGACY_SUPPORT控制是否携带 v01~v07 旧格式解压支持(详见下文选项表格)。选项可多次叠加,未指定的选项保持默认值。

二、zstd CMake 构建选项全解析

所有与库本身相关的选项集中定义在 build/cmake/lib/CMakeLists.txt 的option()声明中,顶层 build/cmake/CMakeLists.txt 则负责工程级开关。核心选项整理如下:

选项默认值作用
ZSTD_BUILD_STATICON是否构建静态库libzstd_static
ZSTD_BUILD_SHAREDON是否构建共享库libzstd_shared
ZSTD_BUILD_COMPRESSIONON是否编译lib/compress/压缩模块源码
ZSTD_BUILD_DECOMPRESSIONON是否编译lib/decompress/解压模块源码
ZSTD_BUILD_DICTBUILDERON是否编译lib/dictBuilder/字典构建模块
ZSTD_BUILD_DEPRECATEDOFF是否编译lib/deprecated/已废弃 API 源码
ZSTD_LEGACY_SUPPORTON是否支持 v01~v07 旧格式解压(对应lib/legacy/zstd_v0*.c
ZSTD_MULTITHREAD_SUPPORTON(Android 为 OFF)多线程压缩支持,编译时定义ZSTD_MULTITHREAD并链接 pthread
ZSTD_BUILD_PROGRAMSON是否构建 zstd CLI 可执行程序
ZSTD_BUILD_TESTS跟随BUILD_TESTING是否构建测试套件(依赖静态库)
ZSTD_BUILD_CONTRIBOFF是否构建 contrib 下的贡献代码
ZSTD_PROGRAMS_LINK_SHAREDOFFCLI 程序链接共享库而非静态库
ZSTD_FRAMEWORKOFF(仅 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.cmakezstdConfigVersion.cmakeSameMajorVersion兼容策略)与带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 TRUEFRAMEWORK_VERSIONPRODUCT_BUNDLE_IDENTIFIERgithub.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 )

要点拆解:

  1. set(ZSTD_BUILD_STATIC ON)/set(ZSTD_BUILD_SHARED OFF)必须在FetchContent_MakeAvailable之前设置,因为选项在子工程project()阶段就被读取;
  2. SOURCE_SUBDIR build/cmake指示 FetchContent 以build/cmake为实际 CMake 源码根(zstd 仓库根目录下还有 Makefile 构建体系,CMake 入口在build/cmake);
  3. 链接目标名libzstd_static来自 lib/CMakeLists.txt 中的add_library(libzstd_static STATIC ...);若同时构建共享库,也可链接libzstd_shared,或直接链接 INTERFACE 别名libzstd
  4. Windows 与 macOS 上需要手动补充target_include_directories指向${zstd_SOURCE_DIR}/lib,这是因为静态目标仅通过$<BUILD_INTERFACE:...>暴露头文件路径,跨平台传递并不总是可靠。

若选择先安装 zstd 再以find_package(zstd)使用,则依赖上一步生成的zstdConfig.cmakezstd::命名空间导出目标(见 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=ONZSTD_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/endif
  • foreach/endforeach
  • while/endwhile
  • macro/endmacro
  • function/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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询