TDengine 中 Fast LZMA2 的 Conan 集成实战:从包构建、代码调用到流式压缩
TDengine 中 Fast LZMA2 的 Conan 集成实战从包构建、代码调用到流式压缩【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengineFast LZMA2 是 LZMA2 压缩算法的一个高性能优化实现TDengine 通过 Conan 包管理方式将其集成到自身的压缩链路中BUILD_WITH_LZMA2默认开启options.cmake并作为时间序列数据压缩的可选算法之一。本文以 TDengine 仓库中的 conan/fast-lzma2/USAGE.md 为主体结合 conanfile.py、上游 lzma2.Makefile 与 tcompression.c 中的真实调用完整讲解如何用 Conan 构建该包、如何在自己的 C/C 项目中引用它、如何编写压缩/解压与流式处理代码以及构建选项、性能调优与排障要点。读完本文你将能够独立完成 Fast LZMA2 的 Conan 打包、依赖接入和业务编码。Fast LZMA2 在 TDengine 中的定位Fast LZMA2 是一个以压缩率高著称的 LZMA2 变体实现接口风格与 zstd 类似函数以FL2_前缀命名。在 TDengine 中它并不是独立运行的组件而是被底层压缩模块直接引用的算法库构建开关位于 options.cmake 的BUILD_WITH_LZMA2选项默认ON关闭后 TDengine 将不再编译 lzma2 相关支持。实际调用发生在 source/util/src/tcompression.c该文件第 59 行通过#include fast-lzma2.h引入头文件随后在压缩与解压路径上调用FL2_compress/FL2_decompress见 tcompression.c 与 tcompression.c。因此理解这个 Conan 包本质上是理解 TDengine 的一条可选数据压缩链路的构建与接入方式。快速开始创建并安装包到本地缓存在包含 conanfile.py 的目录即conan/fast-lzma2/下执行# 在当前目录包含 conanfile.py执行 conan create . --buildmissing # 验证安装结果 conan list fast-lzma2/*conan create会依次完成源码获取、编译、打包、生成 recipe并把包存入本地 Conan 缓存--buildmissing表示当预编译二进制包不存在时从源码构建这也是首次使用时的必经步骤。关于包本身的元信息可查看 conanfile.py包名为fast-lzma2、版本1.0.1、许可证BSD-3-Clause提供了两个构建选项选项默认值说明sharedFalse是否构建为共享库fPICTrue生成位置无关代码Windows 上自动移除源码获取逻辑见 conanfile.py包将上游源码固定pin到提交ded964d203cabe1a572d2c813c55e8a94b4eda48优先使用DEPS_MIRROR_URL环境变量指定的镜像下载失败后回退到公开归档地址且采用归档压缩包而非 git clone避免构建机依赖 git。这与 TDengine 整体的镜像化依赖下载策略见 conan.cmake保持一致。验证包的测试程序执行conan create时包内的test_package会自动运行。测试工程结构如下test_package/conanfile.py通过self.tested_reference_str依赖刚构建的包并用 CMake 构建、运行测试可执行文件test_package/test_package.c一个完整的冒烟测试依次打印FL2_versionNumber()版本号、FL2_compressBound计算出的最大压缩后大小、执行压缩、解压最后用memcmp校验数据一致性并输出Test PASSEDtest_package/CMakeLists.txt仅 7 行演示了最简的find_packagetarget_link_libraries接入方式。如果测试通过说明包已正确安装并可被下游消费。使用不同配置构建Fast LZMA2 的构建行为由settingsos、compiler、build_type、arch和optionsshared、fPIC共同决定可针对不同场景产出不同的二进制# 构建共享库版本 conan create . --buildmissing -o fast-lzma2/*:sharedTrue # 构建 Debug 版本 conan create . --buildmissing -s build_typeDebug # 构建不使用 fPIC 的版本无需位置无关代码时 conan create . --buildmissing -o fast-lzma2/*:fPICFalse这些选项如何落地到实际编译可对照 conanfile.py 的build()方法默认 CFLAGS 为-Wall -O2 -pthread开启 fPIC 时追加-fPICDebug构建会把-O2替换为-O0 -g汇编标志固定为-Wa,--noexecstack防止栈可执行。最终通过make ... libfast-lzma2调用上游 Makefile 完成编译。几个选项间的联动规则也值得注意见 conanfile.pyWindows 平台自动删除fPIC选项位置无关代码仅对类 Unix 共享库有意义构建 shared 版本时同样会移除fPIC选项共享库天然满足 PIC 要求这是一个纯 C 库因此会移除compiler.libcxx与compiler.cppstd等 C 相关设置避免编译器配置干扰。在自己的项目中使用包构建完成后可以通过两种方式把它声明为依赖。方法一conanfile.txt创建conanfile.txt[requires] fast-lzma2/1.0.1 [generators] CMakeDeps CMakeToolchain [options] fast-lzma2/*:sharedFalse然后安装依赖conan install . --buildmissingCMakeDeps负责生成 CMake 的 find_package 配置CMakeToolchain负责生成工具链文件二者是 Conan 2 下与 CMake 协作的标准组合。方法二conanfile.py创建conanfile.pyfrom conan import ConanFile from conan.tools.cmake import cmake_layout class MyProjectConan(ConanFile): settings os, compiler, build_type, arch generators CMakeDeps, CMakeToolchain def requirements(self): self.requires(fast-lzma2/1.0.1) def layout(self): cmake_layout(self)同样执行conan install . --buildmissingcmake_layout会把源码、构建产物按 Conan 约定组织到build/preset之类的目录下便于后续配合 CMake preset 使用。CMakeLists.txt 配置无论采用哪种依赖声明方式CMake 侧的接入都是统一的cmake_minimum_required(VERSION 3.15) project(MyProject C) # 使用 Conan 生成的 toolchain 文件 find_package(fast-lzma2 REQUIRED CONFIG) add_executable(myapp main.c) target_link_libraries(myapp fast-lzma2::fast-lzma2)fast-lzma2::fast-lzma2这个 target 由包内的package_info()定义见 conanfile.py库名导出为fast-lzma2在 Linux/FreeBSD 上会自动追加pthread系统库依赖在 Windows 共享库场景下会自动注入FL2_DLL_IMPORT1宏因此下游通常无需手动处理这些平台差异。构建你的项目依赖安装完成后使用 Conan 生成的 CMake preset 构建# 使用 Conan 生成的 toolchain cmake --preset conan-release # 或 conan-debug cmake --build --preset conan-releaseconan-release/conan-debug这两个 preset 正是由CMakeToolchain生成器在conan install阶段产生的分别对应 Release 与 Debug 配置无需再手写-DCMAKE_TOOLCHAIN_FILE...。代码示例基础压缩/解压下面是一段完整的一站式示例覆盖了内存块压缩的六个标准步骤#include stdio.h #include stdlib.h #include string.h #include fast-lzma2.h int main() { // 原始数据 const char* data Hello, Fast LZMA2!; size_t src_size strlen(data); // 1. 计算压缩所需的最大缓冲区大小 size_t max_compressed_size FL2_compressBound(src_size); char* compressed malloc(max_compressed_size); // 2. 压缩数据压缩级别 1-10推荐 6 size_t compressed_size FL2_compress( compressed, max_compressed_size, data, src_size, 6 // 压缩级别 ); // 3. 检查错误 if (FL2_isError(compressed_size)) { fprintf(stderr, Compression failed: %s\n, FL2_getErrorName(compressed_size)); free(compressed); return 1; } printf(Compression ratio: %.2f%%\n, (compressed_size * 100.0) / src_size); // 4. 解压 char* decompressed malloc(src_size); size_t decompressed_size FL2_decompress( decompressed, src_size, compressed, compressed_size ); // 5. 检查解压错误 if (FL2_isError(decompressed_size)) { fprintf(stderr, Decompression failed: %s\n, FL2_getErrorName(decompressed_size)); free(compressed); free(decompressed); return 1; } // 6. 校验数据 if (memcmp(data, decompressed, src_size) 0) { printf(Success!\n); } free(compressed); free(decompressed); return 0; }该示例与 test_package/test_package.c 中的验证逻辑一致FL2_compressBound预估缓冲、FL2_compress压缩、FL2_isError/FL2_getErrorName处理错误、FL2_decompress解压、memcmp校验一致性。在 TDengine 中tcompression.c 也正是用同样的一对函数实现 lzma2 压缩与解压只是将压缩级别固定为 9 以追求更高压缩比见 tcompression.c。流式压缩适用于大文件一次性压缩要求把整块数据放入内存对大文件并不友好。流式 API 通过FL2_CStream上下文分块处理#include stdio.h #include fast-lzma2.h int compress_file(const char* input_path, const char* output_path) { FILE* fin fopen(input_path, rb); FILE* fout fopen(output_path, wb); if (!fin || !fout) return -1; // 创建压缩上下文 FL2_CStream* cstream FL2_createCStream(); if (!cstream) { fclose(fin); fclose(fout); return -1; } // 初始化压缩流压缩级别 6 size_t init_result FL2_initCStream(cstream, 6); if (FL2_isError(init_result)) { FL2_freeCStream(cstream); fclose(fin); fclose(fout); return -1; } // 分块读取并压缩 size_t const buf_size 16 * 1024; // 16KB 缓冲区 void* in_buffer malloc(buf_size); void* out_buffer malloc(buf_size); size_t read_size; while ((read_size fread(in_buffer, 1, buf_size, fin)) 0) { FL2_inBuffer input { in_buffer, read_size, 0 }; while (input.pos input.size) { FL2_outBuffer output { out_buffer, buf_size, 0 }; size_t result FL2_compressStream(cstream, output, input); if (FL2_isError(result)) { goto cleanup; } fwrite(out_buffer, 1, output.pos, fout); } } // 结束压缩流 FL2_outBuffer output { out_buffer, buf_size, 0 }; size_t result FL2_endStream(cstream, output); if (!FL2_isError(result)) { fwrite(out_buffer, 1, output.pos, fout); } cleanup: free(in_buffer); free(out_buffer); FL2_freeCStream(cstream); fclose(fin); fclose(fout); return 0; }流式 API 的关键点在于FL2_compressStream通过FL2_inBuffer/FL2_outBuffer结构体中的pos字段推进输入输出进度内层while循环保证输入被完全消费外层循环负责读完整个文件最后必须调用FL2_endStream冲刷尾数据。获取版本信息#include stdio.h #include fast-lzma2.h void print_version() { unsigned version FL2_versionNumber(); printf(Fast LZMA2 version: %u.%u.%u\n, version / 10000, (version / 100) % 100, version % 100); }FL2_versionNumber()返回形如1.0.1的编码版本号便于在运行时做特性探测。测试程序 test_package/test_package.c 正是用它打印版本再继续后续的压缩验证。编译选项CFLAGS选项说明-Wall开启全部警告-O2二级优化Release 模式-O0 -g不优化 调试信息Debug 模式-pthread启用多线程支持-fPIC位置无关代码用于共享库这些默认值在 conanfile.py 的build()中按构建类型自动切换因此普通使用者通常无需手动指定。特殊宏定义LZMA2_DEC_OPT在 x86_64 架构上自动定义启用优化的汇编解压代码。上游 lzma2.Makefile 在检测到 x86_64 时会追加-DLZMA2_DEC_OPT并额外编译lzma_dec_x86_64.oWindows 下还会根据PROCESSOR_ARCHITECTURE区分MS_x64_CALL的值。FL2_DLL_EXPORTWindows DLL 导出宏由 lzma2.Makefile 在 Windows 上自动定义。FL2_DLL_IMPORTWindows DLL 导入宏使用共享库时由 conanfile.py 在package_info()中自动注入下游无需关心。性能提示压缩级别选择级别 1-3压缩快压缩率较低级别 4-6压缩速度与压缩率均衡推荐级别 7-10压缩率高速度慢。TDengine 在数据落盘压缩路径中选择级别 9见 tcompression.c属于偏重压缩率的取舍实际使用时可根据 CPU 预算与存储成本权衡。内存占用压缩级别越高内部字典与匹配结构占用内存越多流式 API 通过固定大小的输入/输出缓冲区可以在大文件场景下把内存占用控制在可预期范围内。多线程库内部使用 pthread编译时默认开启多线程支持可自动利用多核这也是 Linux 上需要链接 pthread 的原因包已在 conanfile.py 中自动声明该系统库依赖。故障排查编译错误如果遇到编译问题先清理缓存再重建# 清理并重建 conan remove fast-lzma2/* -c conan create . --buildmissingconan remove ... -c会同时清除本地缓存的 recipe 与二进制包可排除脏缓存导致的构建失败。链接错误确认 CMakeLists.txt 正确链接了库find_package(fast-lzma2 REQUIRED CONFIG) target_link_libraries(your_target fast-lzma2::fast-lzma2)在 Linux 上如果手动链接不经过 Conan 的package_info()可能需要显式链接 pthreadfind_package(Threads REQUIRED) target_link_libraries(your_target fast-lzma2::fast-lzma2 Threads::Threads)需要说明的是经由 conanfile.py 安装依赖时Linux/FreeBSD 上的 pthread 依赖已被自动声明上述手动Threads::Threads仅在脱离 Conan、自行编译链接库时才有必要。高级用法导出到本地 Conan 仓库# 导出包到本地 conan export . fast-lzma2/1.0.1 # 或指定 user 和 channel conan export . fast-lzma2/1.0.1mycompany/stableconan export只导出 recipe不构建二进制适合把配方纳入版本管理或供 CI 消费后续可按需用conan create构建对应二进制。上传到私有 Conan 服务器# 添加远程仓库 conan remote add myremote http://my-conan-server.com # 上传包含 recipe 与所有二进制 conan upload fast-lzma2/1.0.1 -r myremote --all--all表示连同所有平台的预编译二进制一起上传团队内其他成员即可直接拉取避免重复构建。交叉编译# 构建 ARM64 版本 conan create . --buildmissing -s archarmv8 # 构建 Android 版本 conan create . --buildmissing -pr:handroid-armv8注意 lzma2.Makefile 中的架构检测依赖uname -p/uname -m判断 x86_64交叉编译到非 x86_64 目标时不会启用LZMA2_DEC_OPT汇编优化而是回退到纯 C 解压实现功能不受影响。许可证Fast LZMA2 采用双许可证BSD-3-Clause适用于大多数商业与开源项目GPL-2.0适用于 GPL 兼容项目。Conan 包在打包阶段会把上游的LICENSE与COPYING文件一并拷贝到包的licenses目录见 conanfile.py引用该包时请依据你的项目许可证类型选择适用的条款。总结围绕 conan/fast-lzma2/USAGE.md 提供的能力本文从四个层面完成了 Fast LZMA2 在 TDengine 生态中的完整闭环其一通过conan create与-o/-s选项产出不同配置的二进制其二通过conanfile.txt/conanfile.py加CMakeDeps/CMakeToolchain将其接入任意 C 项目其三通过FL2_compress/FL2_decompress与FL2_CStream流式 API 完成单块与分块数据处理其四理解LZMA2_DEC_OPT、fPIC、pthread 等编译细节以便排障。无论你是要复用 TDengine 的压缩能力还是在自己的项目里接入这款高压缩率的 LZMA2 实现上述流程与代码都可以直接作为起点。【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考