iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
Software Development

30 天 CMake 跨平台之旅系列 第 20

[Day 20] 安裝 Project

  • 分享至 

  • xImage
  •  

本日內容

  • install(TARGETS)
  • install(EXPORT)
  • Package Config File
  • 預告

今天會介紹 CMake 的 install() 指令, install() 根據安裝的目標不同, 會有不同的寫法, 本系列只會介紹 install(TARGETS)install(EXPORT), 其他用法先在這簡單介紹

  • install(IMPORTED_RUNTIME_ARTIFACTS)
    • 用來安裝 build-time 用到的 外部 shared library
    • 需要注意, 有時候用 find_package() 找到的 imported target 會是 UNKNOWN type 而非 SHAREDSTATIC, 這時就沒辦法用此指令安裝該 target
  • install({FILES | PROGRAMS})
    • 一目了然, 就是用來裝一般檔案和 binaries 的指令
    • 一般檔案指的是非 headers 的檔案, headers 的建議用 target_sources(FILE_SET) 安裝
  • install(DIRECTORY)
    • 安裝時會保留原本的專案架構
    • 比如當 headers 散落在各個資料夾時, 用 install(FILE_SET) 會很麻煩, 就可以用這個指令
  • install(SCRIPT)
    • 有點小騙的指令, 他會在安裝時 執行 我們給他的 script 的路徑, 而非真的 安裝
  • install(CODE)
    • 安裝時執行的 CMake 指令
  • install(RUNTIME_DEPENDENCY_SET)
    • 可以和 install(TARGETS)install(IMPORTED_RUNTIME_ARTIFACTS) 搭配的指令
    • 如果使用上述兩個指令時有設定 RUNTIME_DEPENDENCY_SET, 執行這個指令就可以將該 targets 的 runtime dependencies 都一併安裝

install(TARGETS)

會將 targets 根據 FHS 的規則加入對應的 directory

install(TARGETS targets... [EXPORT <export-name>]
        [RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
        [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
          PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE|FILE_SET <set-name>|CXX_MODULES_BMI]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [NAMELINK_COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
         [NAMELINK_ONLY|NAMELINK_SKIP]
        ] [...]
        [INCLUDES DESTINATION [<dir> ...]]
)
  • TARGETS
    • 可以指定多個 targets, CMake 會自動幫我們根據 target type 將 target 裝到對應的安裝路徑 (ex. executables to bin, libraries to lib)
  • EXPORT
    • 搭配 install(EXPORT) 使用, 下面會介紹
  • RUNTIME_DEPENDENCIES
    • 類似上面提到的 install(RUNTIME_DEPENDENCY_SET), 不過這邊會會在安裝此 target 的時候一併安裝指定的 dependencies
  • RUNTIME_DEPENDENCIES_SET
    • RUNTIME_DEPENDENCIES 會和 target 一起安裝不同, 這裡僅先設定 dependency set 名稱, 等到 install(RUNTIME_DEPENDENCY_SET) 才安裝
  • 下面則是根據不同的 entity type 調整其設定, 包含
    • ARCHIVE
    • LIBRARY
    • RUNTIME
    • OBJECTS
    • FRAMEWORK
    • BUNDLE
    • PRIVATE_HEADER
    • PUBLIC_HEADER
    • RESOURCE
    • FILE_SET
    • CXX_MODULES_BMI
  • DESTINATION
    • 安裝的目的地
    • 沒給的話會用 GNUInstallDirs 提供的路徑, 根據 target type 去安裝, 可以參考官網的表
      https://ithelp.ithome.com.tw/upload/images/20230920/20161950jgobx45lSR.png
    • 雖然可以自己指定路徑, 但建議還是以 GNUInstallDirs 提供的為主, 比如可以將 headers 裝到 ${CMAKE_INSTALL_INCLUDEDIR}/<project-name> 而非 lib 底下
  • PERMISSIONS
    • 調整安裝的檔案的權限, 包含以下幾種 (基於 Unix permissions)
    • OWNER_READ
    • OWNER_WRITE
    • OWNER_EXECUTE
    • GROUP_READ
    • GROUP_WRITE
    • GROUP_EXECUTE
    • WORLD_READ
    • WORLD_WRITE
    • WORLD_EXECUTE
    • SETUID
    • SETGID
    • 如果是裝到 Windows 上 (ACL), 某些權限會直接忽略, 這個等到 Day 28 再說
  • CONFIGURATIONS
    • 可以指定多個 build types
  • COMPONENT
    • 可以將 targets 加入 component 後, 用 cli cmake -DCOMPONENT=<component> 單獨安裝該 component 的 targets
  • NAMELINK_COMPONENT, NAMELINK_ONLY, NAMELINK_SKIP
    • 可以將 namelink 加入 component, 單獨安裝或是跳過
    • 記得在 Day 16 有介紹過 shared library 的 soversion (or soname) 會指向真正的 library, namelink 則是指向 library 的 soname, 讓 linker 可以找到真正的 library 版本
  • INCLUDES DESTINATION
    • 會將指定的路徑加到 target 的 INTERFACE_INCLUDE_DIRECTORIES property, 讓 import 該 target 的 target 能找到需要的 headers

install(EXPORT)

該指令會幫我們產生 可以讓別人 import 我們 targets 的 cmake file, 預設是 <export-name>.cmake, 如果要讓別人使用此專案, 這就是個很方便的指令

install(EXPORT <export-name> DESTINATION <dir>
        [NAMESPACE <namespace>] [FILE <name>.cmake]
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]
        [CXX_MODULES_DIRECTORY <directory>]
        [EXPORT_LINK_INTERFACE_LIBRARIES]
        [COMPONENT <component>]
        [EXCLUDE_FROM_ALL]
)
  • EXPORT
    • 搭配 install(TARGETS <target-name> EXPORT <export-name>) 使用
  • DESTINATION
    • export targets 安裝的路徑
  • NAMESPACE
    • 很重要的參數, 這會讓我們專案更好讓人使用
    • 記得 Day 14fmt 進來時, fmt 提供的 imported targets 是 fmt::fmt-header-onlyfmt::fmt-core, 前面的 fmt:: 就是 namespace
    • Namespace 可以有效的預防我們專案的 targets 和別人撞名, 所以通常會用 專案名稱 和 :: 當作 namespace <project-name>::
  • FILE
    • 指定安裝的 CMake file 名稱, 預設是 <export-name>.cmake
    • 所以安裝的檔名需要有 .cmake extension
  • PERMISSIONS
    • install(TARGETS), 這邊不多贅述
  • CONFIGURATIONS
    • 僅符合指定的 build types 才安裝
  • COMPONENT
    • 會安裝 install(TARGETS) 時指定的 component 中的所有 targets

Package Config File

記得 Day 13 提過的幾種引進外部 libraries 的方法嗎? 現在我們要自己寫一份讓其他使用者用 find_package() 來引進我們專案
所以我們專案 targets 的版本也很重要

我們可以用 CMakePackageConfigHelpers module 提供的兩個 functions: write_basic_package_version_file()configure_package_config_file()

write_basic_package_version_file()

會產生 <export-name>ConfigVersion.cmake 標示當前使用的 library 版本

write_basic_package_version_file(<filename>
  [VERSION <major.minor.patch>]
  COMPATIBILITY <AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion>
  [ARCH_INDEPENDENT]
)
  • ARCH_INDEPENDENT
    • 給 header-only libraries 使用
    • 指定該 option 就不會檢查目的地的指令集架構和指定的是否相同

configure_package_config_file()

幫我們產生 <package-name>Config.cmake 設定檔
然而, 只用該指令產生的 config 檔會在 build-time 就決定所有的安裝路徑了

但無論是在 Windows 還是 Apple 系列平台, 我們安裝程式都是在 install stage 才安裝!

如果僅用該指令產生 config 檔的話, 就會綁死使用者能夠安裝我們專案的路徑

所以, 如果要避免這種情況, 讓我們的專案能夠 relocate, 可以裝在任意路徑, 我們就需要先自己寫一個 <package-name>Config.cmake.in
該檔案開頭必須包含 @PACKAGE_INIT@, 且內容的路徑都要使用 @PACKAGE_<path-var>@, PACKAGE_<path-var> 系列的變數會在 configure_package_config_file 被處理並轉換成相對於安裝路徑的字串

有了這個概念後, 來看看他的指令

configure_package_config_file(<input> <output>
  INSTALL_DESTINATION <path>
  [PATH_VARS <var1> <var2> ... <varN>]
  [NO_SET_AND_CHECK_MACRO]
  [NO_CHECK_REQUIRED_COMPONENTS_MACRO]
  [INSTALL_PREFIX <path>]
)
  • INSTALL_DESTINATION
    • 安裝的目的地路徑, 相對路徑的話是相對於 INSTALL_PREFIX
  • PATH_VARS
    • 會建出 PACKAGE_<path-var> 系列變數, 讓我們寫的 <package-name>Config.cmake.in 中的 PACKAGE_<path-var> install-time 的路徑能被 parse 成真正的安裝路徑
  • INSTALL_PREFIX
    • 安裝時的 base directory

預告

了解了複雜的安裝指令後, 下一篇我們就來實際操作看看吧!


上一篇
[Day 19] Install Basics
下一篇
[Day 21] Relocatable project
系列文
30 天 CMake 跨平台之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言