グローバル変数と変数スコープの問題を処理するにはどうすればよいですか? プロジェクトのキャッシュをロードしてテストにグローバル変数を挿入するか、テスト CMake ファイルを構成するか、-D コマンド ライン オプションを介してプッシュしますか?
一般的に言えば、現在存在するすべての方法 (キャッシュ経由、環境変数経由、および -D コマンドライン経由) は、予測できない動作を伴うため、いずれかのケースで悪い選択です。
これは私が思い出すことができる問題の最小のリストです:
- どの変数が別の変数と交差/重複する可能性があり、いつですか?
- 変数のロードまたは設定は、cmake 検出ステージ以外 (たとえば、cmake スクリプト モード) では適用できません。
- 同じ一意の変数が、異なる OS/コンパイラ/構成/アーキテクチャなどに対して異なる値を保持することはできません。
Find*
や などのシステム関数で表されるパッケージ (スコープではない) 用語に変数を添付することはできませんadd_subdirectory
。
私は長い間 cmake リスト内で変数を使用してきましたが、独自のソリューションを作成して、それらを cmake リストから一度に切り離すことにしました。
cmake スクリプトを介してスタンドアロン パーサーを作成し、ファイルまたはファイル セットから変数をロードし、一連のルールを定義して、事前定義された順序または厳密な順序で変数セットを有効にし、衝突と重複をチェックするという考え方です。
ここにいくつかの機能のリストがあります:
bool A=ON
bool A=TRUE
に等しいbool A=1
path B="c:\abc"
Windows では (デフォルトの文字列の代わりにpath B="C:\ABC"
明示的な変数) に等しいpath
B_ROOT="c:\abc"
B_ROOT="C:\ABC"
Windows では(変数名の末尾による変数の型検出)と等しい
LIB1:WIN="c:\lib1"
Windows でLIB1:UNIX="/lib/lib1"
のみ設定され、Unix でのみ設定されます (変数の特殊化)。
LIB1:WIN=c:\lib1
, LIB1:WIN:MSVC:RELEASE=$/{LIB1}\msvc_release
- 展開と特殊化によって変数を再利用する
ここですべてを説明することはできませんが、tacklelib
ライブラリ ( https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/ ) を例として、実装を独自に調査することができます。
記述された設定ファイルの例はここに保存されています: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/_config/
実装:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake/tacklelib/SetVarsFromFiles.cmake
必須として、configure_environment(...)
マクロを使用して cmake リストを初期化する必要があります:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/CMakeLists.txt
tacklelib
プロジェクト
の詳細については、readme ファイルをお読みください: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/README_EN.txt
現在、プロジェクト全体は実験的なものです。
PS : cmake でパーサー スクリプトを作成するのは大変な作業です。最初に少なくとも次の問題を読んでください。
独自の CMake スクリプト コードを単体テストする「公式」の方法はありますか? CMake を実行するための特別なモードのようなものはありますか? 私の目標は「ホワイト ボックス テスト」です (可能な限り)。
私は独自の「ホワイトボックス」または独自のスクリプトをテストする方法を作成しました。別のcmakeプロセスでテストを実行するために、一連のモジュール(それ自体がライブラリに依存)を作成しました:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake/tacklelib/testlib/
それに基づいて構築された私のテスト:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake_tests/
アイデアは、テストを含むディレクトリとファイルの階層をテストディレクトリに配置することです。ランナーコードは、事前定義された順序でテストを検索し、個別の cmake プロセスで各テストを実行します。
function(tkl_testlib_enter_dir test_dir)
# Algorithm:
# 1. Iterate not recursively over all `*.include.cmake` files and
# call to `tkl_testlib_include` function on each file, then
# if at least one is iterated then
# exit the algorithm.
# 2. Iterate non recursively over all subdirectories and
# call to the algorithm recursively on each subdirectory, then
# continue.
# 3. Iterate not recursively over all `*.test.cmake` files and
# call to `tkl_testlib_test` function on each file, then
# exit the algorithm.
#
、関数のセットは、ランナー cmake スクリプトまたは*.include.cmake
ファイルの両方から使用できます。
TestLib.cmake
テスト モジュールを使用して外部 cmake プロセスを作成するサイクルを実行するように設計されている場所-*.test.cmake
これらの関数は、ランナー スクリプトまたはインクルード モジュールから呼び出す必要があります (他のグループにはモジュールが含まれます -*.include.cmake
またはテスト モジュール - *.test.cmake
)。
tkl_testlib_enter_dir test_dir
tkl_testlib_include test_dir test_file_name
tkl_testlib_test test_dir test_file_name
テストコードを配置する必要があるすべてのモジュールにTestModule.cmake
自動的に含まれる場所。*.test.cmake
その後tkl_test_assert_true
、モジュール内で使用*.test.cmake
して、テストを成功または失敗としてマークします。
さらに、サブディレクトリのランナー スクリプトでフィルター パラメーターを使用して、_scripts
テストを除外することができます。
--path_match_filter <[+]regex_include_match_expression> | <-regex_exclude_match_expression>[;...]
--test_case_match_filter <[+]regex_include_match_expression> | <-regex_exclude_match_expression>[;...]
長所:
- は
TestModule.cmake
、事前定義されたルールによるテストでディレクトリ全体をスキャンします。テストを順序付けるために正しい階層と名前付けを確認するだけで済みます。
- ディレクトリごとに個別の包含ファイル
*.include.cmake
を使用して、排他的包含、またはディレクトリとその子孫内のテストの順序を変更します。
*.test.cmake
ファイルの存在は、デフォルトでテストを実行するための唯一の要件です。テストを排他的に含めたり除外したりするには、コマンド ライン フラグ--path_match_filter ...
と--test_case_match_filter ...
.
短所:
現在、プロジェクト全体は実験的なものです。