18、CPack生成器详解(上):ZIP与TGZ生成器配置、跨平台压缩包生成、文件权限与符号链接处理
各位好,欢迎来到第18讲。今天咱们聊聊CPack里最常用的两个生成器——ZIP和TGZ。
说实话,我刚开始用CPack时,觉得生成器不就是个压缩格式嘛,选哪个都一样。后来在给一个跨平台项目做交付时,被Windows和Linux上的权限问题折腾得够呛,才意识到这里面的门道有多深。
这一讲,我们就来拆解ZIP和TGZ生成器的配置细节,看看怎么生成跨平台的压缩包,以及如何处理文件权限和符号链接这些“坑”。
ZIP与TGZ生成器:基础配置
先看一个最简单的例子。假设你有一个项目,想生成一个ZIP包和一个TGZ包,CMakeLists.txt里这样写:
include(CPack)
set(CPACK_GENERATOR "ZIP;TGZ")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
然后运行:
cpack -G ZIP
cpack -G TGZ
嗯,就这么简单。但实际项目中,你往往需要更精细的控制。
我个人习惯把生成器配置单独放在一个CPackConfig.cmake文件里,这样主CMakeLists.txt不会太臃肿。比如:
# CPackConfig.cmake
set(CPACK_GENERATOR "ZIP;TGZ")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A cross-platform application")
然后在主文件里include它:
include(CPackConfig.cmake)
include(CPack)
这样做的好处是,你可以为不同平台准备不同的配置片段,灵活切换。
跨平台压缩包生成:一个真实案例
我在项目中遇到过这样一个场景:项目需要在Windows、Linux和macOS上都能构建,并且生成的压缩包要能在任意平台上解压使用。
听起来简单?其实不然。Windows上的ZIP包拿到Linux上解压,文件权限全丢了;Linux上的TGZ包拿到Windows上,很多解压工具不识别符号链接。
那怎么办?我的做法是:
- Windows平台:默认生成ZIP包,因为Windows原生支持ZIP。
- Linux/macOS平台:默认生成TGZ包,因为tar.gz能保留文件权限和符号链接。
- 如果需要跨平台分发:同时生成两种格式,让用户自己选。
代码实现起来也不复杂:
if(WIN32)
set(CPACK_GENERATOR "ZIP")
elseif(APPLE)
set(CPACK_GENERATOR "TGZ;ZIP")
else()
set(CPACK_GENERATOR "TGZ")
endif()
你想想看,这样是不是既照顾了各平台的习惯,又保证了兼容性?
文件权限处理:TGZ的天然优势
说到文件权限,TGZ生成器有个天然优势——它原生支持Unix文件权限。你只需要在安装规则里设置好权限,CPack会自动保留。
举个例子:
install(TARGETS myapp DESTINATION bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
install(FILES config.ini DESTINATION etc
PERMISSIONS OWNER_READ OWNER_WRITE
GROUP_READ
WORLD_READ)
这样生成的TGZ包里,myapp是可执行的,config.ini是只读的。解压后权限自动恢复。
但ZIP生成器呢?它不保留Unix权限。这是个硬伤。
那有没有办法补救?有的。你可以在安装后脚本里手动设置权限,但说实话,这很麻烦。我个人建议:如果目标平台包含Linux,优先用TGZ。
符号链接处理:小心这个“隐形炸弹”
符号链接是另一个容易出问题的地方。我记得有一次,项目里用到了动态库的符号链接(比如libfoo.so -> libfoo.so.1),结果生成的ZIP包在Windows上解压后,符号链接变成了普通文件,内容还是链接目标的内容……
为什么会这样?因为ZIP格式对符号链接的支持很有限。CPack的ZIP生成器默认会尝试保留符号链接,但跨平台时经常出问题。
TGZ就好很多。tar格式原生支持符号链接,只要你在安装时正确设置了符号链接,CPack会原样保留。
看个例子:
install(CODE [[
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
libfoo.so.1 libfoo.so
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/lib)
]])
或者用更CMake的方式:
install(FILES ${CMAKE_SOURCE_DIR}/lib/libfoo.so.1 DESTINATION lib)
install(CODE [[
file(CREATE_LINK libfoo.so.1 ${CMAKE_INSTALL_PREFIX}/lib/libfoo.so SYMBOLIC)
]])
这样生成的TGZ包里,符号链接是完整的。解压后,libfoo.so会正确指向libfoo.so.1。
知识体系一览
为了让你更直观地理解ZIP和TGZ生成器的核心逻辑,我画了一张图:
从图上可以看得很清楚:选择哪个生成器,取决于你的目标平台和需求。没有绝对的好坏,只有合不合适。
实战建议:我的经验总结
讲了这么多,最后给你几条实战建议:
- 优先用TGZ:除非你的用户全是Windows,否则TGZ是更安全的选择。权限和符号链接都能保留。
- ZIP只用于Windows分发:如果用户明确只需要Windows版本,ZIP没问题。但别忘了在文档里注明“解压后请手动设置可执行权限”。
- 同时生成两种格式:如果你做的是开源项目,建议同时提供ZIP和TGZ。用户习惯不同,多一个选择总是好的。
- 测试解压流程:我曾经吃过亏——生成的TGZ包在macOS上解压正常,但在某个Linux发行版上符号链接断了。后来发现是tar版本差异导致的。所以,一定要在目标平台上测试解压。
核心要点:
- ZIP生成器适合Windows平台,但不保留Unix权限和符号链接
- TGZ生成器适合Linux/macOS平台,完整保留权限和符号链接
- 跨平台分发时,建议同时生成两种格式
- 符号链接处理是ZIP生成器的短板,TGZ则无此问题
好了,这一讲的内容就到这里。ZIP和TGZ是最基础的生成器,下一讲我们会继续深入其他生成器,比如DEB、RPM和NSIS,到时候再聊。
公众号:蓝海资料掘金营,微信deep3321