cmakeの使い方 　導入（採用するならout-of-source！）・CMakeList.txtの書き方・自作パッケージのインストール

## **はじめに**

出尽くしてると思いますが、cmakeを使ってみたので使い方と所感を記載します。

## **インストール**

aptやyumでインストールしてください。

```
sudo yum install cmake
```

```
sudo apt-get install cmake
```

## **基本的な使い方**

### **とりあえず使ってみる in-sourceビルド**

1. 各ディレクトリにCMakeList.txtを置く
2. トップで`cmake .`を実行
3. make, make install

以上です。簡単ですね!

### **in-sourceビルドの欠点**

2018/08/07 @tenmyo さんコメントを元に追記

上記の使い方、実は不便な点があります:cloud:。まずはビルド前後のディレクトリ内を見てもらいましょう。

```:ビルド前
$ ls
CMakeLists.txt  conf  lib  LICENSE  README  script  src  uninstall.sh
```

```:ビルド後
$ ls
CMakeCache.txt       CMakeLists.txt        lib       README  uninstall.sh
CMakeFiles           conf                  LICENSE   script
cmake_install.cmake  install_manifest.txt  Makefile  src
```

な、なんかめっちゃファイルが出来てるんですけど:weary:

cmakeを使用してビルドをすると、ビルド時に「成果物 + CMakeCache.txt, CMakeFiles等ビルド用のファイル達」を各ディレクトリ内に作成します。

なので、in-sourceビルド(`cmake .`指定)をしてしまうとビルド後ソース内がごちゃごちゃに。
この辺りが最初に戸惑うポイントだと思います。

でも大丈夫！cmakeは簡単にソースと成果物を分離出来るんです:+1:

### **採用するならout-of-source!**

cmakeはビルド成果物を格納する場所を変えることが出来ます。例えば先ほどの構成に`build`という空のディレクトリを用意しておいて、以下手順でビルドします。

1. 各ディレクトリにCMakeList.txtを置く
2. **buildディレクトリに移動して**、`cmake ../`を実行
3. make, make install

in-sourceとほとんど変わらず簡単ですね。なのにビルド前も後も綺麗なままです！:laughing:

```:ビルド後
$ ls
build  CMakeLists.txt  conf  lib  LICENSE  README  script  src  uninstall.sh
```

成果物は全部buildディレクトリ内。cleanも`rm -rf build/`でOKです。楽ちん！

```:buildディレクトリ内
[@build]$ ls
CMakeCache.txt  cmake_install.cmake  lib       script
CMakeFiles      conf                 Makefile  src
```

また、buildも`make`ではなく`cmake —-build buildディレクトリ`で置き換え可能。
`make`以外のコマンドでも同じ手順でコンパイルが可能になっています:+1:

その他色々なメリットが以下記事に記載されているので、興味ある方はぜひ参照ください:exclamation:
[CMake : out-of-sourceビルドで幸せになる](https://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca)

## **CMakeList.txtの書き方**

使い方の説明は終わり。ここからはCMakeList.txtの書き方です。

### 紹介するその前に

本記事は最新のcmake事情を追えていないため、現在非推奨なオプションが混在しています。
以下の記事で、その理由も含めた詳しい解説がまとめられていますので、参考にしてください。
[CMakeスクリプトを作成する際のガイドライン:https://qiita.com/shohirose/items/5b406f060cd5557814e9](https://qiita.com/shohirose/items/5b406f060cd5557814e9)

(情報古いけど)こんな方法で実現できるよくらいの感覚で見ていただけると幸いです。

### **共通**

- cmakeの保証最低バージョンを指定する。

```cmake
cmake_minimum_required(VERSION 2.8)
```

- コンパイルオプションや独自変数を定義する。

コンパイルオプションは`add_definitions`で、
独自変数は`set`で指定します。

```cmake
#defineの指定
add_definitions("-Wall -g -O2")
#defineの指定
set(DPPATH "/usr/local/lib")
```

`set`で定義した変数は、通常のスクリプトと同様`${DPPATH}`で利用できます。

後はディレクトリでやりたいことによって記載が変わります。

#### **変数情報**

使いそうな変数情報を記載。他にもめっちゃあるみたいですが、よく使うのはこんなもんかな？
他に使いそうなものがあれば追記します。

|変数名|意味|
|:---|:---|
|CMAKE_SOURCE_DIR|ソースコードのトップディレクトリ。cmake ../とかで指定された場所。|
|CMAKE_BINARY_DIR|cmakeの成果物が置かれるトップディレクトリ|
|PROJECT_SOURCE_DIR|projectオプションで指定されたプロジェクトのトップディレクトリ。|
|CMAKE_INSTALL_PREFIX|インストール先のprefix。デフォルトは/usr/local。<br>`cmake -DCMAKE_INSTALL_PREFIX=`pwd`/../local`といったオプション指定で変更可能|

### **サブディレクトリ指定**

ビルド対象のサブフォルダがある場合は以下のように指定すればOK！

```cmake
add_subdirectory(src)
```

### **srcビルド**

#### **バイナリを作成する**

基本は`add_executable`でOKです。add_executable(バイナリ名 ソース達)。ここではlan_routerが作成されます。
オプションがある場合は`add_definitions`を使ってください。

```cmake
add_executable(lan_router DHCPConfigurator.cpp GWConfigurator.cpp LANIPManager.cpp LANManager.cpp main.cpp JsonParser.cpp DHCPConfigurator_dnsmasq.cpp)
```

`set`でソースをまとめておく楽ですかね。複数バイナリも作れます。この場合はlan_router_dhcpd, lan_routerが作成されます。

```cmake
set(SRCS_BASE DHCPConfigurator.cpp GWConfigurator.cpp LANIPManager.cpp LANManager.cpp main.cpp JsonParser.cpp)
#for dhcpd
set(SRCS_DHCPD ${SRCS_BASE} DHCPConfigurator_dhcpd.cpp)
#for dnsmasq
set(SRCS_DNSMASQ ${SRCS_BASE} DHCPConfigurator_dnsmasq.cpp)
add_executable(lan_router_dhcpd ${SRCS_DHCPD})
add_executable(lan_router ${SRCS_DNSMASQ})
```

ヘッダーパスを追加するなら以下で出来ます。

```cmake
INCLUDE_DIRECTORIES("/usr/local/include")
```

#### **ライブラリをリンクする**

ライブラリパスは`link_directories`で指定できます。

```cmake
link_directories("/usr/local/lib")
```

ライブラリのリンクは`target_link_libraries`です。`target_link_libraries(バイナリ名 ライブラリ達)`
1点注意として、**この定義は`add_executable`の後にしないといけないです**。

```cmake
target_link_libraries(lan_router lower_layer_director dputil jansson)
```

### **ライブラリビルド**

srcビルドとの違いはバイナリの指定方法だけ。`add_executable`⇒`ADD_LIBRARY`に変わります。
この例ではlibeth_landevice.soが作成されます。

```cmake
ADD_LIBRARY(eth_landevice SHARED ether_device.c device_json_parser.c)
```

### **インストール設定**

基本は`INSTALL`コマンドを使用。ただし、**ライブラリ、バイナリ、それ以外によって少しオプションが変わります**。
インストール先は`${prefix}/DESTINATION`で指定したフォルダか、もしくはフルパス指定です。

**バイナリ**: 引数3個目に**RUNTIME**を指定する。

```cmake
INSTALL(TARGETS lan_router RUNTIME DESTINATION bin)
```

**ライブラリ**: 引数3個目に**LIBRARY** を指定する。

```cmake
INSTALL(TARGETS eth_landevice LIBRARY DESTINATION lib)
```

**それ以外**(スクリプトやconfファイル): 引数**1個目**に**FILES**を指定する。

```cmake
INSTALL(FILES lan_interface.conf DESTINATION conf PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
```

パーミッションの指定も可能です。

```cmake
#read only
INSTALL(FILES lan_interface.conf DESTINATION conf PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
#read write
INSTALL(FILES setting.json DESTINATION conf PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
```

パーミッションが同じなら複数指定も可能です。

```cmake
#read/write/execute
INSTALL(FILES firewall.sh firewall_BLACKLIST.sh countryip.sh DESTINATION /root/script PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE)
```

## **おまけ: ちょっと凝った使い方**

### **スクリプト実行**

こんな感じにmake実行時にスクリプトを実行することが出来ます。
ここではconfの中身をインストール先のprefixに合わせて置換しています。

```cmake
add_custom_target(create_setting ALL COMMAND "sed" "-e" "\"s@PREFIX@${CMAKE_INSTALL_PREFIX}@g\"" "setting.json.ini" ">" "setting.json")
```

最初ソースに対しても同じことをしようかと思いましたが、こちらはadd_definitionsで十分ですね。

```cmake
add_definitions(-DCONF_PATH="${CMAKE_INSTALL_PREFIX}/conf/")
```

### **option追加**

configureのenableオプションのように、cmake実行時のオプションで変数定義の切り替えも出来るとのことです。
lighttpdから抜粋

```cmake
option(WITH_LIBEV "libev support for fdevent handlers [default: off]")

if(WITH_LIBEV)
        find_package(LibEV REQUIRED)
        set(HAVE_LIBEV 1)
endif()
```

### **option設定 ccmake**

2018/08/07 追記

option追加出来るけど、configureみたいにhelpで一覧見ること出来ないっぽいな～と心の中で思っていたら、@tenmyo さんよりGUIの`cmake-gui`とTUI(text user interface)の`ccmake`というコマンドを教えていただきました！

早速実践。とりあえずオプションいっぱい持ってそうなlighttpdでのccmake結果。cmakeした後に同じディレクトリで`ccmake cmakeしたディレクトリ`でこんな感じにconfig設定画面が出てきます。

**どんなoptionが使えるか**、**今の設定がどうなっているのか**がすぐにわかります！わかりやすい！:+1:

<img width="605" alt="ccmake.png" src="https://qiita-image-store.s3.amazonaws.com/0/252277/58aa9fc2-a4e0-880f-41ad-356d48cc07ae.png">

ちなみに、ubuntuではccmakeを使うために以下が必要でした。

```
sudo apt install cmake-curses-gui
```

## **所感**

- `make`や`configure`と比べると**導入がとにかく簡単**
- 最初は何をやっているか分からなかったが、理解すると覚えることも少ないのでいい。

最初の最初だけとっつきにくいけど、使ってしまえばものすごく楽ちん！って感じでした。

2018/08/07 追記

`configure`をまとめた時は[導入の説明](https://qiita.com/developer-kikikaikai/items/433d69c4bcbf52b249a1)と[利用Tips](https://qiita.com/developer-kikikaikai/items/c3546cede0184f311d0e)で記事を分けましたが、`cmake`は大体のことが1つの記事でまとまりましたね:grin:
これだけでも導入ハードルの低さがわかります。

最初は別途`configure`と比較して`cmake`のデメリット(helpがない等)挙げようと思っていたのですが、全部補われていました。~~もう`configure`はいらない子なのかな？~~
でも自分は`configure`も好きです。`--help`でオプションが出てくるのがなんか好きなので。

##**参考**

基礎: [ごく簡単なcmakeの使い方](https://qiita.com/termoshtt/items/539541c180dfc40a1189)
ライブラリ追加に利用: [初めてのcmake備忘録](http://yukimemo.hatenadiary.jp/entry/2015/02/17/222113)
自作ライブラリ: [CMakeを使って自作ライブラリをビルド＆インストールしてみたまとめ](http://d.hatena.ne.jp/heiwaboke/20110324/1300976433)
インストール: [cmake-commands(7 install](https://cmake.org/cmake/help/v3.0/command/install.html#command:install)
コマンド実行:[cmakeでビルド時にシェルスクリプトを実行する](https://qiita.com/termoshtt/items/7f7090f9d0c52bcd2630)
オプション追加:[CMakeを使ってみた (4) ビルドオプション](http://www.wagavulin.jp/entry/2011/11/27/222650)
out-of-source:[CMake : out-of-sourceビルドで幸せになる](https://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca)
prefix変更:[CMakeでprefixを変える](http://physpolyglot.hateblo.jp/entry/2015/05/08/191110)
ccmake: [ccmakeのすすめ](http://d.hatena.ne.jp/alt-native/20121224/1356319986)