フェルマータ

個人用のメモ。ソフトウェアの導入とかが多くなる予定。

直リンク系ライブラリの 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 と差があるんだっけとか、たぶん改善ポイントはすごく多い。 あと、今回作ってて依存側が依存先のことを超絶細かく知っていてもおかしくないという作りに本能が納得するまですごく時間がかかった。仕事では利用先のライブラリの名前とバージョン書いたら利用できることが多く、ここまでビルドやインストールの中身を意識したのが久々でたいへんつらかった。