1. ホーム
  2. cmake

[解決済み】変数を設定・使用するCMakeの構文とは?

2022-04-06 23:12:15

質問

今度CMakeを使うときの自分への戒めのために質問させていただきます。決して定着しないし、Googleの検索結果もよくない。

CMakeで変数を設定・使用するための構文を教えてください。

どのように解決するのですか?

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() スクリプトは、呼び出された先のスコープで直接変数を変更します。

2つ目は、グローバル変数キャッシュ(Global Variables Cache)です。キャッシュについて知っておくべきこと。

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

    なお INTERNAL キャッシュ変数型は FORCE

  • CMake スクリプトでは、既存の Cache エントリを変更できるのは set(... CACHE ... FORCE) の構文があります。この動作は、例えば CMake 自身が通常 Cache エントリを強制しないため、別の値で事前に定義しておくことで利用されています。

  • コマンドラインを使用して、Cache のエントリを設定するには、次の構文を使用します。 cmake -D var:type=value ただ cmake -D var=value または cmake -C CMakeInitialCache.cmake .
  • できること アンセット のエントリをキャッシュに保存するには unset(... CACHE) .

Cache はグローバルであり、CMake スクリプトの事実上どこにでも設定することができます。しかし、Cache変数を使う場所についてはよく考えることをお勧めします(グローバルであるため、永続的である)。私は通常 set_property(GLOBAL PROPERTY ...)set_property(GLOBAL APPEND PROPERTY ...) 構文を使って、私独自の非固定グローバル変数を定義しています。

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

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

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

変数のデバッグだけが役立つこともあります。以下が参考になるかもしれません。

  • 単純に古い printf を使用したデバッグスタイルです。 message() コマンドを使用します。また、CMake自体に同梱されている、すぐに使えるモジュールもあります。 CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • 調べる CMakeCache.txt ファイルをバイナリ出力ディレクトリに作成します。このファイルは、make環境の実際の生成に失敗した場合にも生成されます。
  • 使用方法 変数ウォッチ() を使えば、変数の読み書きが行われる場所を確認することができます。
  • ディレクトリのプロパティを調べる キャッシュ変数 バリアブル
  • コール cmake --trace ... をクリックすると、CMake の完全なパース処理を見ることができます。これは、多くの出力を生成するため、最後の準備のようなものです。

特殊な構文

  • 環境変数
    • を読み取ることができます。 $ENV{...} と書き set(ENV{...} ...) 環境変数
  • ジェネレータ式
    • ジェネレータ式 $<...> は CMake のジェネレーターが make 環境を書き込むときにのみ評価されます (パーサーが "インプレースで置き換える通常の変数と比較します)。
    • コンパイラやリンカのコマンドラインや、複数のコンフィギュレーションがある環境では、非常に便利です。
  • 参考文献
    • ${${...}} で変数名を与え、その内容を参照することができます。
    • 関数/マクロのパラメータとして変数名を与えるときによく使われます。
  • 定数値 (参照 if() コマンド)
    • とともに if(MyVariable) を使用すると、変数に対して直接真偽をチェックすることができます。 ${...} )
    • が定数なら真 1 , ON , YES , TRUE , Y または0でない数。
    • 定数が 0 , OFF , NO , FALSE , N , IGNORE , NOTFOUND または空文字列、あるいは末尾が -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") と評価されるため、偽となります。 if("MSVC" STREQUAL "1")
      • したがって、ここでの最良の解決策は、上記を参照し、直接的に if(MSVC)
    • 良いニュースは、CMake 3.1 でこの問題が修正されたことです。 ポリシー CMP0054 . を常に設定することをお勧めします。 cmake_policy(SET CMP0054 NEW) を解釈するのみです。 if() 引数が引用されていない場合は、変数またはキーワードとして扱われます。
  • option() コマンド
    • 主に、キャッシュされた文字列のみで ON または OFF のような特殊な処理も可能です。 依存関係
    • しかし 気がつく を間違えないようにしましょう。 option とは set コマンドを使用します。に与えられた値は option は実際には初期値 (最初の設定ステップでキャッシュに一度だけ転送されます) であり、その後ユーザーが CMakeのGUI .

参考文献