直リンク系ライブラリの CMakeLists.txt の書き方調べた。
ポエム
CMakeLists.txt は便利なのだが、ちゃんと書き方を考えるほど切羽詰まった場面が自分にはなかった。今回は書いていて気になったのでちゃんと書く方法を調べたりしてみた。正直知見がなかったので何でググったっけを書いておくメモみたいなものである。
やりたいこと
- static に依存させるライブラリを作成したい
- 作成したライブラリは
ExternalProject
などで github 上から依存解決をしたい - なるべくならグローバルを汚染しないで依存解決をしたい
要は cmake でのライブラリの書き方がわかれば良い。ただ、静的ライブラリであれば add_subdirectory
すればよくね?という気持ちがないではない。今回は何が何でも静的リンクさせたかった、 cmake 経由でやれたことなかったからね。
やること
ライブラリ側
特殊なことは今回はしないのでこれだけ。target_sources
コマンドでコンパイル対象を指定し、 set_property
コマンドから PUBLIC_HEADER
プロパティを指定してインストール時にインストールすべきヘッダを指定して、 target_include_directories
で自身のヘッダファイルの場所を指定して、 install
コマンドでインストール先を指定している。あとはこの辺の単語でググれば最終的にはリファレンスにぶつかって解決できると思う。
- CMakeLists.txt
project(sample_lib VERSION 0.0.1 LANGUAGES CXX) add_library(sample_lib STATIC) target_sources(sample_lib PRIVATE # .cpp ファイルはここに書く ) set_property(TARGET sample_lib PROPERTY PUBLIC_HEADER # .hpp ファイルはここに書く ) target_include_directories(sample_lib INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> # ライブラリのビルド時に読み込むべき include ディレクトリ $<INSTALL_INTERFACE:include>) # ライブラリのインストール時(依存側で)読み込むべき include ディレクトリ install(TARGETS sample_lib EXPORT libsample_lib ARCHIVE DESTINATION lib LIBRARY DESTINATION lib PUBLIC_HEADER DESTINATION include)
利用する側
ExternalProject_add
で CMakeLists.txt のあるディレクトリやレポジトリを指定すると、 cmake
が走りよしなにビルドしたりインストールしてくれる。 INSTALL_DIR
などでインストール先指定しているけれど、特段指定しなければデフォルトのディレクトリに突っ込まれる。が、 Windows 環境でやっていたのでインストールステップ時に C:\Program Files\
下にライブラリをインストールしようとし、パーミッションが足りずに失敗する罠に引っかかったりするの利用側で指定してしまうのが、別段深い知見はないのだが、良いのではと思った。
- CMakeLists.txt
project(test_app) add_executable(test_app main.cpp) include(ExternalProject) ## Dependencies ExternalProject_add(sample_lib PREFIX ${CMAKE_CURRENT_BINARY_DIR}/sample_lib GIT_REPOSITORY https://path/to/sample_lib GIT_TAG master INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR} CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}" ) add_dependencies(test_app sample_lib) link_directories(test_app PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/lib) target_include_directories(test_app PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) target_link_libraries(test_app PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/lib/libsample_lib.a)
あとがき
別段ベストプラクティスではないと思うので動くもの書いたくらい。 lib
とか .a
とか cmake 側でちゃんと生成して作ったほうがいいし、そも add_subdirectory
と差があるんだっけとか、たぶん改善ポイントはすごく多い。
あと、今回作ってて依存側が依存先のことを超絶細かく知っていてもおかしくないという作りに本能が納得するまですごく時間がかかった。仕事では利用先のライブラリの名前とバージョン書いたら利用できることが多く、ここまでビルドやインストールの中身を意識したのが久々でたいへんつらかった。