Posted at
CMakeDay 13

CMake: IMPORTEDターゲット

More than 3 years have passed since last update.


はじめに

CMakeプロジェクト以外でビルドされた既存のライブラリや、プロプライエタリなライブラリでソースコードが公開されていないライブラリを、CMakeプロジェクトで利用したいケースがあります。

このようなライブラリをCMakeのターゲットとして扱うための仕組みが IMPORTED ターゲットです。

(ライブラリだけでなく、実行ファイルをIMPORTEDターゲットとして定義することもできます)

他にも、package-config.cmakeを記述する際に、インストールツリーのライブラリファイルをIMPORTEDターゲットとして定義するという使い道もあります。実際に、install(EXPORT) コマンドが生成するexport.cmakeはIMPORTEDターゲットを使用しています。


IMPORTED なライブラリを定義する

add_library() コマンドに IMPORTED オプションを指定すると、ターゲットをIMPORTEDなターゲットとして定義できます。なお、通常は意識する必要はありませんが、ターゲット・プロパティに IMPORTED が定義されます。

add_library(foo SHARED IMPORTED)

厳密な構文は下記になります。

add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED [GLOBAL])

IMPORTEDなターゲットは、定義したディレクトリか、その配下の(つまりadd_subdirectoryした)ディレクトリで参照できます。上位のディレクトリからは参照できません。

もし、上位のディレクトリから参照したい場合は、GLOBALオプションを付与します。


ライブラリファイルの格納場所を指定する (IMPORTED_LOCATION プロパティ)

add_library(<name> ... IMPORTED) としただけでは、実際のライブラリファイルの格納場所をCMakeが知ることができないため、ユーザーは明示的にライブラリファイルの格納場所をCMakeに伝える必要があります。

ライブラリファイルの格納場所を伝えるには、以下のように、IMPORTED_LOCATION プロパティ(または IMPORTED_LOCATION_<CONFIG> プロパティ)を設定します。


IMPORTED_LOCATIONの設定

set_target_properties(foo

PROPERTIES
IMPORTED_LOCATION /path/to/real/library/libfoo.so)

なおDLL環境でSHAREDライブラリの格納場所をIMPORTED_LOCATION に指定する際には、.libファイルでなく、.dllファイルを指定します。インポートライブラリ(.lib)ファイルの格納場所は、IMPORTED_IMPLIB または IMPORTED_IMPLIB_<CONFIG> で指定します。

IMPORTED_LOCATION のドキュメント(CMake 3.0)


SONAMEを指定する (IMPORTED_SONAME)

IMPORTED_SONAME または IMPORTED_SONAME_<config> プロパティを使用すると、SONAMEを指定できます。


クライアントターゲットが使用すべきインクルードディレクトリを指定する(INTERFACE_INCLUDE_DIRECTORIES)

IMPORTEDライブラリを使用するプログラムをコンパイルする際に、所定のインクルードディレクトリに存在するヘッダファイルの include を要するケースがままあります。

INTERFACE_INCLUDE_DIRECTORIES プロパティを指定すると、target_link_libraries(client foo) のように foo ライブラリをリンク指定することで、clientターゲットに target_include_directories で foo のINTERFACE_INCLUDE_DIRECTORIES で指定したディレクトリが付与されます。

set_target_properties(foo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES /path/to/foo/headers)

# べつのどこか
add_executable(client client.cc)
target_link_libraries(client foo)

# 以下を省略できる
# target_include_directories(client /path/to/foo/headers)

このようにINTERFACE_INCLUDE_DIRECTORIES を活用すると、/path/to/foo/headers を変数foo_INCLUDE_DIRECTORIES に設定して、個々のターゲットに target_include_directories コマンドで付与するという煩雑な作業を省略できます。


クライアントターゲットが使用すべきコンパイラ定義を指定する INTERFACE_COMPILE_DEFINITIONS

このライブラリをリンクする実行ファイルや他のライブラリをコンパイルする際に付与すべきコンパイラ定義を指定します。

IMPORTEDターゲット以外でも使用できますが、その場合は、ライブラリターゲットにtarget_compile_definitions() コマンドで指定する際に、PUBLICINTERFACE オプションを付与することで、このプロパティが自動的に設定されます。


クライアントターゲットが使用すべきコンパイラオプションを指定するINTERFACE_COMPILE_OPTIONS

このライブラリをリンクする実行ファイルや他のライブラリをコンパイルする際に付与すべきコンパイラオプションを指定します。IMPORTEDターゲット以外でも使用できます。

ターゲットがIMPORTEDターゲットでなければ、target_compile_optionsコマンドにINTERFACE または PUBLIC オプションを付与することで、自動的に設定できます。


依存ライブラリを指定する (IMPORTED_LINK_DEPENDENT_LIBRARIES)

インポートするライブラリ自体が他のライブラリに依存していることがあります。

依存しているライブラリ群を IMPORTED_LINK_DEPENDENT_LIBRARIES プロパティに指定することで、インポートしたライブラリをリンクする際に、このプロパティに指定したライブラリ群を同時にリンクできます。


note

詳細は追えていませんが、 `INTERFACE_LINK_LIBRARIES` という2.8.12から導入された新しいプロパティがあり、同様の動作をします。(INTERFACE_LINK_LIBRARIES に置き換えられた、IMPORTED_LINK_INTERFACE_LIBRARIES というプロパティもあります)