28、CPack中的许可证管理:许可证文件包含、许可证选择、许可证显示
许可证管理这件事,说实话,很多开发者一开始都不太在意。我以前也是这样,觉得代码写出来能用就行,许可证随便选一个。直到有一次,我打包了一个开源项目,结果用户反馈说找不到许可证文件,差点惹上法律麻烦。嗯,从那以后,我再也不敢忽视CPack里的许可证配置了。
今天我们就来聊聊,CPack里许可证到底怎么管。说白了就三件事:选什么许可证、怎么把许可证文件塞进安装包、用户安装时怎么看到它。
核心要点:CPack的许可证管理涉及三个层面——许可证选择(指定协议类型)、许可证包含(将LICENSE文件打包)、许可证显示(安装过程中展示协议)。
许可证选择:别随便选一个
CPack本身不替你选许可证,它只是把你在CMakeLists.txt里指定的许可证信息打包进去。我个人习惯在项目根目录放一个LICENSE文件,然后在CMake里这样配置:
# 设置项目许可证
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
# 或者指定许可证简称
set(CPACK_PACKAGE_LICENSE "MIT")
这里要注意,CPACK_RESOURCE_FILE_LICENSE指向的是你本地的许可证文件路径。而CPACK_PACKAGE_LICENSE只是一个字符串标识,告诉用户你的项目用的是哪种协议。
我曾经见过有人把这两个搞混,结果打包出来的安装包里,许可证文件内容是空的,但界面上却写着"GPL-3.0"。你说这多尴尬?
| 变量名 | 作用 | 示例值 |
|---|---|---|
CPACK_RESOURCE_FILE_LICENSE |
指定许可证文件的路径(会被打包进安装包) | ${CMAKE_SOURCE_DIR}/LICENSE |
CPACK_PACKAGE_LICENSE |
设置许可证的简称或标识 | MIT、Apache-2.0 |
许可证文件包含:把LICENSE塞进包里
这一步其实很简单,但很多人会忘。你想想看,用户下载了你的安装包,打开一看,没有许可证文件,他敢用吗?
正确的做法是,在install()命令里把许可证文件一起安装:
install(
FILES LICENSE
DESTINATION share/doc/${PROJECT_NAME}
COMPONENT Runtime
)
然后CPack在打包时,会自动把这个文件包含进去。不过要注意,CPACK_RESOURCE_FILE_LICENSE这个变量指向的文件,是安装过程中显示的许可证,不是安装到目标目录的那个文件。两者可以不同,但我建议保持一致。
小技巧:如果你的项目用了多个第三方库,每个库都有自己的许可证,我建议在项目根目录建一个LICENSES/文件夹,把所有许可证文件放进去,然后在CMake里统一安装。
# 安装所有第三方许可证
install(
DIRECTORY LICENSES/
DESTINATION share/doc/${PROJECT_NAME}/licenses
COMPONENT Runtime
)
许可证显示:让用户看到协议
不同平台的安装包,显示许可证的方式不一样。我挑几个常用的说说:
- NSIS(Windows安装包):安装过程中会弹出一个窗口,显示许可证文本。用户必须点击"我同意"才能继续。
- DMG(macOS磁盘映像):通常不会强制显示,但许可证文件会放在包内。
- DEB/RPM(Linux包):安装时不会弹窗,但包管理器会记录许可证信息。
对于NSIS这种需要交互的安装器,CPack会自动读取CPACK_RESOURCE_FILE_LICENSE指向的文件,并显示在安装向导中。你不需要额外写代码。
注意:NSIS对许可证文件的编码有要求。我曾经遇到过一个问题——许可证文件是UTF-8编码,但NSIS只认ANSI,结果安装时显示乱码。解决方案是:把LICENSE文件另存为ANSI编码,或者用CPACK_NSIS_LICENSE_OVERRIDE变量指定一个兼容的文件。
# 针对NSIS的特殊处理
if(WIN32)
set(CPACK_NSIS_LICENSE_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE_ANSI.txt")
endif()
知识体系结构图
下面这张图,我把许可证管理的整个流程梳理了一下。你可以看到,从选择许可证到最终显示给用户,中间涉及哪些环节:
避坑指南:我踩过的几个坑
做CPack打包这些年,我在许可证管理上栽过好几次跟头。分享出来,希望大家别重蹈覆辙:
- 许可证文件路径写错:我曾经把
CPACK_RESOURCE_FILE_LICENSE指向了一个不存在的路径,结果CPack直接报错退出。后来我习惯在CMake里加一个判断:if(NOT EXISTS ${CPACK_RESOURCE_FILE_LICENSE}),提前检查文件是否存在。 - 多许可证项目处理不当:如果你的项目用了MIT、Apache、GPL三种协议的库,千万别只放一个LICENSE文件。我建议在安装目录下建一个
licenses/子目录,把每个库的许可证单独放进去。 - 忘记更新许可证:项目升级时,如果换了许可证协议,记得同步更新CMake里的配置。我见过有人项目从MIT改成了GPL,但CPACK_PACKAGE_LICENSE还写着MIT,这要是被用户发现,麻烦就大了。
我的个人习惯:每次发布新版本前,我都会跑一遍cpack --config CPackConfig.cmake,然后手动检查生成的安装包里是否包含许可证文件。虽然麻烦点,但心里踏实。
总结一下
许可证管理说白了就三步:选对协议、放对文件、显示正确。CPack提供了CPACK_RESOURCE_FILE_LICENSE和CPACK_PACKAGE_LICENSE两个变量来帮你完成这些事。不同平台的显示方式有差异,但核心逻辑是一样的。
嗯,如果你在配置过程中遇到问题,不妨先检查一下许可证文件的编码和路径。这两个地方最容易出岔子。
公众号:蓝海资料掘金营,微信deep3321