cmake tutorial その7(最終回):EXPORT,find_package()など
最後まで終わった!よく頑張った!このチュートリアルのおかげでCMakeにしていた重大な勘違いに幾つも気付く事ができた。
俺がチュートリアル勉強しながら、テディーベアデバッグ的に適当に書きなぐったことなので、読んでもあまり参考にならないのでその点よろしく。
終盤のステップは説明を端折り過ぎてて何を書いてるのかよくわからない箇所が多かった。
ググッて得られる解説はabcのaやbが抜けていきなりcから解説されたものが多く、初心者にはきつかったからです。特にcmake.orgのチュートリアルはまさにその典型で、チュートリアルのStep 1からして長過ぎて、本当に何が必要なのかわかりにくい・・・orz
https://qiita.com/shohirose/items/45fb49c6b429e8b204ac
まじでこれ。
Export
自分で作ったCMakeプロジェクトを外部のプロジェクトが利用できるようにする
様々な形で他のプロジェクトから利用できるようにする
- ビルドディレクトリ
- インストール済み
- パッケージ
ライブラリ(
MathFunctions/CMakeLists.txt
)のinstallコマンドにEXPORTの追加
install(TARGETS MathFunctions tutorial_compiler_flags DESTINATION lib EXPORT MathFunctionsTargets) #👈これ! install(FILES MathFunctions.h DESTINATION include)
- これで
MathFunctionsTargets.cmake
が作られるっぽい。
install(EXPORT MathFunctionsTargets FILE MathFunctionsTargets.cmake DESTINATION lib/cmake/MathFunctions )
- before
├── bin │ └── Tutorial ├── include │ ├── MathFunctions.h │ └── TutorialConfig.h └── lib └── libMathFunctions.so
- after
├── bin │ └── Tutorial ├── include │ ├── MathFunctions.h │ └── TutorialConfig.h └── lib ├── cmake │ └── MathFunctions │ ├── MathFunctionsTargets-noconfig.cmake │ └── MathFunctionsTargets.cmake └── libMathFunctions.so
config.cmake.in
- なんのためのファイル?
@PACKAGE_INIT@ include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
- top-levelのCMakeに以下を加筆
install(EXPORT MathFunctionsTargets FILE MathFunctionsTargets.cmake DESTINATION lib/cmake/MathFunctions ) include(CMakePackageConfigHelpers) # generate the config file that is includes the exports configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake" INSTALL_DESTINATION "lib/cmake/example" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) # generate the version file for the config file write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake" VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}" COMPATIBILITY AnyNewerVersion ) # install the configuration file install(FILES ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake DESTINATION lib/cmake/MathFunctions )
- インストール後、パッケージング後に再利用可能なCMake構成(xxxxxConfig.cmakeのこと?)が生成できるらしい*1
export(EXPORT MathFunctionsTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake" )
- この辺は何を書いているのかよくわからない。
- 以下の記述をCMakeLists.txtに追記することでインストールせずに、ビルドだけで他プロジェクトからも利用できるようになる(ビルドディレクトリ経由で外部のプロジェクトが利用できるようにする)
export(EXPORT MathFunctionsTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake" )
- 上記記述の有無でビルド・インストールの違いを検証してみた
- 11_build:上記記述なし
- 11_install:11_buildのinstall先
- 11_build_without_install:上記記述あり
- 11_build:上記記述なし
$ tree 11 install 11 [error opening dir] install ├── bin │ └── Tutorial ├── include │ ├── MathFunctions.h │ └── TutorialConfig.h └── lib ├── cmake │ └── MathFunctions │ ├── MathFunctionsTargets-noconfig.cmake │ └── MathFunctionsTargets.cmake └── libMathFunctions.so $ diff -rq 11_build 11_build_wituhout_install/ | grep -E ".*Only in .*" Only in 11_build_wituhout_install/: MathFunctionsTargets.cmake
- MathFunctionsTargets.cmakeをexportしている方にのみ、ビルドディレクトリにMathFunctionsTargets.cmakeが存在していることがわかります。
Concumer
Consumer DirectoryにあるCMakeLists.txtを覗きます
function(find_external_dependency name) set(${name}_ROOT "" CACHE PATH "Root directory to find ${name}") mark_as_advanced(${name}_DIR) find_package(${name} PATHS ${${name}_ROOT} REQUIRED) endfunction() project(Consumer) find_external_dependency(MathFunctions)
- find_packageを関数でwrapしています
- wrap内で何やらキャッシュ関連の制御をしているようです。
set(${name}_ROOT "" CACHE PATH "Root directory to find ${name}")
- find_packageの検索先を指定する変数をキャッシュしている
mark_as_advanced(${name}_DIR)
- これもなにやらキャッシュ関係
- ↑の2行は消しても特に動きは変わらんかったので解説はなし。
find_package
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])
- unix環境なら標準で以下のパスに依存先の
<packageName>Config.cmake
を検索しにいく- 第一引数はtarget名ではなく、パッケージ名なので注意。
- あとcase sensitiveなのも注意。
- 第一引数はtarget名ではなく、パッケージ名なので注意。
<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/ <prefix>/(lib/<arch>|lib*|share)/<name>*/ <prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ <prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/ <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/ <prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/
CMAKE_INSTALL_PREFIX
やCMAKE_PREFIX_PATH
で<prefix>
に追加することもできる(検索先の追加)チュートリアルで何の説明もなしにいきなり応用的な使い方(Full Signature and Config Mode記載内容)が出てくるあたりCMakeは厳しいw
- 補足:Full Signature~のdocは、この先はプロジェクト管理者向けと書かれている
Project maintainers wishing to provide a package to be found by this command are encouraged to read on.
- tutorialに颯爽登場👉
`find_package(${name} PATHS ${${name}_ROOT} REQUIRED)
- 解説
- ドキュメントによると、PATHSを指定した場合は上記で説明したprefixに加え、PAHTで指定した箇所も検索されるらしい。
- が今回のPATHのオペランド(
${MathFunctions_ROOT}
)はmessageで標準出力に表示したが空だった。いみあるのか?この記述 - とりあえず分からないものを全部削除したが、自分の知っている範囲で想定内の動きをした。
- おそらくfind_packageの一般的な使い方で依存先を追加するだけだと以下のCMakeLists.txtで可能。
- 解説
cmake_minimum_required(VERSION 3.10) if(NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) endif() project(Consumer) # Wrapする必要はない find_package(MathFunctions REQUIRED) add_library(consumer consumer.cxx) target_link_libraries(consumer PUBLIC MathFunctions) # install the consumer library install(TARGETS consumer DESTINATION bin EXPORT ConsumerTargets) # install the configuration targets install(EXPORT ConsumerTargets FILE ConsumerTargets.cmake DESTINATION lib/cmake/Consumer ) include(CMakePackageConfigHelpers) # generate the config file that is includes the exports configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/ConsumerConfig.cmake" INSTALL_DESTINATION "lib/cmake/example" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) # install the configuration file install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ConsumerConfig.cmake DESTINATION lib/cmake/Consumer ) # generate the export targets for the build tree # needs to be after the install(TARGETS ) command export(EXPORT ConsumerTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/ConsumerTargets.cmake" )
- いきなり応用的なことをやって説明を放棄するのやめてくれ~
- 最終章はcpackの使い方なのでここで終了とします。
- 一応動かしたが、debug buildとrelease buildを同時に配布パッケージに含めるcpackの使い方がかかれていた。
わからんことメモ
cmake経由で下位ビルドシステムを実行するときのコマンドがよくわからない
- installは
cmake --install .
で良いと思ったら失敗する - 業務で使ってるのに近い形
cmake --build . --target install
だとうまく行った。- なぜこれでうまく行くのかは不明
- 下位ビルドシステムをそのまま叩くのもうまく行った
make install
- 弊社内だとビルドフェイズは下位のビルドシステムをそのまま叩くのが一般的らしいが。。。
memo
- 普通のdiffにはgit diff --name-only相当のオプションがない
- パイプ使ってこんな感じで対処。
$ diff -rqs 11_build 11_build_wituhout_install/ | grep -E ".*Only in .*"
- 小さいツールを組み合わせるunixらしい?やりかたなんだろうか。
- パイプ使ってこんな感じで対処。
おつかれ🍻
*1:At this point, we have generated a relocatable CMake Configuration for our project that can be used after the project has been installed or packaged.