CMakeの使い方（その２）

# はじめに

さて[その１](https://qiita.com/shohirose/items/45fb49c6b429e8b204ac)が意外と長くなってしまったので分割しました。
その２ではコマンドラインの場合とCMakeの場合で節を分けずに進めていきます。

## 関連記事

[CMakeの使い方（その１）](https://qiita.com/shohirose/items/45fb49c6b429e8b204ac)
[CMakeの使い方（その３）](https://qiita.com/shohirose/items/d2b9c595a37b27ece607)

# ステップ４：コンパイルオプションの設定

さて、ここではビルドするときのコンパイルオプションを見ていきたいと思います。オプションとしてよく使うものといえば、最適化オプション`O`やc++11/14/17の機能を有効にする`-std=c++11/14/17`と、`-Wall`等の警告オプションでしょうか。

- [options controlling C dialect](https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/C-Dialect-Options.html#C-Dialect-Options)
- [options to request or suppress warning](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options)


コマンドラインからビルドする場合、例えばこんな感じでオプションを追加しますよね。

```terminal
$ g++ -O2 -std=c++11 -Wall ... （その他色々付加）
```

これに対応するCMakeのコマンドは`target_compile_options`/`target_compile_features`/`target_compile_definitions`で、次のようにオプションを指定することができます。

```cmake
cmake_minimum_required(VERSION 3.13)
project(test_cmake CXX)

add_executable(a.out main.cpp)
# 最適化・警告等のオプション
target_compile_options(a.out PUBLIC -O2 -Wall)
# C++の標準規格の指定
target_compile_features(a.out PUBLIC cxx_std_17)
# マクロ
target_compile_definitions(a.out PUBLIC MY_ORIGINAL_MACRO_CONST=1)
```

`target_compile_features`に与えることができる引数は下記を参照してください。
[CMake Documentation: CMAKE_CXX_KNOWN_FEATURES](https://cmake.org/cmake/help/git-master/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES)

古いCMakeのバージョンでは`CMAKE_CXX_STANDARD`/`CMAKE_CXX_FLAGS`を使ってC++の標準規格のバージョンやオプション等を指定していましたが、現在は推奨されていません。

# ステップ５：ビルドタイプの指定

コマンドにオプションを加えるとビルドタイプを指定することができます。Unix系システムの場合は下記のコマンドとなります。

```terminal
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
$ cmake --build build
```

一方、Windowsの場合はデフォルトのジェネレーターがMSVCなので、下記のコマンドとなります。

```terminal
$ cmake -S . -B build
$ cmake --build build --config Release
```


# ステップ６：ジェネレーター式

コンパイラによってコンパイルオプションは異なります。例えば、警告レベルを指定する場合、gccでは`-Wall`などと指定しますが、Visual Studioでは`/W4`などと指定します。このように、コンパイラ・OS・ビルドタイプなどに応じてCMakeの関数に与える引数を変更するときに使われるのが、[ジェネレーター式（Generator Expressions）](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html)です。

```cmake
cmake_minimum_required(VERSION 3.13)
project(cmake_example CXX)

add_executable(a.out main.cpp)
target_compile_options(a.out PUBLIC
  # ビルドタイプによって変更する
  $<$<CONFIG:Release>: ...>          # Release
  $<$<CONFIG:Debug>: ...>            # Debug
  $<$<CONFIG:RelWithDebgInfo>: ...>  # RelWithDebInfo

  # OSに応じて変更する
  $<$<PLATFORM_ID:Darwin>: ...>   # Mac
  $<$<PLATFORM_ID:Linux>: ...>    # Linux
  $<$<PLATFORM_ID:Windows>: ...>  # Windows

  # コンパイラによって変更する
  $<$<CXX_COMPILER_ID:MSVC>: ...>      # MSVC
  $<$<CXX_COMPILER_ID:GNU>: ...>       # GCC
  $<$<CXX_COMPILER_ID:Clang>: ...>     # LLVM Clang
  $<$<CXX_COMPILER_ID:Intel>: ...>     # Intel classic
  $<$<CXX_COMPILER_ID:IntelLLVM>: ...> # Intel one-API
  )
target_compile_definitions(a.out PUBLIC
  $<$<NOT:$<CONFIG:Debug>>: ...>     # Debugビルド以外
  )
```


# ステップ７：ライブラリのリンク

次にライブラリをリンクすることを考えます。例えば、Boost Program Options Libraryをリンクするにはオプションに`-lboost_program_options`を加えます。

```terminal
g++ -o <target> <ソースファイル> -lboost_program_options <その他リンクオプション>
```

CMakeでは`target_link_libraries`を使ってターゲットに必要なライブラリをリンクさせることができます。

```cmake
target_link_libraries(<target> PUBLIC -lboost_program_options)
```

実際は、ライブラリを直接指定せずに、`find_package`を使ってライブラリの情報を取得し、`target_link_libraries`に渡してリンクすることが推奨されています。
- [CMake: How to Find Libraries](https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/How-To-Find-Libraries)
- [CMake Documentation: find_package](https://cmake.org/cmake/help/latest/command/find_package.html)

```cmake
cmake_minimum_required(VERSION 3.13)
project(test CXX)

# Boost Libraryを探す関数
find_package(Boost REQUIRED COMPONENTS program_options)

add_executable(mytest mytest.cpp)
target_link_libraries(mytest
  PRIVATE
    Boost::boost
    Boost::program_options
  )
```

`find_package`の引数をどのように指定するか、その結果として得られるターゲットは何か、などについては、たいていの場合それぞれのライブラリの公式ページに記載されています。または

```terminal
$ cmake --help-module-list
```

とすると、`find_package`で利用可能なライブラリ名が得られます。