來源:公衆號【很酷的程序員/RealCoolEngineer】
爲了方便使用項目編譯的目標文件,快速部署到目標目錄,可以使用CMake的安裝功能;如果需要對外發布,提供頭文件、庫文件、或者demo的壓縮包則可以使用CMake的打包功能。
在本系列前序的文章中已經介紹了CMake很多內容,在CMake應用:CMakeLists.txt完全指南
一文中簡略介紹了安裝和打包,本文會更加深入地介紹CMake的安裝和打包功能。本系列更多精彩文章敬請關注公衆號【很酷的程序員】的話題:CMake。
本文主要介紹以下幾個方面的內容:
- 安裝庫文件、可執行文件和所需要對外提供的頭文件
- 將需要安裝的文件打包成壓縮包
- 編譯構建腳本編寫
本文會先介紹相關命令和知識點,如果想先實踐,可直接跳到最後一部分。
一 安裝
1 install命令
安裝使用install
命令,用於指定一個項目的安裝規則。其命令格式如下:
install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])
以上命令概述顯示install
命令可以安裝的目標類型:構建目標、文件、程序、目錄等,對應的關鍵字後面跟上對應要安裝的目標。
安裝不同的目標的時候,有一些通用的關鍵字,下面着重介紹幾個最常使用的。
DESTINATION
很好理解,就是安裝對象的目標安裝路徑,可以是絕對路徑,也可以是相對路徑,如果是相對路徑,則認爲是相對於CMAKE_INSTALL_PREFIX
的,所以可以配置CMAKE_INSTALL_PREFIX
指定安裝目錄。
因爲cpack
並不支持絕對路徑,所以建議還是不要使用絕對路徑,當然,除非這是開發者自己確切的目的。
CONFIGURATIONS
爲不同的配置設置不同的安裝規則。假如對Debug
和Release
兩個配置不同的安裝路徑,代碼示例如下:
install(TARGETS target
CONFIGURATIONS Debug
RUNTIME DESTINATION Debug/bin)
install(TARGETS target
CONFIGURATIONS Release
RUNTIME DESTINATION Release/bin)
PERMISSIONS
設置安裝目標的權限,接受的參數是一個權限關鍵字列表,比如:
install(TARGETS target
RUNTIME PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
2 安裝構建目標
安裝構建目標的命令格式爲:
install(TARGETS static_lib shared_lib exe
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
命令第一個參數TARGETS
指定需要安裝的構建目標的列表,可以是靜態庫文件、動態庫文件、可執行文件;安裝時常常按照文件類型安裝到不同的子目錄,比如庫文件放在lib
目錄,可執行文件放在bin
目錄。
針對不同文件類型,比如(RUNTIME
, ARCHIVE
, LIBRARY
,PUBLIC_HEADER
),可以分開進行配置,比如分別指定安裝路徑(DESTINATION
)、設置文件權限(PERMISSIONS
);如果不是在某個類別下的單獨配置,那麼就是針對所有類型。
值得一提的是,ARCHIVE
一般是指靜態庫,LIBRARY
則是指共享庫,在不同平臺上,略有差異,實際應用感覺不符合預期時查看一下官方文檔即可,問題不大。
3 安裝目錄
安裝一個目錄,一般用於將頭文件安裝到目標路徑。
在實際使用中,一般把需要安裝的頭文件放到一個特定目錄下,然後直接安裝整個目錄即可,比如:
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
更加完備的命令格式爲:
install(DIRECTORY dirs...
TYPE <type> | DESTINATION <dir>
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]]
TYPE/DESTINATION
安裝目錄必須執行安裝的目錄類型TYPE
或者安裝的目標路徑DESTINATION
,但是又不可以同時指定;可以使用TYPE
指定安裝的目錄中的文件類型,然後CMake會自動按照類型分配安裝目錄,不同類型對應的安裝路徑如下圖:
當然,開發者也可以選擇只使用DESTINATION
顯式指定安裝的目錄。
FILES_MATCHING
安裝目錄的時候默認會安裝所有的文件,如果使用FILES_MATCHING
關鍵字(在第一個PATTERN
或者REGEX
之前),則表示必須要滿足對應的模式或者正則的文件才能被安裝。
比如,如果目錄下源文件和頭文件混在一起,但是隻想安裝其中的頭文件,則可以這樣寫:
install(DIRECTORY src/ DESTINATION include/
FILES_MATCHING PATTERN "*.h")
PATTERN/REGEX
PATTERN
表示文件名完全匹配纔會被安裝,而REGEX
則是通過正則表達式匹配目標安裝文件(針對目標文件的全路徑);在這兩個表達式後面還可以加上EXCLUDE
表示反選,或者使用PERMISSIONS
指定匹配的目標文件的權限。
3 安裝文件
和安裝目錄類似,只不過是安裝的是文件列表,核心的參數也是類似的;需要使用TYPE
指定文件類型,自行推斷安裝目錄,或者使用DESTINATION
顯式指定安裝目錄。命令格式爲:
install(<FILES|PROGRAMS> files...
TYPE <type> | DESTINATION <dir>
FILES
和PROGRAMS
的不同之處在於文件的默認權限,前者是一般文件,而後者爲可執行文件,默認有可執行權限,包括:OWNER_EXECUTE
,GROUP_EXECUTE
和WORLD_EXECUTE
。
4 自定義安裝腳本
使用install命令還可以在安裝的時候執行自定義的腳本,使用的命令格式爲:
install([[SCRIPT <file>] [CODE <code>]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL] [...])
SCRIPT
指定安裝時需要執行的腳本;CODE
指定的是CMake的命令,也在安裝期間執行,比如:
install(CODE "MESSAGE(\"Sample install message.\")")
5 執行安裝
在構建編譯完成之後,可以使用命令以下執行安裝:
cmake --build . --target install
# 或者針對make構建工具
make install
更加優雅的方法是在cmake
3.15版本往後,使用cmake --install
命令:
cmake --install . --prefix "../output"
--install
指定構建目錄;--preffix
指定安裝路徑,覆蓋安裝路徑變量CMAKE_INSTALL_PREFIX
。
二 打包
1 CPack
要使用打包功能,需要執行include(CPack)
啓用相關的功能。
include(CPack)
會在構建路徑(Build tree)下生成兩個cpack
的配置文件,CPackConfig.cmake
和CPackSourceConfig.cmake
,其實也就對應了兩個構建目標:package
和package_source
;
配合cpack
命令,使用-G
參數指定生成器,常用的有ZIP
、TGZ
、7Z
等,可以同時指定多個,格式也是CMake語法中的列表,例如其默認值"STGZ;TGZ"
;--config
參數可以指定打包配置文件,比如:
cpack -G TGZ --config CPackConfig.cmake
cpack -G TGZ --config CPackSourceConfig.cmake
當然也可以使用cmake
命令:
cmake --build . --target package
cmake --build . --target package_source
如果使用make
作爲構建工具,可以簡單地執行:
make package
make package_source
2 CMake打包相關的內置變量
打包的內容就是install
命令安裝的內容,以目標打包(CPackConfig.cmake
)爲例,主要的相關變量有:
變量 | 含義 |
---|---|
CPACK_GENERATOR | 打包使用的壓縮工具,比如"ZIP";cpack 命令的-G 參數會覆蓋此設置 |
CPACK_OUTPUT_CONFIG_FILE | 配置文件,默認爲CPackConfig.cmake
|
CPACK_OUTPUT_FILE_PREFIX | 打包安裝的路徑前綴。如果是相對路徑,則是相對於構建目錄 |
CPACK_INSTALL_PREFIX | 打包壓縮包的內部目錄前綴 |
CPACK_PACKAGE_FILE_NAME | 打包壓縮包的名稱,由CPACK_PACKAGE_NAME 、CPACK_PACKAGE_VERSION 、CPACK_SYSTEM_NAME 三部分構成 |
需要特別注意的是:以上變量的設置需要在include(CPack)
語句之前。
Before including this CPack module in your CMakeLists.txt file, there are a variety of variables that can be set to customize the resulting installers.
其中CPACK_PACKAGE_NAME
默認爲項目名稱,CPACK_PACKAGE_VERSION
默認爲項目版本號,它們的默認值都是對應project
命令所設置的值;但是如果沒有指定版本號,則會是CMake的默認值。
假如:
CPACK_OUTPUT_FILE_PREFIX
設置爲/usr/local/package
;
CPACK_INSTALL_PREFIX
設置爲RealCoolEngineer
;
CPACK_PACKAGE_FILE_NAME
設置爲CMakeTemplate-1.0.0
;
那麼執行打包文件的生成路徑爲:
/usr/local/package/CMakeTemplate-1.0.0.zip
解壓這個包得到的目標文件則會位於路徑下:
/usr/local/package/CMakeTemplate-1.0.0/RealCoolEngineer/
對於源文件打包,相關的變量名基本是對應地以
CPACK_SOURCE_
開頭,細節可以查看官方文檔。
三 實踐
本文仍以開源項目:https://gitee.com/RealCoolEngineer/cmake-template爲例,本文對應的commit id爲:5713908
。
在項目根目錄中的CMakeLists.txt文件中,使用安裝和打包的語句爲:
# Install
install(TARGETS math demo
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include)
file(GLOB_RECURSE MATH_LIB_HEADERS src/c/math/*.h)
install(FILES ${MATH_LIB_HEADERS} DESTINATION include/math)
# Package
set(CPACK_GENERATOR "ZIP")
set(CPACK_SET_DESTDIR ON) # 支持指定安裝目錄
set(CPACK_INSTALL_PREFIX "RealCoolEngineer")
include(CPack)
安裝打包的內容爲項目構建目標可執行文件demo
,靜態庫math
,以及math
庫對應的頭文件。
1 構建腳本
爲了方便,筆者通常將構建的命令編寫爲腳本,在腳本內指定文件的安裝、打包的目標目錄(CMake參數)。
下面針對cmake-template
的一個示範,將目標文件安裝並打包到項目根目錄下的output
目錄:
#!/bin/bash
set -euf -o pipefail
BUILD_DIR="cmake-build"
INSTALL_DIR=$(pwd)/output
rm -rf "${BUILD_DIR}"
# Configure
BUILD_TYPE=Debug
cmake -B "${BUILD_DIR}" \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCPACK_OUTPUT_FILE_PREFIX="${INSTALL_DIR}"
# Build
cmake --build "${BUILD_DIR}"
cd "${BUILD_DIR}"
# Test
make test CTEST_OUTPUT_ON_FAILURE=TRUE GTEST_COLOR=TRUE
# GTEST_COLOR=TRUE ctest --output-on-failure
# Install
# cmake --build . --target install
make install
# Package
# cmake --build . --target package
make package
cd -
以上便是關於安裝和打包的介紹,關於構建腳本開頭set
命令的幾個參數,可參看往期這篇文章: