Edited at

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

More than 3 years have passed since last update.


モチベーション

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_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( 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プロジェクトに追加します。


ビルドツリー向けの追加コマンド

# ビルドツリーからターゲットを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 のサンプルを記載する。


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

多段の依存関係が存在すると、ライブラリパスがうまく引き継げないようです。

たとえば以下のような3つのCMakeプロジェクトがあるとします。


  • foo: ライブラリ

  • bar: fooライブラリに依存するライブラリ

  • client: barに依存する実行プログラム

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

これを解消するには、クライアント側で明示的に find_package(foo) とするか、

もしくは bar-config.cmakefind_package(foo) を記述する必要があるようです。