CMakeの使い方〜覚書〜

cmakeが好きだが、使い方は忘れることが多い。「あれどうやって書いたっけ？」という情報を中心に覚書として残しておく。

# 基本形

## 実行ファイルの作成

### main.cppのみ

main.cppから実行ファイルを作成する。CMakeList.txtは、main.cppと同じ場所にひとつだけの構成。

```text:main.cppのみ
.
├── CMakeLists.txt
└── main.cpp
```

```cmake:CMakeList.txt
cmake_minimum_required(VERSION 3.5)
project (Project1)
add_executable(
        Target1
        main.cpp
)
```

### ソースファイルはsrcとincludeに分ける

CMakeList.txtは、ディレクトリのトップレベル階層にひとつ。ソースファイルは、CMakeList.txtとは別のディレクトリに配置。

```text:ソースファイルはsrcとincludeに分ける
.
├── CMakeLists.txt
├── include/
│   └── my_math.h
└── src/
    ├── main.cpp
    └── my_math.cpp
```

```cmake:CMakeList.txt
cmake_minimum_required(VERSION 3.5)
project(Project1)
set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
set(INC_DIR ${PROJECT_SOURCE_DIR}/include)
include_directories(
        ${INC_DIR}
)
add_executable(
        Target1
        ${SRC_DIR}/main.cpp
        ${SRC_DIR}/my_math.cpp
)
```

``PROJECT_SOURCE_DIR``は、``project()``コマンドでプロジェクト名を定義するとセットされる環境変数で、トップレベル・ディレクトリがセットされる。

## ユニットテストの実行

### googletestを使う

```text:./CMakeList.txt
.
├── CMakeLists.txt
├── src/
│   ├── CMakeLists.txt
│   ├── main.cpp
│   ├── my_math.cpp
│   └── my_math.h
└── test/
    ├── CMakeLists.txt
    └── test.cpp
```

```cmake:./CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(Project1)
enable_testing()
add_subdirectory(src)
add_subdirectory(test)
add_test(
        NAME MyTests
        COMMAND MyTest
)
```

```cmake:./src/CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
add_library(MyLib1 STATIC my_math.cpp)
add_executable(Target1 main.cpp)
target_link_libraries(Target1 MyLib1)
```

```cmake:./test/CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
find_package(PkgConfig)
pkg_search_module(GTEST gtest_main REQUIRED)
add_executable(MyTest test.cpp)
target_link_libraries(MyTest MyLib1 ${GTEST_LDFLAGS} gtest_main)
target_compile_options(MyTest PUBLIC ${GTEST_CFLAGS})
```

``REQUIRED``オプションは、エラーがあった時、メッセージを出力して処理を停止させる。

## 常套句を部品化する

T.B.D. 後日整理したうえで記載する

# コマンド

## cmake_minimum_required

[``cmake_minimum_required``](https://cmake.org/cmake/help/v3.5/command/cmake_minimum_required.html)は、CMakeLists.txtに記す文法に関するcmakeのバージョン。

```cmake:例
cmake_minimum_required(VERSION 3.5)
```

## project

[``project``](https://cmake.org/cmake/help/v3.5/command/project.html)は、cmakeプロジェクトの名称。ここ指定した名前は、``PROJECT_NAME``にセットされる。同様に、``PROJECT_SOURCE_DIR``や``PROJECT_BINARY_DIR``がセットされる。

```cmake:例
project (Project1)
```

## add_executable

[``add_executable``](https://cmake.org/cmake/help/v3.5/command/add_executable.html)は、ビルドターゲットとして実行ファイルを作成する。又、その際に必要なソースファイルを指定する。

```cmake:例
add_executable(Target1 main.c)
```

プロジェクトには、２つ以上のターゲットがあっても良い。

```cmake:例
add_executable(Target1 main.c)
add_executable(Target2 main.c)
set_target_properties(Target1 PROPERTIES COMPILE_DEFINITIONS "BUILDTYPE=1")
set_target_properties(Target2 PROPERTIES COMPILE_DEFINITIONS "BUILDTYPE=2")
```

## find_package

[``find_package``](https://cmake.org/cmake/help/v3.5/command/find_package.html)は、外部モジュールの設定をロードする。

```cmake:例
find_package(PkgConfig)
```

例えば、以下のようにX11モジュールをロードすると、``X11_LIBRARIES``のような環境変数と値が展開される。

```cmake
find_package(X11 REQUIRED)
```
使用できるパッケージは、以下のコマンドで参照できる。

```bash
$ cmake --help-module-list | grep -e '^Find'
```

### find_package(PkgConfig)

find_package(PkgConfig)を指定すると、``pkg_check_modules``を利用してpkg-configコマンドで参照できる情報をcmakeでも利用できるようになる。

例えば、``gtk+-3.0``に関する情報を得るには、以下のように指定する。第一引数は任意の名前。第二引数は、``pkg-config --list-all``として表示されるものから選択する。セットされる変数は、マニュアルの[FindPkgConfig](https://cmake.org/cmake/help/v3.0/module/FindPkgConfig.html)に説明がある。

```cmake:例
pkg_check_modules(GTK3 gtk+-3.0 REQUIRED)
```

この例では、``GTK3_INCLUDE_DIRS``や``GTK3_LIBRARIES``という変数に以下の例で示すコマンドの結果が得られる。

```bash:例
$ pkg-config --cflags gtk+-3.0
$ pkg-config --libs gtk+-3.0
```

``pkg_check_modules``で得られる変数は以下の通り。

|変数 |意味 |
|:--|:--|
|\<XPREFIX\>_FOUND   |モジュールが見つかると1  |
|\<XPREFIX\>_LIBRARIES  |-lで指定するライブラリ  |
|\<XPREFIX\>_LIBRARY\_DIRS  |-Lで指定するライブラリのフルパス  |
|\<XPREFIX\>_LDFLAGS  |リンカに与えるフラグすべて  |
|\<XPREFIX\>\_LDFLAGS_OTHER  |その他のリンカに与えるフラグ  |
|\<XPREFIX\>_INCLUDE\_DIRS  |-Iで与えるインクルードパス  |
|\<XPREFIX\>_CFLAGS  |コンパイルフラグすべて  |
|\<XPREFIX\>_CFLAGS\_OTHER  |その他のコンパイルフラグ  |

環境変数``PKG_CONFIG_PATH``は、cmakeの中でも指定できる。

```cmake
set(PKG_CONFIG_PATH ${PKG_CONFIG_PATH}　/path/to/pkgconfig)
```

## target_include_directories

[``target_include_directories``](https://cmake.org/cmake/help/v3.5/command/target_include_directories.html)は、ターゲットのビルドに必要なヘッダファイルのパスを追加する。

インクルードファイルの指定は、[``include_directories``](https://cmake.org/cmake/help/v3.5/command/include_directories.html)もある。target_xxx_yyy は指定した target にのみ影響する。xxx_yyy はその他の処理にも影響を与えるため target_xxx_yyy の使用が推奨されている。つまり、特に全体に共通する設定でない限り、[``include_directories``](https://cmake.org/cmake/help/v3.5/command/include_directories.html)でなく、[``target_include_directories``](https://cmake.org/cmake/help/v3.5/command/target_include_directories.html)を使用するのが良い。

## target_link_libraries

[``target_link_libraries``](https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html)は、ビルドターゲットに必要なライブラリを指定する。

リンクライブラリの指定は、[``link_libraries``](https://cmake.org/cmake/help/v3.5/command/link_libraries.html)もある。target_xxx_yyy は指定した target にのみ影響する。xxx_yyy はその他の処理にも影響を与えるため target_xxx_yyy の使用が推奨されている。つまり、特に全体に共通する設定でない限り、[``link_libraries``](https://cmake.org/cmake/help/v3.5/command/link_libraries.html)でなく、[``target_link_libraries``](https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html)を使用するのが良い。

```cmake:例
target_link_libraries(Target1 ${X11_LIBRARIES})
```

## set_target_properties

[``set_target_properties``](https://cmake.org/cmake/help/v3.5/command/set_target_properties.html)は、ビルドに影響を与えるのプロパティ（以降、ビルドプロパティと呼ぶ）に値をセットする。

```cmake:例
set_target_properties(create_window PROPERTIES COMPILE_FLAGS "-O0 -g")
```

ビルドプロパティは、マニュアルの[Properties on Targets](https://cmake.org/cmake/help/v3.5/manual/cmake-properties.7.html#target-properties)に詳しい説明がある。

ちなみに、例で示したデバッグオプションの指定は、以下のように設定したのと同じ意味になる。

```cmake:方法A
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
```

## cmake_print_properties

[``cmake_print_properties``](https://cmake.org/cmake/help/v3.5/module/CMakePrintHelpers.html?highlight=cmake_print_properties)は、プロパティをデバッグ表示する。

```cmake:例
include(CMakePrintHelpers)
cmake_print_properties(TARGETS ModuleB
        PROPERTIES
        INCLUDE_DIRECTORIES)
```

CMakePrintHelpersにあるのでモジュールのロード(``include(CMakePrintHelpers)``)が必要。

## enable_testing

[``enable_testing``](https://cmake.org/cmake/help/v3.5/command/enable_testing.html)は、指定されているCMakeList.txt以下のユニットテストを有効にする。このコマンドは、トップレベル・ディレクトリのCMakeList.txtに指定する必要がある。

## add_test

[``add_test``](https://cmake.org/cmake/help/v3.5/command/add_test.html#command:add_test)は、[ctest](https://cmake.org/cmake/help/v3.5/manual/ctest.1.html#manual:ctest(1))によるユニットテストを実行する。

```text:文法
add_test(NAME <name> COMMAND <command> [<arg>...]
         [CONFIGURATIONS <config>...]
         [WORKING_DIRECTORY <dir>])
```

NAMEで指定された名前のテストを追加する。その際のテスト実行ファイルは、COMMANDで指定する。故に、add_testコマンドでテストを追加する場合、別途、COMMANDで指定した実行ファイルが作られるようにCMakeList.txtに書かれていないといけない。

### add_subdirectory

[``add_subdirectory``](https://cmake.org/cmake/help/v3.5/command/add_subdirectory.html)は、ビルド対象の下層ディレクトリを追加する。そのディレクトリには、CMakeList.txtを置く必要がある。

### set

[``set``](https://cmake.org/cmake/help/v3.5/command/set.html)は、カレント変数に値をセットする。``unset``コマンドは逆にカレント変数を削除する。

# 環境変数

## PROJECT_NAME

プロジェクト名称。

## PROJECT_SOURCE_DIR, \<PROJECT-NAME\>\_SOURCE\_DIR

トップレベルのソースパス。

## PROJECT_BINARY_DIR, \<PROJECT-NAME\>\_BINARY\_DIR

ビルドディレクトリのフルパス。

# 参考

  * [CMake 3.5.2 Documentation ](https://cmake.org/cmake/help/v3.5/)
  * [cmake チュートリアルを読む前に](https://qiita.com/maueki/items/9cce88f6122e205754c5)
  * [CMakeを使ってみた (7) find_packageとpkg_check_modulesによるライブラリ探索](https://www.wagavulin.jp/entry/2017/02/20/082608)
  * [CMake入門](http://bkmts.xsrv.jp/cmake/)
  * [Google Test勉強録 (1) CMakeでのビルド](https://qiita.com/ktrmnm/items/667a7b7c93cd3fb78419)
  * [CMake: CTest](https://qiita.com/mrk_21/items/25ee7f00cebb9934b472)