CMakeでコンパイルオプションをtargetごとに設定する方法

CMakeでコンパイルオプションを足すとき、つい全体に add_compile_options() を書きたくなります。

小さいプロジェクトなら動きます。ただ、ライブラリ、アプリ、テストが増えてくると、どのターゲットにどのオプションが効いているのか分かりづらくなります。

新しく書くなら、まず target_compile_options() に寄せるのが扱いやすいです。

https://cmake.org/cmake/help/latest/command/target_compile_options.html

基本形

add_library(my_lib
  src/lib.cpp
)

target_compile_options(my_lib
  PRIVATE
    -Wall
    -Wextra
)

PRIVATE にすると、my_lib 自身のコンパイルにだけ効きます。

利用側にも伝える必要があるオプションは多くありません。警告オプションなら、まず PRIVATE でよいことが多いです。

PUBLICにする場面

ヘッダーの都合で、利用側にも同じコンパイル定義やオプションが必要な場合は PUBLIC を考えます。

ただし、警告オプションを PUBLIC にすると、利用側のターゲットにも伝播します。

target_compile_options(my_lib
  PUBLIC
    -Wall
)

これは便利な反面、依存先の都合でアプリ側の警告設定まで変わることになります。基本は控えめに使います。

コンパイラごとに分ける

GCC/ClangとMSVCでオプションは違います。

target_compile_options(my_app
  PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
)

このような条件付きの書き方には generator expressions を使います。

https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html

最初は読みにくく感じますが、CMakeLists.txtをOSやコンパイラごとに分岐させるよりは管理しやすいです。

add_compile_optionsとの違い

add_compile_options() は現在のディレクトリ以下に効きます。

https://cmake.org/cmake/help/latest/command/add_compile_options.html

add_compile_options(-Wall -Wextra)

簡単ですが、影響範囲が広くなりがちです。

ターゲットごとにオプションを変えたいなら、target_compile_options() の方が追いやすくなります。

まとめ

CMakeでコンパイルオプションを設定するなら、まずターゲット単位で考えます。

  • 警告オプションは target_compile_options(... PRIVATE ...)
  • 利用側にも必要なものだけ PUBLIC
  • コンパイラ差分は generator expressions で分ける
  • 全体に効かせる add_compile_options() は影響範囲に注意する

srcapptests のようにターゲットが分かれているなら、オプションもターゲットごとに持たせる方が後から読みやすいです。

関連記事

参考