CMake

CMake とは、autoconf みたいに Makefile を作るツールです。Makefile 以外にも Visual Studio や Xcode の設定ファイルも作れるらしい。

## 基本的な文法

* CMake への入力
    * Directories:
        * CMakeLists.txt 親ディレクトリのここを最初に読む。
        * add_subdirectory() で子ディレクトリを追加できる。
    * Scripts: (script).cmake
        * cmake -P で実行する。
    * Modules: (module).cmake
        * include() で呼び出す。
* コマンドの文法
    * コマンド名は大文字小文字を区別しない。(こういうのやめて欲しい。。。)
    * add_executable(hello world.c) のように書く。
    * 引数は色々な方法で指定出できる。
        * Bracket Argument: [===[abcdef]===] の形式。
        * Quoted Argument: "abcdef" の形式。
        * Unquoted Argument: abcdef の形式
* 変数の文法
    * 変数は大文字小文字を区別する。
    * 代入:
        * 普通の変数: set(変数名 値)
        * 環境変数: set(ENV{変数名} 値)
    * 利用: Quoted Argument か Unquoted Argument の中で ${変数名} と書く。
        * if() の中だけ 変数名 のように書く。
        * 環境変数は if() の中でも $ENV{変数名} と書く。
* コメント
    * Bracket Comment: #[===[abcdef]===] と書く。カッコ閉じるまで。
    * Line Comment: # abcdef と書く。一行のみ。
    
## 主なコマンド

* add_executable(name source...)
    * 実行ファイル name をソースファイル source ...から作る
* add_library(name [STATIC | SHARED | MODULE] source ...)
    * ライブラリターゲット name を source ... から作る
    * 二番目の引数でライブラリの種類を選べる
        * STATIC: アーカイブファイルができる。
        * SHARED: 動的ライブラリができる。
        * MODULE: dlopen で動的に読むファイルができる。
        * 無指定の場合 BUILD_SHARED_LIB=ON なら SHARED、そうでなければ STATIC
* target_link_libraries(target item ...)
    * ターゲット target を item にリンクする。
    * target とは add_executable または add_library で作ったターゲット
    * item とは
        * ライブラリのターゲット名
        * ライブラリファイルのフルパス
        * ライブラリ名
        * リンクフラグ

## Package

CMake は find_package(パッケージ名) で Package (ヘッダファイルやライブラリなどの依存)のありかを探す。解決するには二つの方法がある。

* Module mode:
    * Find(Package).cmake を実行。
    * CMake 以外で作られたパッケージを探すのに使う。
* Config mode:
    * (Package)Config.cmake または (package)-config.cmake を実行。
    * CMake で作られたパッケージを探すのに使う。

Module mode を先に試して見つからなかったら Config mode を実行する。find_package によりパッケージの位置を示す変数がセットされる。変数の内容は cmake ファイルによってそれぞれだが、典型的には次のような変数名が使われる。

* (PACKAGE)_INCLUDE_DIRS
* (PACKAGE)_VERSION

これらのパッケージを探す位置がちょっとむずかしいがだいたい二通りあるらしい。

* `CMAKE_SYSTEM_PREFIX_PATH` で指定されたパスのリスト: システムにインストールされたパッケージを探す。`CMAKE_PREFIX_PATH` を使って追加する事も出来る。
* [CMake Package Registry](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Finding%20Packages.html#cmake-package-registry): Unix では `~/.cmake/packages/<パッケージ名>` に間接的に記述されている。CMakeLists.txt に `export` コマンドがあると、`make install` しなくても `make` だけでここに登録される。インストール不要なので開発時に便利。

詳しくは [Finding Packages — Mastering CMake](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Finding%20Packages.html) に書いてある。

## cmake コマンド利用時よく使う変数

* `CMAKE_INSTALL_PREFIX`:
    * `cmake -DCMAKE_INSTALL_PREFIX=$HOME/local` のようにすると標準以外の場所にインストールできる。
    * ここで指定したディレクトリは同時に find_package の検索パス (`CMAKE_SYSTEM_PREFIX_PATH`) にも追加されるので同じ場所にインストールした他のパッケージを参照できる。
* `CMAKE_PREFIX_PATH`:
    * `cmake -DCMAKE_PREFIX_PATH=$HOME/local` のようにすると標準以外の場所にインストールしたパッケージを find_package で探す事ができる。
    * CMAKE_SYSTEM_PREFIX_PATH に直接追加せずこの変数を使うべき。
* `CMAKE_VERBOSE_MAKEFILE`:
    * cmake は make 時に省略してログを出す。`cmake -DCMAKE_VERBOSE_MAKEFILE=1` のようにすると元の詳しいログが出る。
    * `VERBOSE=1 make` でも同じ。
* `CMAKE_POSITION_INDEPENDENT_CODE`:
    * Position Independent Code を生成するフラグ。
    * `... can not be used when making a shared object; recompile with -fPIC` というエラーが出たらライブラリにこれを付けてビルドすると `-fPIC` を付けてビルドしてくれる。
    * 例えば protobuf を自分でビルドする時など CMakeList.txt を編集したくない時は `cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON .` のようにする。

VSCode の CMake Tools でこれらの CMake 変数を設定するには以下のように settings.json に書く。

```json
{
    "cmake.configureSettings": {
        "CMAKE_PREFIX_PATH": "/root/local"
    }
}
```

## cmake よく使う コマンド


* `add_compile_options`:
    * 任意のコンパイルオプションを足す。
    * ~~`add_compile_options(-pedantic -Wall)` のようにすると警告レベルを変えられる。互換性が無いので使わないほうが良いらしい。~~
    * `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Wconversion")` 汚いがこちらの方が動いた。

## 参考

* [Mastering CMake — Mastering CMake](https://cmake.org/cmake/help/book/mastering-cmake/)
* [cmake-language(7) — CMake 3.24.2 Documentation](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html)
* [Using Dependencies Guide — CMake 3.24.2 Documentation](https://cmake.org/cmake/help/latest/guide/using-dependencies/)
* [Finding Packages — Mastering CMake](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Finding%20Packages.html)
* [CMAKE\_INSTALL\_PREFIX — CMake 3.24.2 Documentation](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
* [CMAKE\_PREFIX\_PATH — CMake 3.24.2 Documentation](https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html#variable:CMAKE_PREFIX_PATH)
* [Configuring CMake Tools — CMake Tools 1.4.0 documentation](https://vector-of-bool.github.io/docs/vscode-cmake-tools/settings.html#cmake-configuresettings)