CMake使用CPack制作安装程序
CPack的功能很强大,笔者前面有一博文
使用CMake的CPack工具打包项目介绍了一下使用CPack来打包成7z
压缩文件,不仅如此,它还可以生成各平台的安装包。
CPack支持以下类型的生成器:
名称 | 文件类型 | 平台及说明 |
---|---|---|
STGZ | STGZ(.sh) | 自解压文件,支持shell脚本的平台 |
7Z | 7zip(.7z) | 跨平台 |
ZIP | ZIP(.zip) | 跨平台 |
TGZ | TGZ(.tar.gz) | 跨平台 |
TXZ | TXZ(.tar.xz) | 跨平台 |
TBZ2 | TBZ2(.tar.bz2) | 跨平台 |
TZ | TZ(.tar) | 跨平台 |
TZST | TZST(.tar.zst) | 跨平台 |
RPM | RPM(.rpm) | Linux,用于redhat系产品 |
DEB | DEB(.deb) | Linux,用于Debian, ubuntu系列产品 |
DragNDrop | DMG(.dmg) | macOS |
productbuild | PKG(.pkg) | macOS |
Bundle | Bundle(.bundle) | macOS |
NSIS | Binary(.exe) | Windows |
INNOSETUP | Binary(.exe) | Windows |
NuGet | NuGet(.nupkg) | Windows |
WIX | MSI(.msi) | Windows |
IFW | Binary | Linux, Windows, macOS,使用QtIFW编译器生成 |
External | JSON(.json) | 与外部打包工具集成 |
FreeBSD | PKG(pkg) | BSD,Linux, OSX |
本文就介绍一下如何使用CPack来制作各个主流平台的应用程序安装程序。
关于CPack的知识,可以参考 https://cmake.org/cmake/help/latest/module/CPack.html
一、Linux
1. RPM
RPM安装包格式适用于red hat
出品的系统RHEL
以及centos
。
安装rpmbuild
要制作RPM包,必须要先安装rpmbuild
命令。
在ubuntu
下使用下面的命令安装:
1sudo apt install rpm
安装后既可以使用rpm
命令,也可以使用rpmbuild
命令。
如果是CentOS系统,默认是有rpm
命令的,需要使用下面的命令单独安装rpmbuild
。
1 yum install rpm-build
CMakeLists.txt设置
1#设置安装规则
2install(TARGETS ${PROJECT_NAME} DESTINATION /usr/local/bin)
3#设置CPack生成器为RPM
4set(CPACK_GENERATOR "RPM")
5#设置CPack项目名称
6set(CPACK_PROJECT_NAME ${PROJECT_NAME})
7#设置CPack项目版本
8set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
9#必须包含CPack的cmake文件
10include(CPack)
2. DEB
DEB格式适用于Debian
以及Ubuntu
系统。CMakeLists.txt设置:
1#设置安装规则
2install(TARGETS ${PROJECT_NAME} DESTINATION /usr/local/bin)
3# DEB要求设置`CPACK_PACKAGE_CONTACT`或者`CPACK_DEBIAN_PACKAGE_MAINTAINER`变量
4set(CPACK_PACKAGE_CONTACT "witton@163.com")
5#设置CPack生成器为RPM
6set(CPACK_GENERATOR "DEB")
7#设置CPack项目名称
8set(CPACK_PROJECT_NAME ${PROJECT_NAME})
9#设置CPack项目版本
10set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
11#必须包含CPack的cmake文件
12include(CPack)
生成好DEB格式后,可以使用apt命令安装:
1sudo apt install ./demo-0.1.0-Linux.deb
如果想要生成多种安装包格式,可以在CPACK_GENERATOR
变量中填写多个,以分号隔开:
1set(CPACK_GENERATOR "DEB;RPM")
二、MacOS
macOS下制作安装包,稍麻烦一点,最主要的问题是动态库的搜索路径问题,在Linux下可以使用ldconfig进行配置,但是MacOS下没有这样的工具,虽然有环境变量DYLD_LIBRARY_PATH
或 DYLD_FALLBACK_LIBRARY_PATH
可以设置,但是如果生成程序的时候rpath
没有设置为@rpath
开头的路径,而是使用的绝对路径,就是灾难。
所以在生成程序时,最好是设置程序的动态库路径为@rpath
开头的路径。有关MacOS程序的@rpath
、@loader_path
、@executable_path
可以在网络上搜索相关资料。
这里我们以一个实例来讲,更好理解。下面为t
项目结构:
有一个lib
库,提供了一个函数foo
,供main.cc
调用,lib.h
与priv.h
分别为lib库的公开头文件与私有头文件。
lib/lib.cc
:
1#include <iostream>
2using namespace std;
3
4void foo() {
5 cout << "foo" << endl;
6}
lib/lib.h
:
1#ifndef __LIB__H__
2#define __LIB__H__
3
4#include "priv/priv.h"
5
6void foo();
7
8#endif //__LIB__H__
lib/priv/priv.h
:
1#pragma once
2
3#ifndef __LIB__H__
4#error 私有头文件不能直接包含,需要include `lib.h`
5#endif
6
7// 这是私有头文件
为了展示动态库和静态的安装,这里把lib
库,既编译成动态库,也编译成静态库:
lib/CMakeLists.txt
:
1cmake_minimum_required(VERSION 3.25.0)
2project(tlib VERSION 0.1.0)
3
4add_library(${PROJECT_NAME} SHARED lib.cc)
5add_library(${PROJECT_NAME}s lib.cc)
6
7#设置库的公开头文件,注意,这里一定要加上${CMAKE_CURRENT_SOURCE_DIR},不然安装时会找不到文件
8set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/lib.h)
9#设置库的私有头文件
10set_target_properties(${PROJECT_NAME} PROPERTIES PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/priv/priv.h)
main.cc
:
1#include <stdio.h>
2#include <stdlib.h>
3#include "lib.h"
4
5int main(int argc, char *argv[])
6{
7 foo();
8 return 0;
9}
CMakeLists.txt
:
1cmake_minimum_required(VERSION 3.25.0)
2project(t VERSION 0.1.0)
3
4add_subdirectory(lib)
5aux_source_directory(. SRC)
6
7add_executable(${PROJECT_NAME} ${SRC})
8target_include_directories(${PROJECT_NAME} PUBLIC lib)
9target_link_libraries(${PROJECT_NAME} tlib)
10
11#设置安装规则
12install(TARGETS ${PROJECT_NAME} tlib tlibs
13 ARCHIVE DESTINATION ${PROJECT_NAME}/lib #静态库,macOS中标记为“FRAMEWORK”除外
14 LIBRARY DESTINATION ${PROJECT_NAME}/lib #动态库,macOS中标记为“FRAMEWORK”除外
15 RUNTIME DESTINATION ${PROJECT_NAME}/bin #可执行文件,macOS中标记为“MACOSX_BUNDLE”除外
16 FRAMEWORK DESTINATION ${PROJECT_NAME}/framework # 在 macOS上,标有“FRAMEWORK”属性的静态库和共享库都被视为“FRAMEWORK”目标。
17 PUBLIC_HEADER DESTINATION ${PROJECT_NAME}/include # 与库关联的任何公开头文件
18 PRIVATE_HEADER DESTINATION ${PROJECT_NAME}/include/priv # 与库关联的任何私有头文件
19)
我们期望最终制作的安装包,安装后的结构:
1. dmg
为了制作dmg
格式的安装包,CMakeLists.txt
文件中添加
1# 需要设置`${PROJECT_NAME}`目标的属性`INSTALL_RPATH`为`@loader_path/../lib`,
2# 即安装后的运行时路径为`@loader_path/../lib`,@loader_path是重点,
3# 是相对于可执行文件的路径,否则会出现找不到`libtlib.dylib`库。
4# 可以设置多个路径,在后面直接添加即可,比如再添加`/usr/local/lib`
5set_property(
6 TARGET ${PROJECT_NAME}
7 PROPERTY
8 INSTALL_RPATH
9 "@loader_path/../lib"
10 "/usr/local/lib"
11)
12# 设置CPACK的生成器类型为`DragNDrop`
13set(CPACK_GENERATOR DragNDrop)
14#设置CPack的项目名
15set(CPACK_PROJECT_NAME ${PROJECT_NAME})
16#设置CPack的项目版本号
17set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
18#必须包含CPack
19include(CPack)
执行CPack打包命令后,会生成t-0.1.0-Darwin.dmg
安装包,在MacOS系统中双击加载后好即可拖曳安装了,与其它DMG
安装包一样。
拖曳安装好后,执行:
使用otool -L ./t
命令来查看依赖:
使用otool -l ./t
命令来查看rpath
:
完整的CMakeLists.txt
:
1cmake_minimum_required(VERSION 3.25.0)
2project(t VERSION 0.1.0)
3
4add_subdirectory(lib)
5
6aux_source_directory(. SRC)
7
8add_executable(${PROJECT_NAME} ${SRC})
9target_include_directories(${PROJECT_NAME} PUBLIC lib)
10target_link_libraries(${PROJECT_NAME} tlib)
11
12#设置安装规则
13install(TARGETS ${PROJECT_NAME} tlib tlibs
14 ARCHIVE DESTINATION ${PROJECT_NAME}/lib #静态库,macOS中标记为“FRAMEWORK”除外
15 LIBRARY DESTINATION ${PROJECT_NAME}/lib #动态库,macOS中标记为“FRAMEWORK”除外
16 RUNTIME DESTINATION ${PROJECT_NAME}/bin #可执行文件,macOS中标记为“MACOSX_BUNDLE”除外
17 FRAMEWORK DESTINATION ${PROJECT_NAME}/framework # 在 macOS上,标有“FRAMEWORK”属性的静态库和共享库都被视为“FRAMEWORK”目标。
18 PUBLIC_HEADER DESTINATION ${PROJECT_NAME}/include # 与库关联的任何公开头文件
19 PRIVATE_HEADER DESTINATION ${PROJECT_NAME}/include/priv # 与库关联的任何私有头文件
20)
21# 需要设置`${PROJECT_NAME}`目标的属性`INSTALL_RPATH`为`@loader_path/../lib`,
22# 即安装后的运行时路径为`@loader_path/../lib`,@loader_path是重点,
23# 是相对于可执行文件的路径,否则会出现找不到`libtlib.dylib`库。
24# 可以设置多个路径,在后面直接添加即可,比如再添加`/usr/local/lib`
25set_property(
26 TARGET ${PROJECT_NAME}
27 PROPERTY
28 INSTALL_RPATH
29 "@loader_path/../lib"
30 "/usr/local/lib"
31)
32
33# 设置CPACK的生成器类型为`DragNDrop`
34set(CPACK_GENERATOR DragNDrop)
35#设置CPack的项目名
36set(CPACK_PROJECT_NAME ${PROJECT_NAME})
37#设置CPack的项目版本号
38set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
39#必须包含CPack
40include(CPack)
2. pkg
CPack生成器productbuild
可以生成macOS下的pkg
安装包。
将前面的CPACK_GENERATOR
改为productbuild
,再使用cpack_add_component(${PROJECT_NAME} REQUIRED)
添加进组件即可生成一个简单的安装包,如果没有使用cpack_add_component(${PROJECT_NAME} REQUIRED)
添加组件,只会生成一个空包。
完整的CMakeLists.txt
:
1cmake_minimum_required(VERSION 3.25.0)
2project(t VERSION 0.1.0)
3
4add_subdirectory(lib)
5
6aux_source_directory(. SRC)
7
8add_executable(${PROJECT_NAME} ${SRC})
9target_include_directories(${PROJECT_NAME} PUBLIC lib)
10target_link_libraries(${PROJECT_NAME} tlib)
11
12#设置安装规则
13install(TARGETS ${PROJECT_NAME} tlib tlibs
14 ARCHIVE DESTINATION ${PROJECT_NAME}/lib #静态库,macOS中标记为“FRAMEWORK”除外
15 LIBRARY DESTINATION ${PROJECT_NAME}/lib #动态库,macOS中标记为“FRAMEWORK”除外
16 RUNTIME DESTINATION ${PROJECT_NAME}/bin #可执行文件,macOS中标记为“MACOSX_BUNDLE”除外
17 FRAMEWORK DESTINATION ${PROJECT_NAME}/framework # 在 macOS上,标有“FRAMEWORK”属性的静态库和共享库都被视为“FRAMEWORK”目标。
18 PUBLIC_HEADER DESTINATION ${PROJECT_NAME}/include # 与库关联的任何公开头文件
19 PRIVATE_HEADER DESTINATION ${PROJECT_NAME}/include/priv # 与库关联的任何私有头文件
20)
21# 需要设置`${PROJECT_NAME}`目标的属性`INSTALL_RPATH`为`@loader_path/../lib`,
22# 即安装后的运行时路径为`@loader_path/../lib`,@loader_path是重点,
23# 是相对于可执行文件的路径,否则会出现找不到`libtlib.dylib`库。
24# 可以设置多个路径,在后面直接添加即可,比如再添加`/usr/local/lib`
25set_property(
26 TARGET ${PROJECT_NAME}
27 PROPERTY
28 INSTALL_RPATH
29 "@loader_path/../lib"
30 "/usr/local/lib"
31)
32
33# 设置CPACK的生成器类型为`productbuild`
34set(CPACK_GENERATOR productbuild)
35#设置CPack的项目名
36set(CPACK_PROJECT_NAME ${PROJECT_NAME})
37#设置CPack的项目版本号
38set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
39#必须包含CPack
40include(CPack)
41#这里必须使用cpack_add_component命令添加组件,否则只会生成一个空包
42cpack_add_component(${PROJECT_NAME} REQUIRED)
安装情况如下所示:
默认情况下,介绍
,请先阅读
,许可
三个页面的内容是CPack的模板内容,是三个txt
文本文件,需要自定义一下,可以使用html文件。在项目根目录添加一个res
目录,把所有自定义的CPack安装模板放在里面,现在目录树:
welcome.html
:
1<html>
2 <head>
3 <meta charset="utf-8">
4 </head>
5 <body>
6 <h1>欢迎使用macOS软件t</h1>
7 </body>
8</html>
readme.html
:
1<html>
2 <head>
3 <meta charset="utf-8">
4 </head>
5 <body>
6 <h1>读一下我吧!</h1>
7 </body>
8</html>
license.html
:
1<html>
2 <head>
3 <meta charset="utf-8">
4 </head>
5 <body>
6 <h1>版权所有(C),Witton Bell</h1>
7 </body>
8</html>
CMakeLists.txt
设置:
1set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/res/welcome.html")
2set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/res/license.html")
3set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/res/readMe.html")
4
5# 设置CPACK的生成器类型为`productbuild`
6set(CPACK_GENERATOR productbuild)
7#设置CPack的项目名
8set(CPACK_PROJECT_NAME ${PROJECT_NAME})
9#设置CPack的项目版本号
10set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
11#必须包含CPack
12include(CPack)
13cpack_add_component(${PROJECT_NAME} REQUIRED)
现在生成的安装包,运行如下所示:
三、Windows
Window下介绍一下NSIS/NSIS64
,它是一个开源的安装包制作工具。
使用nsis软件来制作安装包,需要先下载
nsis并安装。
设置CPack的生成器为NSIS
或者NSIS64
,该安装程序的许可证是UTF16编码格式的文本。
CMakeLists.txt
设置:
1set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/res/license.txt")
2
3# 设置CPACK的生成器类型为`NSIS64`
4set(CPACK_GENERATOR NSIS64)
5#设置CPack的项目名
6set(CPACK_PROJECT_NAME ${PROJECT_NAME})
7#设置CPack的项目版本号
8set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
9#必须包含CPack
10include(CPack)
它有一些特殊的变量,可以自定义安装界面的一些显示,具体参见: https://cmake-doc.readthedocs.io/zh-cn/latest/cpack_gen/nsis.html
NSIS软件可以做很多定制,感兴趣的读者可以继续深究!
四、自解压安装包
自解压安装包是使用的shell脚本作为安装程序的,它的CMakeLists.txt
设置:
1#设置许可证文本的文件,而不是内容
2set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/res/license.txt")
3# 设置CPACK的生成器类型
4set(CPACK_GENERATOR "STGZ")
5#设置CPack的项目名
6set(CPACK_PROJECT_NAME ${PROJECT_NAME})
7#设置CPack的项目版本号
8set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
9set(CPACK_PACKAGE_VENDOR "Witton Bell")
10#必须包含CPack
11include(CPack)
实际上它是根据CMake安装目录下share/cmake/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
的模板文件来生成的。
它主要可以定制以下变量:
- CPACK_PACKAGE_NAME:包名
- CPACK_PACKAGE_VERSION:包版本
- CPACK_PACKAGE_VENDOR:包所有者
- CPACK_RESOURCE_FILE_LICENSE_CONTENT:直接设置许可证内容
如果想要定制更多内容,可以修改CPack.STGZ_Header.sh.in
模板文件的内容。
如果对你有帮助,欢迎点赞收藏!
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2025/2025-01-23-CMake使用CPack制作安装程序/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。