web-dev-qa-db-ja.com

変数を設定および使用するためのCMakeの構文は何ですか?

次回CMakeを使用するときには、これを自分自身へのリマインダーとして要求しています。それは固執することはなく、そしてGoogleの結果は素晴らしいものではありません。

CMakeで変数を設定および使用するための構文は何ですか?

120
CivFan

CMakeスクリプトを書くときには、CMakeの構文と変数の使い方について知っておくべきことがたくさんあります。

構文

set()を使った文字列:

  • set(MyString "Some Text")
  • set(MyStringWithVar "Some other Text: ${MyString}")
  • set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

あるいはstring()と一緒に:

  • string(APPEND MyStringWithContent " ${MyString}")

set()を使ったリスト

  • set(MyList "a" "b" "c")
  • set(MyList ${MyList} "d")

list()を使えばもっと良いです。

  • list(APPEND MyList "a" "b" "c")
  • list(APPEND MyList "d")

ファイル名のリスト

  • set(MySourcesList "File.name" "File with Space.name")
  • list(APPEND MySourcesList "File.name" "File with Space.name")
  • add_excutable(MyExeTarget ${MySourcesList})

ドキュメンテーション

スコープまたは「変数にはどのような値がありますか?」

まず、「正規変数」とその範囲について知っておく必要があるものがあります。

  • 通常の変数は、それが設定されているCMakeLists.txtおよびそこから呼び出されるすべてのもの(add_subdirectory()include()macro()およびfunction())から見えます。
  • add_subdirectory()function()コマンドは特別なものです、なぜならそれらは彼ら自身の範囲を開くからです。
    • 意味変数set(...)はそこに見えているだけであり、それらはそれらが呼ばれたスコープレベル(親スコープと呼ばれる)のすべての通常の変数のコピーを作ります。
    • したがって、サブディレクトリまたは関数にいる場合は、set(... PARENT_SCOPE)を使用して、親スコープ内の既存の変数を変更できます。
    • あなたはこれを利用することができます。関数名として関数名として変数名を渡すことで関数内で。例としては、function(xyz _resultVar)set(${_resultVar} 1 PARENT_SCOPE)を設定することがあります。
  • 一方、include()またはmacro()スクリプトで設定したものはすべて、変数が呼び出される場所の範囲内で直接変数を変更します。

次に、「グローバル変数キャッシュ」があります。キャッシュについて知っておくべきこと:

  • 指定された名前の通常の変数が現在のスコープで定義されていない場合、CMakeは一致するキャッシュエントリを探します。
  • キャッシュ値は、バイナリ出力ディレクトリのCMakeCache.txtファイルに格納されています。
  • キャッシュ内の値は、生成される前に CMakeのGUI アプリケーションで変更できます。したがって、通常の変数と比較して、それらにはtypedocstringがあります。私は通常GUIを使用しないので、グローバル値と永続値を設定するためにset(... CACHE INTERNAL "")を使用します。

    INTERNALキャッシュ変数型はFORCEを意味することに注意してください

  • CMakeスクリプトでは、set(... CACHE ... FORCE)構文を使用する場合にのみ既存のキャッシュエントリを変更できます。この振る舞いは、例えばCMake自身によるものです。なぜなら、それは通常Cacheエントリ自身を強制するものではなく、それゆえあなたは別の値でそれを事前に定義することができるからです。

  • コマンドラインを使用して、cmake -D var:type=value、ちょうどcmake -D var=value、またはcmake -C CMakeInitialCache.cmakeの構文でキャッシュ内のエントリを設定できます。
  • unset(... CACHE)を使用して、キャッシュ内の 設定解除 エントリを作成できます。

キャッシュはグローバルであり、あなたはあなたのCMakeスクリプトのどこにでも事実上それらを設定することができます。しかし、キャッシュ変数をどこで使用するかについて二度考えることをお勧めします(それらはグローバルであり、永続的です)。私は通常、set_property(GLOBAL PROPERTY ...)set_property(GLOBAL APPEND PROPERTY ...)の構文を使って、自分の永続的でないグローバル変数を定義します。

変数の落とし穴と「変数の変更をデバッグする方法」

落とし穴を避けるためには、変数について次のことを知っておく必要があります。

  • 両方とも同じ名前を持つ場合、ローカル変数はキャッシュされた変数を隠します
  • find_...コマンドは - 成功した場合 - "呼び出しが再び検索されないように"キャッシュされた変数として結果を書き込みます。
  • CMakeのリストはセミコロンで区切られた単なる文字列です したがって引用符が重要です
    • set(MyVar a b c)"a;b;c"で、set(MyVar "a b c")"a b c"です
    • リストとしてリストを指定したい場合は、常に1つの例外を除いて引用符を使用することをお勧めします。
    • 一般的にリストの処理にはlist()コマンドを使います
  • 上記のスコープ全体の問題。特にローカル変数を親スコープに表示したくないため、functions()の代わりにmacros()を使用することをお勧めします。
  • CMakeが使用する多くの変数はproject()enable_language()の呼び出しで設定されます。そのため、これらのコマンドを使用する前にいくつかの変数を設定することが重要になる可能性があります。
  • 環境変数は、CMakeがmake環境を生成した場所やmakeファイルを使用したときとは異なる場合があります。
    • 環境変数を変更しても生成プロセスは再起動されません。
    • 特に生成されたIDE環境はあなたのコマンドラインとは異なるかもしれないので、キャッシュされているものにあなたの環境変数を転送することをお勧めします。

場合によっては変数のデバッグだけが役に立ちます。次のことが役に立ちます。

  • message()コマンドを使用して、古いprintfデバッグスタイルを使用するだけです。 CMake自体に同梱されているモジュールを使う準備ができているものもあります。 CMakePrintHelpers.cmakeCMakePrintSystemInformation.cmake
  • バイナリ出力ディレクトリのCMakeCache.txtファイルを調べてください。このファイルは、実際のmake環境の生成に失敗した場合でも生成されます。
  • variable_watch() を使って、あなたの変数がどこで読み書きされ、削除されるのかを確認してください。
  • ディレクトリのプロパティ CACHE_VARIABLESVARIABLES を調べてください。
  • CMakeの完全な解析プロセスを見るためにcmake --trace ...を呼び出してください。それは大量の出力を生成するので、それは最後の準備のようなものです。

特別な構文

  • 環境変数
    • $ENV{...}を読み、set(ENV{...} ...)環境変数を書くことができます。
  • ジェネレータ式
    • ジェネレーター式$<...>はCMakeのジェネレーターがmake環境を書くときにだけ評価されます(パーサーによって "その場で"置き換えられる通常の変数との比較)
    • とても便利コンパイラー/リンカーのコマンド行および複数構成環境で
  • 参考文献
    • ${${...}}を使用すると、変数に変数名を付けてその内容を参照できます。
    • 関数/マクロパラメータとして変数名を付けるときによく使われます。
  • 定数値( if() コマンドを参照)
    • if(MyVariable)を使うと、変数のtrue/falseを直接チェックすることができます(ここで囲む${...}は不要です)。
    • 定数が1ONYESTRUEY、またはゼロ以外の数値であれば真。
    • 定数が0OFFNOFALSENIGNORENOTFOUND、または末尾が-NOTFOUNDである場合はfalseです。
    • この構文はif(MSVC)のようなものによく使われますが、この構文のショートカットを知らない人にとっては混乱を招く可能性があります。
  • 再帰的置換
    • 変数を使用して変数名を構成できます。 CMakeが変数を代入した後、結果が変数自身であるかどうかをもう一度チェックします。これはCMake自身で使われている非常に強力な機能です。テンプレートの一種としてset(CMAKE_${lang}_COMPILER ...)
    • しかし注意してくださいこれはif()コマンドで頭痛の種になる可能性があります。これはCMAKE_CXX_COMPILER_ID"MSVC"で、MSVC"1"である例です:
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")if("1" STREQUAL "1")と評価されるため、trueです。
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")if("MSVC" STREQUAL "1")と評価されるため、falseです。
      • そのため、ここでの最善の解決策はif(MSVC)を直接チェックすることです(上記参照)。
    • 良いニュースは、これがCMake 3.1で policy CMP0054 の導入により修正されたことです。 「cmake_policy(SET CMP0054 NEW)引数を引用符で囲まないときは変数またはキーワードとしてのみ解釈する」ように常にif()を設定することをお勧めします。
  • option() コマンド
    • ONまたはOFFにしかなり得ない主にキャッシュされた文字列だけで、それらは次のような特別な処理を可能にします。 依存関係
    • ただし、に注意してください。optionsetコマンドと間違えないでください。 optionに与えられた値は、実際には「初期値」(最初の設定ステップの間に一度キャッシュに転送される)だけであり、その後 CMakeのGUI を通してユーザーによって変更されることを意味します。

参考文献

210
Florian

ここでは早くて汚い始めるための基本的な例をいくつか紹介します。

1項目の変数

変数を設定します。

SET(INSTALL_ETC_DIR "etc")

変数を使う:

SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")

複数項目の変数(つまりリスト)

変数を設定します。

SET(PROGRAM_SRCS
        program.c
        program_utils.c
        a_lib.c
        b_lib.c
        config.c
        )

変数を使う:

add_executable(program "${PROGRAM_SRCS}")

CMakeの変数に関するドキュメント

11
CivFan

FOOが環境変数から取得されている使用法の$ENV{FOO}。それ以外の場合は${FOO}として使用します。ここで、FOOは他の変数です。設定には、cmakeでSET(FOO "foo")を使用します。

0
parasrish