お手軽な xxx-config.cmake の作成方法

### モチベーション

CMake でライブラリを作成する際に、`<foo>-config.cmake` ファイルを作成しておくと、そのライブラリを利用するCMakeプロジェクトで find_package コマンドを利用して検索できます。

この foo-config.cmake を手で作成することもできますが、これはなかなか骨の折れる作業になります。

そこで、この記事では install(EXPORT) コマンドを使用して、foo-config.cmake を自動生成するCMakeLists.txtの書き方について解説します。

### この方法のメリット
- FindFoo.cmake を書く必要がない。
- クライアント側のCMakeLists.txt で `find_package(foo)` した後に、 `target_link_libraries(foo)` するだけで、自作のライブラリをリンクできる。


### おおまかな手順
1. 自作のライブラリを `install(TARGETS)` する際に `EXPORT <export-name>` オプションでエクスポート名を付与する
2. `install(EXPORT <export-name>)` コマンドで、インストールツリー向けの `foo-config.cmake` ファイルを生成して、インストールする
3. （オプション）`export(TARGETS)` コマンドで、ビルドツリー向けの `foo-config.cmake` ファイルが生成される

以下のサンプルでは、usage-requirement を用いて、このライブラリを `find_package` して使用するCMakeプロジェクトが`target_link_link_libraries()` を行うだけで以下が行えるようにしている。
- 自動的にインクルードパスが追加される
- 依存ライブラリがリンク対象に含まれる(以下の例では、`foo` をリンクすると、 `bar` が自動的にリンクされる）

### 実際のサンプル（インストールツリー向けのサンプル）
ライブラリ foo を作成して、そのライブラリ向けの foo-config.cmake を自動生成するサンプルを記述します。
CMakeLists.txt は以下のような記載になります。

```cmake
cmake_minimum_required(VERSION 2.8.12)

project(libfoo C)

# 1. INTERFACE_INCLUDE_DIRECTORIES にソースディレクトリとビルドディレクトリを自動追加する。
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) 
                                               
# 2. ライブラリのビルド指定
add_library(foo SHARED foo.c)

# 3. インストールするヘッダファイルを指定しておく。
# 指定したファイルは、INSTALL(TARGETS) の PUBLIC_HEADER で指定した
# ディレクトリにインストールされる。
set_target_properties(foo PROPERTIES
        PUBLIC_HEADER foo/foo.h
)

# 4. foo ライブラリが依存するライブラリを指定する。（オプション）
# PUBLIC指定してリンクすると、依存ライブラリがエクスポートされる(注1)
target_link_libararies(foo PUBLIC bar)

# 5. ターゲットのインストール指定
install(TARGETS foo
    EXPORT foo-export                         # 5.a EXPORT オプションで エクスポート名を指定する
    LIBRARY        DESTINATION lib            # 5.b ライブラリのインストール先
    INCLUDES       DESTINATION include        # 5.c エクスポート時にincludeパスに含めるパスを指定する
    PUBLIC_HEADER  DESTINATION include/foo)   # ヘッダのインストール先

# 6. foo-config.cmake を自動生成してインストールする。 
install(EXPORT foo-export                     # 6.a 
    FILE foo-config.cmake                     # 6.b ファイル名を指定する
    DESTINATION share/cmake/foo/              # 6.c インストール先
    EXPORT_LINK_INTERFACE_LIBRARIES)          # 6.d 同時にリンクすべきライブラリをエクスポートする
```

上記のプロジェクトをビルドしてインストールすると、`${CMAKE_INSTALL_PREFIX}/share/cmake/foo/foo-config.cmake` が生成されます。
生成された foo-config.cmake では、以下が行われます。
1. ターゲット foo を IMPORTED ライブラリとして定義する。
2. ターゲット foo の配置場所(IMPORTED_LOCATION) にインストール先のライブラリファイルを指定する。
3. ターゲット foo の INTERFACE_INCLUDE_DIRECTORIES プロパティにインストール先の foo/include を指定する。

1, 2 によって、find_package(foo) したプロジェクトで、ターゲット foo を使用してリンクすることができます。
3 によって、target_link_libraries(<target> foo) することで、 foo/include が自動的にインクルードされます。

上記の foo プロジェクトの CMakeLists.txt に下記のexport(EXPORT) コマンドを追加すると、foo のビルドツリーから、 fooターゲットを利用するための `foo-export.cmake` ファイルが、foo プロジェクトのビルドツリー内に生成されます。
このファイルは foo プロジェクトをインストールせずとも利用することができます。

#### 詳細

1. CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE を有効にする。
このCMake変数を ON に指定すると、ターゲットの INTERFACE_INCLUDE_DIRECTORIES にソースディレクトリと、ビルドディレクトリが自動的に追加されます。

2. ライブラリのビルド指定です。通常の指定と同じで構いません。

3. インストールヘッダの指定
4. ライブラリリンクの指定
5. ターゲットのインストール指定
普段と同様に、fooターゲットのインストール先を指定しますが、その際にいくつかの追加のオプションを指定します。
なお指定するパスが相対パスの場合は、 CMAKE_INSTALL_PREFIX からの相対パスになります。

    a. 後続の install(EXPORT) で利用する エクスポート名を指定します。ここでは foo-export という名前を指定しました。

    c. 生成される foo-config.cmake で foo ターゲットに指定する INTERFACE_INCLUDE_DIRECTORIESプロパティの設定値を指定します。その際に5.d で指定するヘッダのインストール先と一貫性を持たせます。

6. install(EXPORT) コマンドで、 foo-config.make の自動生成とインストール設定を行います。
 
    a. foo-export には、5 で指定したエクスポート名を指定します。

    b. 自動生成するファイル名を指定します。

    c. インストール先を指定します。find_packageが検索するパスを指定すると便利です。

    d. foo ライブラリのLINK_INTERFACE_LIBRARIES を指定します。

### インストールせずに、fooターゲットを利用したい
ビルドツリーから直接 foo ターゲットを利用するための `foo-export.cmake` を生成するためには、以下の export(EXPORT) コマンドを、fooプロジェクトに追加します。

```cmake:ビルドツリー向けの追加コマンド
# ビルドツリーからターゲットをIMPORTするための CMakeファイルを生成する（オプション）
export(EXPORT foo-export FILE foo-export.cmake
       EXPORT_LINK_INTERFACE_LIBRARIES)
```

生成された `foo-export.cmake` では、ビルドツリー内のライブラリファイルやディレクトリを参照した IMPORTED ターゲットが定義されます。


### ライブラリ利用側のプロジェクト
メリットで述べたとおり、``find_package(foo)`` を実行すると、foo-config.cmake が検索され、その中で `foo` というIMPORTEDターゲットが定義される。ライブラリ利用側のプロジェクトでは、`target_link_libraries(<target> foo)` とすれば、自動的にinclude_directoryと依存ライブラリのリンクが実施される。

以下に、foo ライブラリを使用するプロジェクトの CMakeLists.txt のサンプルを記載する。

```cmake:fooライブラリを利用するCMakeLists.txtのサンプル
cmake_minimum_required(VERSION 2.8.12)

project(foo-client C)

find_package(foo REQUIRED)

add_executable(foo-client foo-client.c) # fooライブラリを使用する実行ファイルを作成

target_link_libraries(foo-client foo)   # foo ライブラリをリンクする。
                                        # 自動的にインクルードディレクトリも設定されるため、
                                        # target_include_directories を記述しないで済む。
```
##### 注意:多段の依存関係の問題
参照 http://www.itk.org/Bug/print_bug_page.php?bug_id=1101 

多段の依存関係が存在すると、ライブラリパスがうまく引き継げないようです。
たとえば以下のような３つのCMakeプロジェクトがあるとします。

- foo: ライブラリ
- bar: fooライブラリに依存するライブラリ
- client: barに依存する実行プログラム

client をビルドするときに、fooライブラリのインストール先が引き継がれずに、リンクエラーになる可能性があります。

これを解消するには、クライアント側で明示的に `find_package(foo)` とするか、
もしくは `bar-config.cmake` に `find_package(foo)` を記述する必要があるようです。