C/C++プロジェクトをCMakeでビルドする

# CMake

CMakeは、C/C++プロジェクト向け、マルチプラットフォームのビルドツールです。
僕が初めてプログラミングに触りC/C++を勉強していた当時、難しそうという雰囲気から避けてしまっていたツールでもありました。しかし、現在はPythonライブラリ開発で高速化のためにpybindを用いて処理をC++化したり、大学でのロボコンではOpenCV、ROSなどを用いた大きめのプロジェクト開発をしたりするため、CMakeをガッツリ利用しています。

CMakeは10年以上前から開発されているツールですが、現在も、これから先も使い続けられるツールだと思います。今回はQiitaの「[Qiita 10周年記念イベント - 10年後のために今勉強しておきたい技術](https://qiita.com/official-events/12fc7bacec894d33a981)」というテーマで、難しそうと思っていた過去の自分にも分かるように、そして今からCMakeを勉強しようと思っている人の資料となるように、という思いを込めて投稿しようと思います。

プロジェクトにCMakeを導入する時には、ガイドラインをまとめてくれている記事に目を通した上で、レファレンスを適宜参照することを推奨する。

- [CMake Reference Documentation](https://cmake.org/cmake/help/latest/index.html)
    - 利用しようとしているコマンドはそのCMakeのバージョンで利用できるのかはドキュメントとよく照らし合わせるようにしたほうが良い。新しいバージョンでは利用しやすいように機能が増えていることもあり、それはドキュメントを読めば書いてあり、古いバージョンを利用する場合にはどうするかも書いてある[^1]。
- [CMakeスクリプトを作成する際のガイドライン - Qiita](https://qiita.com/shohirose/items/5b406f060cd5557814e9)
    - 参考文献も合わせて、眺めておいて、何が良くないとされているのかは知っておくと良い

# 環境

ちなみに、CMake 3.13.0のリリースは2018年11月20日。

```
$ cmake --version
cmake version 3.13.4
```

# 対象とするプロジェクトの構造

今回は、ライブラリをビルドし、ヘッダファイルと共に適切な場所に配置するようなプロジェクトを作成する。
また、このライブラリをリンクさせるソースコードのサンプルも任意で生成出来るようにする。

ここでは以下のような`mylib`ライブラリのプロジェクト構造を作成したとして進める。

- include : ライブラリのヘッダファイル
    - `#include "mylib/mylib.h"`としてインクルードすることを想定している
- lib : ライブラリのヘッダファイルに対応するソースファイル
    - `include/mylib/mylib.h`と`lib/mylib/mylib.c`が対応する
- examples : `mylib`ライブラリを利用したソースコードのサンプル

```
.
├── CMakeLists.txt
├── include
│  └── mylib
│     └── mylib.h
├── lib
│  └── mylib
│     ├── CMakeLists.txt
│     └── mylib.c
└── examples
   ├── CMakeLists.txt
   └── main.c
```

# 基本的なビルド方法

基本的なビルド方法としては、以下のような流れを想定している。
後ほど、[#高度なビルド方法](#高度なビルド方法)で、ビルドする際に利用できる重要なオプションについて触れる。

```sh
$ mkdir build
$ cd build
$ cmake ..　
$ make #ライブラリのビルド
$ make examples #ライブラリを利用したサンプルをビルドしてバイナリを生成する
```

ライブラリをインストールする際には、`CMAKE_INSTALL_PREFIX`を定義する。詳細は[# ビルドしたライブラリのインストール方法](#ビルドしたライブラリのインストール方法)で書いている。

```sh
$ cmake .. -DCMAKE_INSTALL_PREFIX='$HOME/.local'
$ make install
```

オブジェクトファイル`*.o`やライブラリ、バイナリなどの成果物を削除する場合は`clean`ターゲットが用意されている。

```sh
$ make clean
```

ビルド環境を作成しなおす場合、大抵の場合は`cmake ...`のコマンドで作り直しが出来る。
しかし、オプションをつけている場合、`cmake ...`のコマンドでは消えない場合があるので、何か変だと思った場合は、一度`build`フォルダを削除してやり直すことも良い。

```sh
$ rm -rf build
$ mkdir build
...
```

# CMakeのデバッグ方法

手順を追っている時に、詰まった時の助けになるであろうデバッグ方法をいくつか紹介する。

## CMakeがキャッシュしている変数の値を表示する

```sh
$ cmake .. -LAH
```

キャッシュしている変数を`-L`、ADVANCEDに設定された変数も表示するときは`-A`、変数名についている説明を表示するなら`-H`をつける

[cmake(1) - CMake Documentation #Generate a Project Buildsystem](https://cmake.org/cmake/help/latest/manual/cmake.1.html#generate-a-project-buildsystem) の`-L[A][H]`の項目を参照。

## traceする

```sh
$ cmake .. --trace-source=CMakeLists.txt
```

CMakeLists.txtに記述された内容のどこを実行したのかをtraceできる。

```sh
$ cmake .. --trace
```

CMakeが自動的に生成して読み込んで実行したものも含めてtraceする。

また、それぞれで、変数が展開された状態でログ出力をしたい場合は`--trace-expand`が利用できる。

```sh
$ cmake .. --trace-source=CMakeLists.txt --trace-expand
$ cmake .. --trace --trace-expand
```

[cmake(1) - CMake Documentation #Generate a Project Buildsystem](https://cmake.org/cmake/help/latest/manual/cmake.1.html#generate-a-project-buildsystem) の`--trace`の項目辺りを参照。

## makeした時のコンパイルされるコマンドを出力する

```sh
$ make VERBOSE=1 
```

`gcc -I./include -o mylib.c.o -c mylib.c`みたいなのを眺めたかったら`VERBOSE=1`をつける

# プロジェクトルートのCMakeLists.txt

```cmake
# 動作確認できたCMakeのバージョン
cmake_minimum_required(VERSION 3.13)

# プロジェクトの情報
project(mylib
    VERSION 1.0
    DESCRIPTION "mylib project"
    LANGUAGES C
)

# in-source ビルドガード
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
    message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
endif()

# 以下のフォルダにあるCMakeLists.txtも読み込んでビルドターゲットを生成する
add_subdirectory(lib/mylib)
add_subdirectory(examples EXCLUDE_FROM_ALL)
```

基本的にはこんな感じ。

## cmakeのバージョン

```cmake
cmake_minimum_required(VERSION 3.13)
```

まずは、CMakeのバージョンを設定しておく。ここには、**動作確認出来ている最も低いバージョン**を記載しておくべきで、動作を保証するための何よりも一番最初に設定しておくポリシーでもある。ここでは、今回利用したCMakeのバージョンが3.13だったので、このようにしている。

## プロジェクトの情報

```cmake
project(mylib
    VERSION 1.0
    DESCRIPTION "mylib project"
    LANGUAGES C
)
```

プロジェクトの情報をprojectに記載しておく。これによって、`PROJECT_NAME`など、いくつかの変数名がセットされる。
[project - CMake Documentation](https://cmake.org/cmake/help/latest/command/project.html)

## in-sourceビルドガード

```cmake
# guard against in-source builds
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
    message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
endif()
```

この部分を説明する前に、まず、ビルドの方法には、in-sourceと呼ばれる方法とout-of-sourceと呼ばれる方法の2種類があるという話をしておく。
cmakeを使った方法として、以下のように`build`フォルダを作成してからビルドする方法をよく見かけると思う。これはout-of-sourceと呼ばれるビルド方法で、**out-of-sourceビルドをすることを強く推奨する**。

```sh
$ mkdir build
$ cd build
$ cmake ..
$ make
```

in-sourceの問題点は[CMake : out-of-sourceビルドで幸せになる - Qiita](https://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca)から引用すると、以下の通り。out-of-sourceを使った時はこれらの問題を解決でき、その話はQiitaの記事を参照してほしい。

>\# in-sourceビルド (`cmake .`) の何が問題なのか？
>まずは、in-source ビルドのどこが問題なのか、確認します。
>
>- git でソース管理する際に、ビルド成果物や cmakeコマンドが生成する各種ファイルによってリポジトリが汚れしまい `git status`した際に、本来追加すべきファイルを見落とす可能性がある
>- cmakeが生成したファイルをまとめて消したいときにディレクトリごとに `CMakeCache.txt` や `CMakeFiles` ディレクトリを消すのが苦痛
>- Debugビルド、Releaseビルドを分けたい時に、ソースツリーを別々に用意する必要がある
>https://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca#in-sourceビルド-cmake--の何が問題なのか

さて、本題に戻るが、ここではin-sourceビルドガードを記述していた。
前述のような問題で開発者を悩ませないようにするための対策で、これは[C++向けライブラリEigenのCMakeLists.txtで利用されていたin-sourceビルドガード](https://github.com/eigenteam/eigen-git-mirror/blob/36b95962756c1fce8e29b1f8bc45967f30773c00/CMakeLists.txt#L5-L9)をそのまま利用している。

## subdirectoryを追加する

```cmake
add_subdirectory(lib/mylib)
add_subdirectory(examples EXCLUDE_FROM_ALL)
```

プロジェクトルートに配置したCMakeLists.txt以外にも、`lib/mylib`以下や`examples`以下にもCMakeLists.txtを配置している。
このように、CMakeLists.txtを配置したディレクトリを`add_subdirectory`に追加することで、それらをビルドの対象として読み込む事ができ、CMakeLists.txtを分割することが出来るものだと思えば良い。

`add_subdirectory(examples EXCLUDE_FROM_ALL)`のように、`EXCLUDE_FROM_ALL`という引数が与える事ができる。
これの効果を理解するために、CMakeを用いてビルドする手順をもう一度見てみる。

```sh
$ mkdir build
$ cd build
$ cmake ..
$ make
```

この`make`を実行する際に、ビルドターゲットを指定することが出来るのだが、ターゲットを指定しなかった場合は`DEFAULT_TARGET`として指定されているターゲットが利用されることになる。
通常は、CMakeによって用意される`all`が`DEFAULT_TARGET`としてセットされている[^2]。

CMakeでは、CMakeLists.txtにライブラリやバイナリの生成ルールを記述した場合、通常、それらは`all`ターゲットに追加されることになる。`all`ターゲットに追加したくない場合は、`EXCLUDE_FROM_ALL`を指定することで出来る。
今回のように、`add_subdirectory`に`EXCLUDE_FROM_ALL`を与えると、そのディレクトリ内で記述されている全ての生成ルールが`all`ターゲットから除外される。もっと細かく、ライブラリやバイナリ単位でも可能である。

`examples`を`all`ターゲットから除外した理由についても触れておくと、今回の`mylib`プロジェクトはライブラリを提供しているものを想定している。何らかのCLIツールのバイナリを生成するプロジェクトではない。
なので、ライブラリだけ生成できればOK。
ライブラリを利用したサンプルとして`examples`のバイナリを生成するルールを用意しているけど、ライブラリを使いたいだけならバイナリを生成する必要は無く、ユーザが必要に応じて生成出来るようにしたい、という理由になる。[^3]

では、次はそれぞれのディレクトリに配置されているCMakeLists.txtを見ていく。

# lib/mylib/CMakeLists.txt

`lib/mylib`ディレクトリには、ライブラリのヘッダファイルに対応するソースファイルが配置されている。
ここに配置されるCMakeLists.txtでは、ライブラリの生成ルール、インストール方法を記述している。

```cmake
# mylibを共有ライブラリとして生成するためのオプションの定義
option(MYLIB_BUILD_SHARED_LIBS "build mylib as a shared library" OFF)

# オプション定義によって生成するライブラリの種類(SHARED/STATIC)を切り替える部分
if (MYLIB_BUILD_SHARED_LIBS)
    add_library(mylib SHARED)
else()
    add_library(mylib STATIC)
endif()

# mylibを生成するために必要なソースファイル
target_sources(mylib
    PRIVATE # mylib.cはmylibライブラリを生成するためだけに必要なのでPRIVATE
    mylib.c
)

# mylibを生成するために必要なヘッダファイルが配置されているディレクトリを指定する
target_include_directories(mylib
    # mylib.hなどはmylibライブラリを生成するのに加えて、
    # mylibライブラリを利用する他のバイナリなどでも利用するのでPUBLIC
    PUBLIC 
    ${PROJECT_SOURCE_DIR}/include
)

# GNUのディレクトリ構造で定義されたCMAKE_INSTALL_<dir>の変数を読み込む
include(GNUInstallDirs)
# install mylib library
install(TARGETS mylib
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# install headers
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    FILES_MATCHING PATTERN "*.h"
)
```

## mylibを共有ライブラリとして生成するためのオプションの定義

```cmake
option(MYLIB_BUILD_SHARED_LIBS "build mylib as a shared library" OFF)
```

まず、前提として、ライブラリを静的ライブラリで生成するのか、共有ライブラリで生成するのかはユーザが指定出来るようにするべきである[^17]。そして、それを指定するためのオプションとして`BUILD_SHARED_LIBS`が既に用意されており、それが`ON`か`OFF`かを判断して切り替えてくれている。
しかし、これはプロジェクト全体に適用されてしまうため、通常はライブラリごとにオプションを用意する。

ここでは、`mylib`ライブラリに対して、共有ライブラリとして生成するためのオプションとして、`MYLIB_BUILD_SHARED_LIBS`定義し、オプションの説明と、デフォルト値を与えておく[^4]。

このオプションの値を変更したい時は以下のように`-D`オプションを利用する。

```sh
$ cmake .. -DMYLIB_BUILD_SHARED_LIBS=ON
```

## ライブラリの生成ルール

```cmake
if (MYLIB_BUILD_SHARED_LIBS)
    add_library(mylib SHARED)
else()
    add_library(mylib STATIC)
endif()
```

前述のオプション定義によって生成するライブラリの種類を分岐させると同時に、ライブラリの生成ルールを記述している。
ライブラリをビルドするには`add_library`を用い、引数にはライブラリ名と、そのライブラリの種類を指定する。
`SHARED`を指定すると共有ライブラリとして`libmylib.so`、`STATIC`を指定すると静的ライブラリとして`libmylib.a`が生成される。
[add_library #normal-libraries - CMake Documentation](https://cmake.org/cmake/help/latest/command/add_library.html#normal-libraries)

## mylibを生成するために必要なソースファイル

```cmake
target_sources(mylib
    PRIVATE
    mylib.c
)
```

ライブラリの生成に必要なソースファイルの定義は`add_library`でも出来るが、`target_sources`を利用して記述することも出来る[^5]。

`target_sources`にリストアップしたソースファイルやヘッダファイルには、`PRIVATE`、`PUBLIC`、`INTERFACE`を指定出来る。それぞれの意味を完結に表した表を[CMakeスクリプトを作成する際のガイドライン#PRIVATE/PUBLIC/INTERFACEを適切に使う](https://qiita.com/shohirose/items/5b406f060cd5557814e9#privatepublicinterfaceを適切に使う)から引用したものが以下の表である。


|キーワード | ターゲットが必要とする | ターゲットに依存するターゲットが必要とする |
| -------- | -------- | -------- |
| PRIVATE | :o: | :x: |
| PUBLIC | :o: | :o: |
| INTERFACE | :x: | :o: |

`mylib.c`は`mylib`ライブラリの生成に必要とする。
しかし、`mylib`をリンクして利用するターゲットでは成果物である`libmylib.a`やヘッダファイルが必要となるのであって、`mylib.c`自体は必要ではない。なのでここでは`PRIVATE`が適切である。

今回、`mylib`ライブラリのビルドに必要なソースファイルは`mylib.c`だけであったが、実際のライブラリでは多くのソースファイルに依存することになる。そういった場面では、`*.c`でパターンにマッチしたファイルを自動で収集させたい、という需要が出てくると思う。
自動で収集する機能は、`file(GLOB ...)`[^6]や`aux_source_directory`[^7]が利用できる。

しかし、それらのドキュメントに記載されているように、自動で収集する機能を利用することは**推奨していない**。
その内容をここでも記載しておくと、その理由は、これを利用した場合、**CMakeは新しいソースファイルがいつ追加されたかを認識することが出来ない**からである。
本来、新しいファイルが追加された場合には`CMakeLists.txt`が編集されるため、CMakeがビルド環境を再生成してくれる。しかし、自動で収集させた場合、新しいファイルを追加しても`CMakeLists.txt`を編集しないため、CMakeはビルド環境を再生成するタイミングを検出することが出来なくなる。
結果、新しいファイルを追加した場合は**手作業で**ビルド環境を再生成させることになる。ということらしい[^8]。

## mylibを生成するために必要なヘッダファイルが配置されているディレクトリを指定する

```cmake
target_include_directories(mylib
    PUBLIC 
    ${PROJECT_SOURCE_DIR}/include
)
```

`mylib.h`などはmylibライブラリを生成するのに加えて、`mylib`ライブラリをリンクする他のバイナリなどでも利用するので`PUBLIC`が適切。
先程、ファイルを自動で収集するのは良くないといいつつ、ここではディレクトリを指定してるのは良いのか？と思うかもしれない。これは各ソースファイル内で正しくincludeできるようにするための記述であり、ヘッダファイルの依存関係の解決をしているわけではない（たぶん。あと、依存関係は別でちゃんと解決されている）[^9]。
これは、`gcc -I./include -c mylib.c -o mylib.o`とするように、ソースファイル内でincludeしているファイルをどこから探すか？という情報を与える`-I`オプションに対応している。

ここまで記述すれば、ライブラリのビルドが出来るようになっていると思う。[#基本的なビルド方法](#基本的なビルド方法)の手順を利用して、試してみてもいいかも。

## GNU Coding Standardsとして定義されているインストールディレクトリを利用する

```cmake
include(GNUInstallDirs)
```

ここからは、インストール方法の記述になる。まずここでは、GNU Coding Standardsとして定義されているインストールディレクトリを`CMAKE_INSTALL_<dir>`の変数で利用できるように読み込んでいる。今回利用する変数は以下の3つで、具体的には以下のような値が環境に合わせてセットされる。

- `CMAKE_INSTALL_LIBDIR` = `lib` or `lib64` or `lib/<multiarch-tuple>` on Debian
- `CMAKE_INSTALL_INCLUDEDIR` = `include`
- `CMAKE_INSTALL_PREFIX` = `/usr/local` on UNIX or `c:/Program Files/${PROJECT_NAME}` on Windows.

[GNUInstallDirs - CMake Documentation](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html)
[CMAKE_INSTALL_PREFIX - CMake Documentation](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)

## ビルドしたライブラリのインストール方法

```cmake
install(TARGETS mylib
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
```

ビルドしたライブラリのインストール方法を記述している。インストールするターゲットは`mylib`をビルドして出来た成果物であり、その成果物のタイプごとにインストール方法を記述できる。
今回の成果物としては、静的ライブラリ(`ARCHIVE`)か共有ライブラリ(`LIBRARY`)の場合がある。それらをインストールする作業としては、ファイルを適切な場所に配置ができれば良いので、`DESTINATION`だけ指定しておけば良い。
配置場所として`DESTINATION`に`${CMAKE_INSTALL_LIBDIR}`を指定すると、`${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}`に配置されることになる。
変数を展開してみると、`/usr/local/lib`となるので、ライブラリは`/usr/local/lib/libmylib.a`と配置される。

`/usr/local/`に配置するにはroot権限が必要になるので[^10]、その代わりとして`$HOME/.local/`がよく利用される。
そこで、`${CMAKE_INSTALL_PREFIX}`を上書きしてビルド環境を作成した上で`make install`すると良い。

```sh
$ cmake .. -DCMAKE_INSTALL_PREFIX='$HOME/.local'
$ make install
```

[install - CMake Documentation](https://cmake.org/cmake/help/latest/command/install.html)

## ヘッダファイルのインストール

```cmake
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    FILES_MATCHING PATTERN "*.h"
)
```

今回は、`include`内の全てのヘッダファイルをインストールする。この場合は、`install(DIRECTORY ...)`が利用できる。
ディレクトリは再帰的にファイルが検索される。
配置場所は、ライブラリの時同様に`${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}`に配置されることになるので、`/usr/local/include/mylib/mylib.h`のようにヘッダが配置される。
また、`FILES_MATCHING PATTERN "*.h"`で、ヘッダファイルだけ配置するようにしている。

`include`の中の一部だけをインストールしたい場合、`PUBLIC_HEADER`にヘッダ一覧を指定しておいて、前述の`install(TARGET mylib ...)`でインストールする方法が使えると思う[^11]。

ここまでの記述で、ライブラリとヘッダファイルのインストールが出来るようになった。

# examples/CMakeLists.txt

```cmake
add_custom_target(examples)
add_dependencies(examples
    main
)

add_executable(main main.c)
target_link_libraries(main
    mylib
)
```

`mylib`ライブラリを利用したサンプルをビルドするルールを記述している。

## examplesターゲットを作成する

```cmake
add_custom_target(examples)
```

`make`コマンドでは、ターゲットを引数として与えることができた。
`make examples`とすれば、`examples`をターゲットとして指定したことになり、このコマンドで`mylib`ライブラリを利用したサンプルを**全て**ビルドするものを用意したい。
`examples`ターゲットのような独自のターゲットは`add_custom_target`を用いて作成できる。この時点ではまだ何も生成されないので、以下の`add_dependencies()`で定義する。

## examplesターゲットで生成したいものを定義する

```cmake
add_custom_target(examples)
add_dependencies(examples
    main
)
```

今回は、サンプルとして`main`を用意しようとしていて、これを`examples`ターゲットの依存関係として`add_dependencies`を利用して定義する。
これによって、`examples`ターゲットを実行するためには`main`を生成する必要がある→`main`が生成されていなければ生成する、という動作が実現できる。
今回は`main`しか用意していないが、サンプルとして複数用意しており、それらも`examples`ターゲットで生成されてほしい場合は`add_dependencies`の`main`に続けて記述していけば良い。

## mainのビルド方法を定義する

```cmake
add_executable(main main.c)
```

ライブラリの時は`add_library`であったが、実行ファイルを生成する場合は`add_executable`を指定する[^12]。
1つのソースファイルから1つの実行ファイルを生成する場合は、`target_source`に分離させず、`add_executable`にまとめて書いてしまう方が冗長にならなくて良いと思う。
[add_executable - CMake Documentation](https://cmake.org/cmake/help/latest/command/add_executable.html)

## mainにmylibライブラリをリンクする

```cmake
target_link_libraries(main
    mylib
)
```

`main.c`は`mylib.h`をincludeしていたので、実行ファイルを生成する際に`mylib`ライブラリをリンクする必要がある。
そのときには`target_link_libraries`を利用する。
これによって、`main`を生成する時に、`mylib`ライブラリがまだビルドされていない場合は先に`mylib`ライブラリをビルドするように、よしなにされる。
[target_link_libraries - CMake Documentation](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)

これで、`make examples`でサンプルをビルドすることが出来るようになった。
[#基本的なビルド方法](#基本的なビルド方法)に帰って、一通りの流れを試してみてほしい。

# 高度なビルド方法

## コンパイラを指定する

MacではXCodeが持っているコンパイラや`gcc`だと思っている`clang`がいたりするため、コンパイラを上手く指定したい場面がある。
しかし、`CMakeLists.txt`内でコンパイラを直接指定することは良くない。なぜなら、その部分が環境依存になってしまうため、異なる環境の差異を吸収出来なくなてしまうからである。
これはCMakeによって解決させる、もしくは、以下のようにCMakeを実行する際に、ユーザが適切にコンパイラを指定するべきである。

```sh
cmake .. -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ 
```
[How can I make CMake use GCC instead of Clang on Mac OS X? - stack overflow](https://stackoverflow.com/questions/24380456/how-can-i-make-cmake-use-gcc-instead-of-clang-on-mac-os-x)

## ビルドタイプにDebug,Releaseなどを指定する

gdbデバッグを行う目的で`-g`オプションをつけてビルドしたいときには`Debug`でのビルドを行う。一方、`Release`は最適化した状態でビルドしたい時に用いる。
この`Debug`、`Release`を`CMAKE_BUILD_TYPE`に指定する。

```sh
# デバッグするために、-gオプションをつける
$ cmake .. -DCMAKE_BUILD_TYPE=Debug

# 最適化をするために、-O3オプションをつける
$ cmake .. -DCMAKE_BUILD_TYPE=Release
```

`Debug`や`Release`は、**大文字から始まるCamel caseを利用する**ようにした方が良い。`CMAKE_BUILD_TYPE`自体は大文字小文字でも関係なく正しく切り替わる。
しかし、CMakeLists.txtの記述によっては、`${CMAKE_BUILD_TYPE}`にセットされている値が`Debug`と一致するか、のように、大文字小文字を区別して利用している場合がある[^13]。

[CMAKE_BUILD_TYPEのUPPER CASEにご用心 - Qiita](https://qiita.com/KRiver1/items/4b7ad90168dfb4aedde6)

## 新しいバージョンのCMakeを使って`cmake --install`を使う

CMake 3.13では`${CMAKE_INSTALL_PREFIX}`を上書きしてビルド環境を作成した上で`make install`する必要があった。

```sh
$ cmake .. -DCMAKE_INSTALL_PREFIX='$HOME/.local'
$ make install
```

しかし、より新しいバージョン[^14]のCMakeでは、この2行を以下の1行で実行出来るようになっている。

```sh
$ cmake --install . --prefix="$HOME/.local"
```
[Step 4: Installing and Testing - CMake Documentation](https://cmake.org/cmake/help/v3.21/guide/tutorial/Installing%20and%20Testing.html)

# その他
## mylibを別のプロジェクトから利用したい

```cmake
# Build mylib
include(FetchContent)
FetchContent_Declare(
    mylib
    GIT_REPOSITORY https://github.com/hoge/mylib.git
    GIT_TAG        origin/main
)

FetchContent_GetProperties(mylib)
if(NOT mylib_POPULATED)
    FetchContent_Populate(mylib)
    add_subdirectory(${mylib_SOURCE_DIR} ${mylib_BINARY_DIR})
endif()

add_subdirectory(src)
```

例えば、GitHubなどでmylibのプロジェクトが公開されているのであれば、CMakeから`FetchContent`を利用して取得する事ができる。

## FetchContentを利用できるようにする

```cmake
include(FetchContent)
```

includeする。

## 取得したいリポジトリの情報

```cmake
FetchContent_Declare(
    mylib
    GIT_REPOSITORY https://github.com/hoge/mylib.git
    GIT_TAG        origin/main
)
```

ここに取得したいGitHubリポジトリの情報を記述する。ここでは`GIT_TAG`にブランチ名を指定しているが、コミットハッシュや`v1.0`などのタグも利用できるようになっている。

## 2重で読み込んでしまうのを防ぐ

```cmake
FetchContent_GetProperties(mylib)
if(NOT mylib_POPULATED)
    FetchContent_Populate(mylib)
    add_subdirectory(${mylib_SOURCE_DIR} ${mylib_BINARY_DIR})
endif()
```

`FetchContent_GetProperties(<name>)`で、`<name>_POPULATED`、`<name>_SOURCE_DIR`や`<name>_BINARY_DIR`の3つの変数を読み込んでいる。
これらの変数は、`FetchContent_Populate()`によって定義されるため、初回の読み込みでは`if(NOT mylib_POPULATED)`の条件がtrueになるが、以降はfalseとなるので、2重で読み込んでしまうのを防ぐ事ができる。

注意することとしては、`FetchContent_Populate()`に渡した名前は**lower caseに変更され**、`mylib_POPULATED`、`mylib_SOURCE_DIR`や`mylib_BINARY_DIR`のようにprefixとして利用されることである[^15]。
[FetchContent #command:fetchcontent_populate - CMake Documentation](https://cmake.org/cmake/help/latest/module/FetchContent.html#command:fetchcontent_populate)

ちなみに…、新しいCMakeのバージョンなら、以下の一行で出来るっぽい。

```cmake
FetchContent_MakeAvailable(mylib)
```
[FetchContent #overview - CMake Documentation](https://cmake.org/cmake/help/latest/module/FetchContent.html#overview)

## threadライブラリを利用する場合

```cmake
# pthreadを使う
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

add_executable(main main.c)
target_link_libraries(main
    Threads::Threads
)
```

threadライブラリをリンクして`main`をコンパイルしたい場合は、上記のようにすればいい。
こういった有名なライブラリに関しては、CMakeであれば`find_package`を用いて簡単に読み込むことが出来るようになっている。
threadライブラリが見つかった場合はターゲットとして`Threads::Threads`が読み込まれるので、`target_link_libraries`で`Threads::Threads`を指定すればリンクできる。
また、コンパイル時に`-pthread`オプションをつけたい場合は`set(THREADS_PREFER_PTHREAD_FLAG ON)`とすると良い[^16]。
[FindThreads - CMake Documentation](https://cmake.org/cmake/help/latest/module/FindThreads.html)
[cmake and libpthread - stack overflow](https://stackoverflow.com/questions/1620918/cmake-and-libpthread)

# おわりに

柔軟に記述出来る反面、どう書くのが良いのか分かりにくいのがCMakeの難しいところで、そういったポイントを丁寧にカバーしてみました。
ここまでの手順を追えば、CMakeの基本的な使い方は十分だと思います。後はそのプロジェクト固有の処理や、CMakeはマルチプラットフォームですので、OSごとの分岐処理などを使いこなせれば最高だと思います。(ここが一番むずかしい…。)

最後になりましたが、:qiita:Qiita10周年おめでとうございます:cracker: :cracker: :cracker:
これからもよろしくお願いします:qiitan:　:qiitan:　:qiitan:



[^1]: 例えば、FetchContentを見てみると、`FetchContent_MakeAvailable` を使えば1つのコマンドで出来ると書いてあるが、「CMake 3.14以前をサポートするなら、次のようにする必要がある」という文面とともに、例が記載されている。[FetchContent #command:fetchcontent_populate - CMake Documentation](https://cmake.org/cmake/help/latest/module/FetchContent.html#overview)

[^2]: ようするに、`make`は`make all`とした時と同じ、ということ。生成された`Makefile`を見てみると、`default_target: main`という記述が見つかると思う。また、その`main`ターゲットの詳細は`main: cmake_check_build_system ...`に書かれている。

[^3]: 伝われ...！

[^4]: CMakeが持っている変数の一覧を説明付きで表示するコマンドである`cmake .. -LH`を叩いた時などに、オプションの説明が利用される。

[^5]: というかこうした方がメンテしやすそうだし、こうした方がいい。

[^6]: [file - CMake Documentation #Filesystem](https://cmake.org/cmake/help/latest/command/file.html#filesystem)

[^7]: [aux_source_directory - CMake Documentation](https://cmake.org/cmake/help/latest/command/aux_source_directory.html)

[^8]: ビルド環境を再生成するタイミングを意識するのが嫌か、手作業でファイルを追加するのが嫌か、どっちを取るか？という話。これくらいなら、まだ手作業でファイルを追加する方が楽。めちゃめちゃ大きいプロジェクトだと実際どうしているか、はまだコードを眺めていないので、どうしているかは分からない。分かったら教えて。

[^9]: ちゃんと依存関係解決しないと、どのオブジェクトファイルを再生成する必要があるのか分からんはず。実は、ちゃんと依存関係が解決されていて、`build/lib/mylib/CMakeFiles/mylib.dir/depend.make`を見てみると、その中に各オブジェクトファイルをtargetとして、そのprereqにヘッダファイルがリストアップされているのが分かると思う。`g++`はMake用の依存関係を出力できるので、`g++ -MM *.cpp > depend.make`として、`depend.make`をincludeすることで利用できる。

[^10]: `sudo make install`のように、`sudo`をつけないとpermission deniedする。prefixを上書きする理由は、`sudo`を使うのを避けるためではなくて、単純に配置する場所を変えたかっただけ、という好みの話もある。

[^11]: [install - CMake Documentation](https://cmake.org/cmake/help/latest/command/install.html#command:install) の`PUBLIC_HEADER`を使っているサンプルを見てほしい。

[^12]: 実行ファイルを生成するのは、いっちばん基本的な話になると思うんだけど、思った以上に最後になってしまった…。

[^13]: CMakeLists.txtの中で`DEBUG`と一致するか、で利用していたらどうするんだ、という話もあるかもしれないが、これの解決方法としては何かに統一しておくのが良いということになると思う。

[^14]: いつから使えるようになったの？

[^15]: 例えば、`FetchContent_Populate(MyLib)`としても、`mylib_POPULATED`、`mylib_SOURCE_DIR`や`mylib_BINARY_DIR`が定義される。

[^16]: `This variable has no effect if the system libraries provide the thread functions, i.e. when CMAKE_THREAD_LIBS_INIT will be empty.`って書いてあるののは実はよく分かってない。

[^17]: [CMakeの使い方（その１）#静的共有ライブラリの指定について(中級者以上) - Qiita](https://qiita.com/shohirose/items/45fb49c6b429e8b204ac#%E9%9D%99%E7%9A%84%E5%85%B1%E6%9C%89%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E6%8C%87%E5%AE%9A%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E4%B8%AD%E7%B4%9A%E8%80%85%E4%BB%A5%E4%B8%8A)に書いてあった