CMake再入門メモ
はじめに
モダンなC/C++開発ではビルドにCMakeを使うのがほぼ標準となっている。しかし、そこそこ経験を積んだあとでもCMakeのドキュメントを読んでいて意味がわからない事があった。そこでドキュメントを読み直してCMakeの基礎的な概念を復習した。下記のメモはCMakeバージョン3.21の公式ドキュメントをベースにしている。
ビルドシステム
ビルドシステムに関するドキュメントのイントロダクションが端的にCMakeのビルドの基本要素を述べているので引用する。
A CMake-based buildsystem is organized as a set of high-level logical targets. Each target corresponds to an executable or library, or is a custom target containing custom commands. Dependencies between the targets are expressed in the buildsystem to determine the build order and the rules for regeneration in response to change.
CMakeのビルドシステムは論理的なターゲットの集合からなっている。ターゲットは対応する実行形式ファイルやライブラリを持つものか、カスタムコマンド実行のためのターゲットのいずれかである。ビルド順序やリビルド時の生成ルールを決めるために、ターゲット間の依存関係がビルドシステムで表現される。
ビルドシステム(buildsystem)はファイルを生成する一連のルールを定義するもので、ライブラリなどのビルド生成物と関連付けられた「ターゲット」がその基本的な要素となる。CMakeはその依存関係を管理してビルド順序を決める。
CMake言語
ビルドシステムはCMakeListsファイルやcmake拡張子を持つファイル(以下cmakeファイルと呼ぶ)にビルドの依存関係や処理内容をCMake言語(CMake language)によって記述する。
CMake言語では関数やマクロの実行を行うコマンド呼出し(command invocation)がプログラム構成要素の単位であり、コマンド呼出しの列挙でソースファイルが構成される。
CMakeListsファイルはそれが配置されたディレクトリに関連づいた処理や設定を記述する。add_subdirectory()
コマンドによってサブディレクトリに処理の一部を移管することもできる。その場合は指定されたサブディレクトリにもCMakeListsファイルが存在する必要がある。
cmakeファイルは特定のディレクトリに依存しない処理を記述できる。cmakeコマンドの-P
オプションでスクリプト(script)として読み込んで実行する方式や、別のファイルからinclude()
コマンドによってモジュール(module)として読み込まれてその文脈で実行される方式がある。
ターゲットの定義のようなプロジェクト(下記参照)に結び付いたコマンドはスクリプト内では実行はできない。
ソースツリー・ビルドツリー
ビルドに使用されるソースコードを含むトップレベルディレクトリをソースツリー(source tree)と呼ぶ。ここにトップレベルのCMakeLists.txtが配置され、プロジェクト(下記参照)が定義される。
ビルドの生成物を保管するためのディレクトリをビルドツリー(build tree)と呼ぶ。ビルドツリーにはCMakeCache.txtが作成・保管され、キャッシュ変数やオプションなどが格納される。
同一ディレクトリを両方の用途に使用することも可能だが、ビルドツリーをソースツリーと分離(out-of-source build)してソースツリーをキレイに保つことが推奨されている。
cmake実行中に実行時情報を提供する変数が多数提供されている。例えば処理中の位置を取得するには次のような変数がある。
- CMAKE_SOURCE_DIR
ソースツリーの絶対パス - CMAKE_BINARY_DIR
バイナリツリーの絶対パス - CMAKE_CURRENT_SOURCE_DIR
ソースツリーにおける現在処理中のディレクトリの絶対パス - CMAKE_CURRENT_BINARY_DIR
ビルドツリー内における現在処理中のディレクトリの絶対パス
スクリプトとしての実行ではこれらの変数はカレントディレクトリを返す。
プロジェクト
ビルドシステムを論理的に分割する単位。ビルドシステムは少なくとも1つのプロジェクトを持つ。トップレベルのCMakeListsファイルはproject()
コマンドを使用してソースツリーが所属するプロジェクトを定義する。サブディレクトリ内でproject()
を呼びサブプロジェクトを定義することで、一つのビルドシステムに複数のプロジェクトを管理する事ができる。
プロジェクト分割については様々なプラクティスがあるようだが深入りしない。
ターゲット
ターゲットには何かを生成するためのものとそうでないものの2種類がある。
バイナリターゲット
ビルドシステムのメインの構成要素で、ライブラリや実行形式ファイル等のビルド生成物と結びついた論理的な単位。名前やプロパティ(下記参照)を持つ。
- ソースファイル
lib1.cpp
からなるライブラリターゲット(library target)t1
を作成
add_library(t1 lib1.cpp)
- ソースファイル
exe2.cpp
からなる実行形式ターゲット(executable target)t2
を作成
add_executable(t2 exe2.cpp)
- ターゲット
t1
にPOSITION_INDEPENDENT_CODE
プロパティを定義し、値をON
とする
set_property(TARGET t1 PROPERTY POSITION_INDEPENDENT_CODE ON)
Pseudoターゲット
バイナリターゲットと異なり、ビルドシステムの生成物と必ずしも結びついていないターゲット(pseudo target)がある。
-
IMPORTEDターゲット
ビルドシステムがビルドを行う前から存在する依存先を表すもの。
典型的なケースでは、インストール済のパッケージにより定義されたものがfind_package経由でビルドシステムへ追加されて使用可能になる。 -
ALIASターゲット
あるターゲットに別名をつけたもの。 -
INTERFACE LIBRARYターゲット
Usage Requirement(下記参照)プロパティを持ち、他のターゲットへプロパティをプロパゲートさせるためのターゲット。原則ソースコードを持たず、コンパイルは行われない。
プロパティ
CMakeのビルドシステムにおける様々な要素に名前付き属性値としてプロパティ(property)を持たせることができる:
- ディレクトリ
- ターゲット
- キャッシュ変数
- ソースファイル
- その他(テストやファイルなど)
また、特定の要素ではなくグローバルスコープにプロパティを定義することもできる。
プロパティの参照や設定はset_property()
, get_property()
などのコマンドと変数(下記参照)を介して行われる。そのためプロパティの型は変数に準じるものと思われる(明確な規定を見つけられなかった)。特定の要素のスコープに関連づけられているという点がプロパティと変数の大きな違いである。
変数
CMakeには通常変数(normal variable)、キャッシュ変数(cache variable)、環境変数(environment variable)という3種類の変数がある。
通常変数とキャッシュ変数は別々の概念だが、参照時には通常変数と同じ形式(例えば変数VAR1
に対して${VAR1}
)でキャッシュ変数も参照することができる(両方が同じ名前で存在する場合は通常変数が優先される)。
またCMake 3.21より以前ではキャッシュ変数をset(CACHE)
コマンドでセットすると同名の通常変数が削除されるという仕様で変数名の重複が回避されていた。
変数には未定義の状態と、定義済みの状態がある。set()
コマンドなど値を設定するコマンドを初回に実行したときに定義され、unset()
コマンドで未定義の状態に戻すことができる。未定義変数への参照は空の文字列を返す。
通常変数
メモリ上に記憶域を持つ通常の変数。関数内で定義されたものはその関数のスコープ、そうでないものはディレクトリのスコープに所属する(CMakeLists.txtが配置されているディレクトリ、スクリプトモードの場合は単一のディレクトリで実行されていると仮定される。モジュールの場合includeした位置のコンテキストに従う)
スコープは階層構造であり、ネストされたスコープからその外側のスコープ(親スコープ)にある変数を参照することができる。変更はset(PARENT_SCOPE)
によって明示的に親スコープへの操作として指定する必要がある。ネストしたスコープでPARENT_SCOPE
オプションなしでset()
を実行するとスコープ内での変数の定義になり、親スコープの同名の変数は隠される。
- 変数
VAR1
に値value1
をセットする。
set(VAR1 "value1")
- 変数
VAR1
を未定義の状態に戻す
unset(VAR1)
キャッシュ変数
ビルドディレクトリのCMakeCache.txtに記録される変数。グローバルスコープで参照可能で、生存期間がcmakeコマンドの終了後も継続する変数である。cmakeの複数回の実行で値を保つので生成したビルドの構成情報を保存するような用途にも使われる。
キャッシュ変数VAR1
の値は$CHACHE{VAR1}
で参照できる。同名の通常変数が存在しない場合は${VAR1}
でも参照できる。
set(CACHE)
コマンドで初回の変数定義ができる。既に定義されているものの変更にはFORCE
オプションが必要で、指定されていない場合はコマンドは無視される。
cmakeの-D
コマンドライン引数でも定義や変更が可能。
他の変数と異なり、キャッシュ変数は型を持つ。cmakeコマンドの-D
オプションで型を指定せずに定義することで「型のない状態」で使うこともできる。この場合set(CACHE)
を実行した時点で型が確定する。
環境変数
cmake実行プロセスが保持する環境変数。実行中にグローバルスコープでのみ存在しキャッシュはされない。環境変数VAR1
の値は$ENV{VAR1}
で参照できる。
- 環境変数
VAR1
に値var1
を設定する。このコマンドによって実行中のcmakeプロセスの環境変数が変更される。後続のテストプロセスなど別プロセスへは影響しない。
set(ENV{VAR1} var1)
- 環境変数
VAR1
をクリアする。
set(ENV{VAR1})
または
set(ENV{VAR1} "")
または
unset(ENV{VAR1})
リスト(list)
変数はすべて文字列として扱われるが、複数のものをまとめて扱いたい場合のためにリストという概念がある。これは複数の文字列を;
で連結したものである。リストという型が存在するわけではなく、あくまで文字列にすぎないが、関数の引数が暗黙的に連結されてリストとして扱えたり、操作関数など言語レベルでのサポートがあって不定個数のものをまとめて扱うのに便利である。
set(LIST1 "AA" "BB" "CC") # 3つの文字列からなるリストを作成
message("${LIST1}") # -> AA;BB;CC
list(APPEND LIST1 "DD") # リスト末尾に要素を追加
message("${LIST1}") # -> AA;BB;CC;DD
list(LENGTH LIST1 LEN) # リスト要素の個数を取得
message("${LEN}") # -> 4
list(GET LIST1 2 ITEM) # 2番目の要素を取得
message("${ITEM}") # -> CC
Build SpecificationとUsage Requirement
ビルドにおいては依存関係にあるターゲット間でプロパティを共有したり推移的に定義することが必要になることがある。CMakeは依存関係を調整してビルドを自動化するために、このようなプロパティの設定をサポートする機能があり、ターゲットのBuild SpecificationとUsage Requirementという概念によって説明される。
ビルドにおいて、ターゲットそのものに必要なプロパティと、ターゲットを使う側が必要とするプロパティがある。例えばINCLUDE_DIRECTORIES
プロパティはターゲットのビルド時にヘッダファイルを探索するためのディレクトリのリストを定義する。一方、INTERFACE_INCLUDE_DIRECTORIES
は「そのターゲットを使用するコードを含むターゲット」のビルド時に必要なディレクトリのリストを保持する。典型的なケースでは前者は実装が必要とするプライベートなヘッダファイルの位置を指し、後者はパブリックなAPIのヘッダファイルの位置を指す。
このようにターゲットのビルドに必要な設定情報をBuild Specificationと呼び、ターゲットを使用する側に必要なものをUsage Requirementと呼ぶ。前者はターゲットのコンパイル時にコンパイラやリンカに供給されるものなのに対して、後者はターゲットに依存する(推移的な依存を含む)ターゲットのビルドに必要となる。
Usage Requirementのプロパティは対応するBuild Specificationプロパティに接頭辞INTERFACE_
をつけたものである。たとえばターゲットAがターゲットBを使用し、ターゲットBにINTERFACE_INCLUDE_DIRECTORIES
プロパティが定義されていると、ターゲットAのビルド時にターゲットBのINTERFACE_INCLUDE_DIRECTORIES
の内容がターゲットAへINCLUDE_DIRECTORIES
としてプロパゲートされる。
プロパゲートされたものをターゲットAがどう使うかはtarget_link_librariesコマンドで指定される。
target_link_libraries
CMakeで最も重要なコマンドの一つ。
名前からライブラリ間のリンクを行うものと考えがちだが、より広く、ターゲット間の依存関係を定義するものと捉えた方がよい。例えばINCLUDE_DIRECTORIES
がこのコマンドによってターゲット間でプロパゲートされたりするので、純粋にリンカに関するコマンドというわけではない。
Build Specificationがあるターゲットのビルドで閉じたものなのに対して、Usage Requirementは依存関係があるターゲット間に規定される性質であり、推移的な状況も考慮する必要がある。
例えばターゲットAがターゲットBを使用し、さらにBがCを使用していて、BのパブリックヘッダがCのパブリックヘッダを直接参照していると、A -> B -> Cという推移的な依存関係によってAのビルドにCのパブリックヘッダが必要になる。
このような状況では、2ターゲット間でのUsage Requirementプロパティのプロパゲートを考えるとともに、プロパゲートされたものをさらにプロパゲートさせるかどうかという設定が必要になる。これを行うのがtarget_link_libraries
コマンドである。
プロパゲートされたプロパティをAが直接使用するか、さらに依存関係のあるターゲットへプロパゲートさせるかPRIVATE
/PUBLIC
/INTERFACE
キーワードで制御する。
target_link_libraries(A PRIVATE B)
target_link_libraries(A PUBLIC B)
target_link_libraries(A INTERFACE B)
- PRIVATE
プロパゲートされたプロパティは依存元(A)でBuild Specificationとしてのみ使用される。 - INTERFACE
プロパゲートされたプロパティは依存元(A)のUsage Requirementとしてのみ使用される。 - PUBLIC
プロパゲートされたプロパティは依存元(A)のBuild SpecificationおよびUsage Requirementとする。
コマンド呼出し
前述のようにCMake言語はコマンド呼出しによって構成される。コマンド呼出しはシンプルな構文で、コマンド名と引数によって与えられる。引数の文字列はクォートしてもしなくてもよい。
set(VAR1 var1) # 変数名VAR1および値var1の両方が文字列としてコマンド側へ渡される
ビルトイン関数では第一引数に既定のキーワードを渡すことで同名のコマンドに複数の動作モードを定義している。
install(TARGETS <target>... [...]) : 第一引数でTARGETSという文字列を渡す
install(DIRECTORY <dir>... [...]) : 第一引数でDIRECTORYという文字列を渡す
公式ドキュメントはこれらをinstall(TARGETS)
やinstall(DIRECTORY)
のように記述して区別している。
if()
コマンドは歴史的な理由から特殊な呼び出し規則を持つ。通常は引数に変数の値を渡したい場合は${...}
という形式、つまり変数参照をするべきだが、if()
コマンドには変数名を受け取る構文がある。変数参照をすると二重に値を評価することになるので注意が必要である。
if(VAR1)
# 変数VAR1の値が定義されていて偽と評価される文字列でない
endif()
if(${VAR1})
# 変数VAR1の値を変数名とする変数が定義されていて、その値が偽と評価される文字列でない
endif()
ここで、「偽と評価される文字列」とは0
、OFF
、NO
, FALSE
, N
, IGNORE
, NOTFOUND
, 空文字列, -NOTFOUND
で終わる文字列のいずれかである。
関数(function)とマクロ(macro)
関数とマクロはそれぞれfunction()
とmacro()
コマンドで作成可能なカスタムコマンドである。
C/C++のプリプロセッサによるマクロと同様に、マクロはその呼び出し部分において、マクロ定義の文字列をインラインに展開し呼び出しを置き換えたように動作する。マクロ内部でreturn()
を呼ぶとマクロを呼び出した側のコンテキストでreturn()
することになる。一方、関数はスコープを作成し、return()
もその関数からの脱出になる。
関数は任意個数の引数をサポートするために関数内部で参照可能なARGC
やARGV0
, ARGV1
, ...といった変数が自動的に定義される。マクロ内部でもこれらの名前で参照可能だが、変数として存在するわけではなく、マクロ展開時に与えられた引数で置き換えられる。そのため、変数である必要があるコマンド、例えばif(ARGV1)
などは関数内では使えるがマクロ内では使用できない。
マクロの必要性が特になければ関数を使用する方が直感的で無難であると思われる。
関数
function()
コマンドで新規の関数が定義できる。
関数内部では新しいスコープが開始し、仮引数はそのスコープに定義された変数であり、呼び出し側から与えられた値をもつ。
CMakeには関数の戻り値や参照の概念がないので、関数の結果を呼出し側へ返すには工夫が必要である。典型的には、関数は出力用変数の名前を受け取り、set(PARENT_SCOPE)
することで呼び出し側の変数を書き換えるという事を行う。
例:2つの引数を連結してリストを戻す関数
function(f in1 in2 out)
set(${out} ${in1} ${in2} PARENT_SCOPE) # outを参照して変数名を取得
endfunction()
set(result)
f("A" "B" result) # resultの値ではなく、resultという変数名を文字列で渡す
message("${result}") # -> A;B
マクロ
macro()
コマンドで新規のマクロが定義できる。
実行時に呼び出し箇所へインライン展開されたかのように動作する。新しいスコープは作らず、呼び出し側が与えた引数で仮引数を文字通り置き換えてからマクロ本体を実行する。
呼び出し側の変数へ直接のset()
が可能なので、関数のようにset(PARENT_SCOPE)
を使う必要はない。
macro(f in1 in2 out)
set(${out} ${in1} ${in2})
endmacro()
set(result)
f("A" "B" result)
message("${result}") # -> A;B
オプション
option()
コマンドでコンディショナルにキャッシュ変数を定義することができる。具体的には、このコマンドの実行時点までに通常変数かキャッシュ変数として同名の変数が定義されている場合は何もせず、そうでない場合のみ新しくキャッシュ変数を定義してデフォルト値を設定する。
ビルドの構成に関して外部からカスタマイズ可能な選択肢を明示する目的で使われる。デフォルト値が設定できるので、後続の参照時に値が未定義である状態を避けることができる。
任意の文字列を格納する用途には使えず、ON
/OFF
/0
/1
など真偽の値(を表す文字列)のみ格納できるブール型の変数のように扱われる。
option(OPT1 "explanation" OFF) # 1
message(${OPT1}) # 1の実行前にOPT1が定義されていればその値
# そうでなければ1でOPT1が定義され、デフォルト値OFFが返る
オプションと同様の事は変数やキャッシュ変数で実現できなくもないが、ややトリッキーになる。set()
によって通常変数を、またはset(CACHE FORCE)
によってキャッシュ変数を設定すると既に定義されていたときに上書きしてしまうし、set(CACHE)
を使用すると、前段から与えられたものが通常変数だった際にキャッシュ変数を追加してしまう。
CMake 3.13より以前ではoption()
コマンドで指定された名前と同名の通常変数がある場合にはそれを削除するという仕様で名前の重複が回避されていた。
インストール
ビルドした成果物を実行のために適切な位置へ配置するのがインストール(install)である。make installやninja installなどネイティブコマンドと同等のことがcmake --install
によって実行できる。このインストール時の処理の指示を行うのがinstall
コマンドである。
install(TARGETS)
コマンドによりターゲットに対してファイル種別ごとのインストール位置やオプションを指定できる。システムワイドな位置にインストールする場合、OSによってディレクトリ構成が異なることも多いが、LinuxやBSDであればGNUInstallDirs
モジュールを使ってシステムデフォルトのインストールパスを取得して使うことができる。
ターゲットと無関係にファイルやディレクトリをインストールしたい場合はinstall(FILES)
やinstall(DIRECTORIES)
コマンドでインストールのルールを設定できる。
キャッシュ変数CMAKE_INSTALL_PREFIX
によってインストールのトップレベルの位置が指定できる。
インポート/エクスポート
ここまでは主にプロジェクト内での依存関係について述べてきた。プロジェクト外部との依存関係の解決がCMakeのもう一つの大きな役割となる。
依存関係をcmakeファイルの形で保存することをエクスポート(export)、別のCMakeプロジェクトからそれを利用することを、インポート(import)と呼ぶ。
install(TARGETS)
コマンドのEXPORT
オプションでインストールするターゲットをエクスポート名と関連づけることができる。install(EXPORTS)
でcmakeファイル名やそのインストール先を指定する。NAMESPACE引数を指定することで、エクスポートされるターゲット名に接頭辞をつけることができる。インポートする側はこの接頭辞つきのターゲット名を利用する。
インストールを経由せずにビルドしたものをそのまま別プロジェクトで利用することも可能である。この場合はexport()
コマンドで依存情報をcmakeファイルへ書き出す。
機能やパッケージを提供する側を上流(upstream)、機能を使用したり依存する側を下流(downstream)と呼ぶ。
パッケージ
パッケージ作成に関するドキュメントのイントロダクションが端的にパッケージ(package)とは何かを述べている。
Packages provide dependency information to CMake based buildsystems. Packages are found with the find_package() command. The result of using find_package() is either a set of IMPORTED targets, or a set of variables corresponding to build-relevant information.
パッケージはビルドシステムに依存関係の情報を提供するものである。パッケージはfind_package()コマンドによって探索される。find_package()によって得られるのはIMPORTEDターゲットやビルド関連情報の変数のセットである。
外部の依存関係を提供するという点でエクスポート/インポートと似ているが、適合するバージョンの解決を行ったり、CMakeをサポートしていないサードパーティのライブラリに対しても利用できるという点で、パッケージの方がより広い範囲をカバーするものである。例えばエクスポート/インポートのみだとエクスポートしたcmakeファイルを配置する位置を何らかの方法で共有する必要があるが、find_packageはファイルを探索する場所も定義しており、cmakeファイルを共有する標準的な方法を提供している。またConfig-fileパッケージ(下記参照)ではエクスポート/インポートの仕組みを使用することが多く、互いに関連しあっている。
パッケージにはConfig-fileパッケージとFind-moduleパッケージの2種類がある。find_packageにもmoduleモードとconfigモードの2つの動作モードがあり、デフォルトでは最初にmoduleモードで動作してFind-moduleパッケージを探す、見つからなかった場合にConfig-fileパッケージを探すconfigモードに移行するという動作になっている。
Config-fileパッケージ
機能を提供する上流によって必要な構成情報のファイルが与えられるパッケージ。通常は上流の開発者によってビルド成果物の一部として作成・公開される。
具体的にはPackage Configurationファイルと、オプショナルなPackage VersionファイルがConfig-fileパッケージの構成要素である。
パッケージを作成する上流ビルドシステムが生成物をインストールする位置が
<prefix>/include/foo-1.2/foo.h
<prefix>/lib/foo-1.2/libfoo.a
であるときに、Package ConfigurationファイルやPackage Versionファイルは
<prefix>/lib/cmake/foo-1.2/FooConfig.cmake
<prefix>/lib/cmake/foo-1.2/FooConfigVersion.cmake
に配置することができる。
(これ以外にもfind_packageがサポートする場所へ置くことができる。またファイル名としてCamelCaseだけでなくsnake caseを使用する事もできる)
Package Configurationファイル
Package Configurationファイルは上流の情報を変数やターゲットプロパティを通して提供するモジュールである。
パッケージに関連づいた変数(インクルードパスやライブラリに関するもの)を定義して呼び出し側へ返す。
set(Foo_INCLUDE_DIRS ${PREFIX}/include/foo-1.2)
set(Foo_LIBRARIES ${PREFIX}/lib/foo-1.2/libfoo.a)
またはIMPORTEDターゲットの定義を行い、インポート側へ利用可能なターゲットとして公開することも可能である。
add_libarary(hoge IMPORTED)
target_include_directories(hoge ...)
典型的には、上流側もCMakeによって開発され、CMakeListsファイル内のinstall(TARGETS)
とinstall(EXPORTS)
によってcmakeファイルのエクスポートおよびインストールが指示される。Package Configurationファイルはこのモジュールを読み込む事でIMPORTED
ターゲットの定義ができる。この場合、パッケージ作成の手順の大半はこの2つのコマンドに正しく引数を指定することに帰着する。
Package Versionファイル
パッケージにはバージョンをつけることができる。バージョンはmajor
, minor
, patch
, tweak
という最大4つの整数からなり、バージョン文字列(version string)はmajor[.minor[.patch[.tweak]]]
のようにこれらをドットで連結した形式で表される。
Package Versionファイルは、find_package()
コマンドに対して要求されたバージョンの情報を受け取り、自分自身がその条件に合致するかを判定し、合致する場合にバージョン番号等の詳細を戻すためのモジュールである。
バージョン情報とのマッチングなどはある程度決まったコードになるので、このファイルを作成するときは、CMakePackageConfigHelpers
モジュールをincludeして
write_basic_package_version_file()
コマンドを使用することでボイラープレートを作成する事ができる。
Find-moduleパッケージ
必要とするヘッダやライブラリの情報を下流側から探しに行くためのルールを記述したファイルによって構成されるパッケージ。上流がCMakeによってビルドされていなかったり、CMakeをサポートしていない場合でもfind_package()
を使って探索してインポートすることができる。
補足
公式ドキュメントを読んで特に気になった事を補足する。
dependencies
公式ドキュメント中ではdependenciesという単語で「依存先(依存される側)」を表すことがある。「依存関係」という意味で読んでいると意味がとりにくかった。
Usage requirements are propagated by reading the INTERFACE_ variants of target properties from dependencies and appending the values to the non-INTERFACE_ variants of the operand.
depender/dependee/dependant
依存関係のある二者の片方を表す時の表現は必ずしも一貫
していなくてセクションによって使う単語が微妙に異なっている:
- depender (依存する側)
- dependee (依存される側)
- dependent (依存する側)
link interface
公式ドキュメント中、link interfaceという用語が明確な定義がなく使われているところがあった。おそらくINTERFACE_LINK_LIBRARIES
が指すものと同じ意味で使っていると思われる。deprecatedなプロパティにLINK_INTERFACE_LIBRARIESという名前があるので、古い用語なのかもしれない。
Libraries for a Target and/or its Dependents
The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify both the link dependencies and the link interface in one command.
リファレンス
CMakeドキュメント
cmake-buildsystem(7)
cmake-language(7)
cmake-packages(7)
Discussion