为了介绍如何使用CMake的CPack工具进行项目打包,这里使用了前文CMake项目使用ctest+gtest进行单元测试中的示例。
为了更接近实际开发中项目的情况,自行下载gtest并进行源码编译来模拟实际项目中的依赖项;在实际的开发中,可能会有各种各样的配置文件需要在打包的时候一起发布出去,这里在根目录下创建一个bin目录(将所有项目生成的文件全部指定生成到此目录下的各个项目目录中),下面再创建一个demo目录(根据项目来取名),在demo目录中创建一个config.ini文件。
根目录的CMakeLists.txt
如下:
cmake_minimum_required(VERSION 3.12.0)
project(demo VERSION 0.1.0)
# 这里不管系统有没安装GTest都从网络上下载源码进行编译,使用自己编译的GTest
cmake_policy(SET CMP0135 NEW)
message("download GTest...")
include(FetchContent)
FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/refs/heads/main.zip)
FetchContent_MakeAvailable(googletest)
include(CTest)
enable_testing()
#设置编译后的可执行文件存放路径
set(BIN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin)
add_subdirectory(test)
# 根据项目存放到以项目名命名的目录中
set(EXECUTABLE_OUTPUT_PATH ${BIN_DIR}/${PROJECT_NAME})
add_executable(${PROJECT_NAME} main.cpp)
# 设置需要安装的文件
install(DIRECTORY ${BIN_DIR}
DESTINATION ./
FILES_MATCHING
PATTERN "*.exe"
PATTERN "*.ini"
)
# 设置包的模式,可以是7Z、ZIP等等,参见cpack --help
set(CPACK_GENERATOR 7Z)
include(CPack)
为了让各个项目都将编译后的可执行文件按指定要求存放,需要在每个子项目中(project后)添加如下指令:set(EXECUTABLE_OUTPUT_PATH ${BIN_DIR}/${PROJECT_NAME})
本例中需要在test目录中修改CMakeLists.txt
:
project(t)
set(EXECUTABLE_OUTPUT_PATH ${BIN_DIR}/${PROJECT_NAME})
add_executable(${PROJECT_NAME} test.cpp ../func.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main)
include(GoogleTest)
gtest_discover_tests(t)
然后设置需要安装的文件,根据前面的设定,这里使用目录的方式设定安装文件:
install(DIRECTORY ${BIN_DIR}
DESTINATION ./
FILES_MATCHING
PATTERN "*.exe"
PATTERN "*.ini"
)
即将所有输出目录中的exe文件以及ini文件打包。
此时编译后的目录结构如下:
在build目录(有CMakeCache.txt的目录),运行cpack,即可得到打包后的文件,笔者的为demo-0.1.0-win64.7z
可以在build_CPack_Packages\win64\7Z\demo-0.1.0-win64查看打包的情况,这里有额外的include与lib,并不是想要的,是因为使用的GTest为自行编译的库,如果不想让它们出现在包中,可以在引入GTest之前设置INSTALL_GTEST
为OFF
现在很多项目都是使用的Git来管理项目,可以在打包的时候以Git的分支名时期时间,SHA组合的方式来命名包。
在根CMakeLists.txt
中的install指令前添加如下指令:
string(TIMESTAMP vTimeStamp "%Y%m%d%H%M%S")
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE vGitCommit
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE vGitBranch
OUTPUT_STRIP_TRAILING_WHITESPACE
)
在include(CPack)
前加上set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${vGitBranch}-${vTimeStamp}-${vGitCommit}")
即可。
附上最终根CMakeLists.txt
:
cmake_minimum_required(VERSION 3.12.0)
project(demo VERSION 0.1.0)
set(INSTALL_GTEST OFF)
cmake_policy(SET CMP0135 NEW)
message("GTest not found, download it...")
include(FetchContent)
FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/refs/heads/main.zip)
FetchContent_MakeAvailable(googletest)
include(CTest)
enable_testing()
set(BIN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin)
add_subdirectory(test)
set(EXECUTABLE_OUTPUT_PATH ${BIN_DIR}/${PROJECT_NAME})
add_executable(${PROJECT_NAME} main.cpp)
string(TIMESTAMP vTimeStamp "%Y%m%d%H%M%S")
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE vGitCommit
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE vGitBranch
OUTPUT_STRIP_TRAILING_WHITESPACE
)
install(DIRECTORY ${BIN_DIR}
DESTINATION ./
FILES_MATCHING
PATTERN "*.exe"
PATTERN "*.ini"
)
set(CPACK_GENERATOR 7Z)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${vGitBranch}-${vTimeStamp}-${vGitCommit}")
include(CPack)