CMake:configure_fileコマンド

# はじめに

CMake の `configure_file()` コマンドを使用すると、テンプレートファイルをもとにファイルを出力できます。
テンプレートファイル内では`${VAR}` のようなプレースホルダを使用して、CMakeLists.txtで定義した変数の内容を使用できます。
また、単にファイルをコピーすることもできます。

本稿では、`configure_file()` コマンドの概要を示した後、その使用例として `pkg-config` 向けのファイルを生成する方法を示します。

# `configure_file` コマンド

## コマンド書式

```cmake:configure_fileコマンドの書式
configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
```

## コマンド解説

ファイル `<input>` から、ファイル `<output>` にファイルをコピーします。コピーする際に、`<input>` ファイル中の変数への参照
はCMakeLists.txt中のCMake変数の値に置換されます。
`<output>` が相対パスの場合、現在のバイナリディレクトリからの相対パスとして扱われます。
`<input>` ファイルが修正されると、ビルドシステムが検知して再出力されます。

### 変数の置換
`configure_file` コマンドは、ファイル中の `${VAR}` または `@VAR@` の形式で参照した変数 `VAR` をCMake中の同名の変数で置き換えます。もし `VAR` が未定義なら、空で置換されます。`
@ONLY` オプションを指定すると、`@VAR` の形式のみが置換され、`${VAR}` の形式は置換されずにそのまま出力されます。

### ファイルの単純コピー
`COPYONLY` が指定されると、一切の置換は行われず、単純にファイルをコピーします。

### Cプリプロセッサ向け機能
入力ファイル中の `#cmakedefine VAR ...` の形式の行は、`#define VAR ...` か `/* #undef VAR */` のどちらかに置き換えられます。CMake変数の`VAR` が`if()` コマンドで false と評価される場合は、`/* #undef VAR */ に、さもなければ `#define VAR ...` に置き換えられます。`...` の部分は、通常と同様のルールで置換されます。

入力ファイル中の `#cmakedefine01 VAR` の形式は、`VAR` の値によって `#define VAR 1` または `#define VAR 0` に置き換えられます。

### 改行の指定
`NEWLINE_STYLE` オプションで改行方法を指定できます。

| オプション                       | 改行 |
|:--------------------------------|:----|
|`UNIX` または `LF`                | `\n` |
|`DOS` または `WIN32` または `CRLF` | `\r\n` |

`COPYONLY` は `NEWLINE_STYLE` と同時に使用してはなりません。

### その他
`ESCAPE_QUOTES` については未調査なので、記載しません。

参考:[CMake v3.0 - configure_file(7)](http://www.cmake.org/cmake/help/v3.0/command/configure_file.html)

# `configure_file` コマンドの使用例

## `pkg-config` 向けのファイルを生成する

`configure_file` コマンドを使って、自作のライブラリを使用する際のコンパイルフラグやリンカフラグを、`pkg-config` で扱えるようにしてみます。

`pkg-config` が、読み込むファイルは `libfoo.pc` というファイルなので、`configure_file` の入力ファイル名は`libfoo.pc.in`とします。

`libfoo.pc.in` を以下のように記述します。`libfoo.pc` 中に `${VAR}` 形式の変数参照を残したいので、変数は`@VAR@` 形式で記載します。

```txt:libfoo.pc.in
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: Foo
Description: Foo Library
Version: @foo_VERSION@
Libs: -L${libdir} -lfoo
Cflags: -I${includedir}
```

`.pc` ファイルの書式については、`man pkg-config` で確認してください。

CMakeLists.txt は以下のように記述します

```cmake:pkg-config向けCMakeLists.txt
cmake_minimum_required(VERSION 2.8)

set(foo_VERSION 1.0.0)
add_library(foo foo.c)

configure_file(libfoo.pc.in libfoo.pc @ONLY)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libfoo.pc
    DESTINATION lib/pkgconfig)

install(TARGETS foo
    PUBLIC_HEADER DESTINATION include
    ARCHIVE DESTINATION lib)
```

インストール先になる `lib` や `include` はlibfoo.pc.in と記載を揃えていますが、メンテナンス性を考慮して変数として設定しても構いません。


プロジェクトをビルドし、ビルドディレクトリに以下のような `libfoo.pc` が出力されたことを確認してください。

```txt:libfoo.pc
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: Foo
Description: Foo Library
Version: 1.0.0
Libs: -L${libdir} -lfoo
Cflags: -I${includedir}
```

このプロジェクトをインストールすると、下記のコマンドで `libfoo` のコンパイルフラグなどが取得できます。
(当然、`pkg-config` を別途インストールする必要があります）

```txt
$ pkg-config libfoo --cflags --libs
-I/usr/local/include -L/usr/local/lib -lfoo
```

### FindPkgConfig モジュール
`configure_file()` コマンドとは関連しませんが、`FindPkgConfig`モジュールの `pkg_check_modules` を使用すると、`pkg-config` コマンドを使用してコマンドラインフラグ等を取得し、CMake変数に設定できます。

```cmake:FindPkgConfig

include(FindPkgConfig)

pkg_check_modules(Foo libfoo)
message(STATUS "Foo_FOUND      ${Foo_FOUND}")
message(STATUS "Foo_CFLAGS     ${Foo_CFLAGS}")
message(STATUS "Foo_LIBRARIES  ${Foo_LIBRARIES}")
message(STATUS "Foo_LDFLAGS    ${Foo_LDFLAGS}")
```

参考: [CMake v3.0 - FindPkgConfigモジュール](http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html)