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


168

次回CMakeを使用するときに、これを思い出すためにこれを求めています。それは固執することはなく、Googleの結果は素晴らしいものではありません。

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

回答:


281

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アプリケーションで変更できます。したがって、それらは-通常の変数と比較して- typeとaを持っていdocstringます。通常はGUIを使用しないためset(... CACHE INTERNAL "")、グローバル値と永続値を設定するために使用します。

    ので、予めご了承くださいINTERNALキャッシュ変数の型が意味するものではありませんFORCE

  • CMakeスクリプトでは、set(... CACHE ... FORCE)構文を使用する場合にのみ、既存のキャッシュエントリを変更できます。この動作は、たとえばCMake自体によって使用されます。これは、通常はキャッシュエントリ自体を強制しないため、別の値で事前定義できるためです。

  • コマンドラインを使用して、シンタックスを使用してcmake -D var:type=valuecmake -D var=valueまたはを使用して、キャッシュにエントリを設定できますcmake -C CMakeInitialCache.cmake
  • を使用して、キャッシュ内のエントリの設定を解除できますunset(... CACHE)

キャッシュはグローバルであり、CMakeスクリプトの実質的にどこにでも設定できます。ただし、キャッシュ変数を使用する場所については、2度考えることをお勧めします(これらはグローバルであり、永続的です)。通常、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環境はコマンドラインと異なる場合があるため、環境変数をキャッシュされたものに転送することをお勧めします。

デバッグ変数のみが役立つ場合があります。以下が役立ちます。

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

特別な構文

  • 環境変数
    • 環境変数$ENV{...}を読み書きできset(ENV{...} ...)ます
  • ジェネレータ式
    • ジェネレーター式$<...>は、CMakeのジェネレーターがmake環境を作成するときにのみ評価されます(パーサーによって「インプレース」で置き換えられる通常の変数との比較)。
    • コンパイラー/リンカーのコマンドラインやマルチ構成環境などで非常に便利
  • 参考文献
    • を使用し${${...}}て、変数に変数名を付け、その内容を参照できます。
    • 関数/マクロパラメータとして変数名を指定するときによく使用されます。
  • 定数値(if()コマンドを参照)
    • if(MyVariable)あなたが直接、真/偽の(囲んでいるため、ここでは不要のための変数を確認することができます${...}
    • 真の定数がある場合は1ONYESTRUEY、またはゼロ以外の数値。
    • 定数がある場合はFalse 0OFFNOFALSENIGNORENOTFOUND、空の文字列、または接尾辞で終了します-NOTFOUND
    • この構文はしばしばのようなものに使用されますが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")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") これはfalseです。 if("MSVC" STREQUAL "1")
      • したがって、ここでの最善の解決策は-上記を参照-直接チェックすることです if(MSVC)
    • 良いニュースは、ポリシーCMP0054の導入により、CMake 3.1でこれが修正されたことです。常にcmake_policy(SET CMP0054 NEW)if()引用符で囲まれていない場合、引数を変数またはキーワードとしてのみ解釈する」に設定することをお勧めします。
  • option()コマンド
    • 主に単にキャッシュされた文字列のみ、ONまたは依存関係のみのOFFような特別な処理が可能です
    • しかし、注意して、間違えないでくださいoptionsetコマンド。与えられる値optionは、実際には「初期値」(最初の構成ステップ中に一度キャッシュに転送される)のみであり、その後CMakeのGUIを介してユーザーが変更することを意図しています。

参考文献


使用するif ("${MyString}" ...)と警告が表示されますPolicy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted。たとえば、ビルド367を参照してください。何か案は?
jww 2017

また、引用符を外す${MyString}と、「if given arguments ...」のような一連のエラーが発生しますたとえば、「if given arguments」の後にパラント、「NOT」、「EQUALS」などが続きます。
jww 2017

@jww警告はMyString、変数名が含まれていることを意味します。変数名は再び逆参照されます。私は誰も本当にそのようOLDな行動を望んでいないと思います。したがって、私の観点からすると、ポリシーCMP0054を設定するだけで完全に安全で下位互換性がありますNEWここの説明を参照)。
フロリアン

@jwwそして、これらの問題/警告を回避する最も安全な方法は、if (MyString ...)(コードが警告を発している場合)ただ実行することです。
フロリアン

ありがとう。すべての出現箇所を削除して${MyString}置き換えましたMyString(またはすべて削除したと思います)。それでも喜びがない:ビルド372。がらくたは私たちのコードからさえ来ていません。CMakeから来ているようです。行283はif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")です。
JWW

18

すばやく簡単に始めるための基本的な例をいくつか示します。

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ドキュメント


1

$ENV{FOO}使用法でFOOは、は環境変数から取得されます。とそうでない場合は使用${FOO}場所、FOO他のいくつかの変数です。設定にSET(FOO "foo")は、CMakeで使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.