mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
TEST_INCLUDE_FILES: Evaluate generator expressions in include paths
The TEST_INCLUDE_FILE(S) directory properties were written verbatim into CTestTestfile.cmake, so a $<CONFIG>-parameterized include path could not select a per-configuration script and failed at ctest time. Evaluate generator expressions per include entry in cmLocalGenerator::GenerateTestFiles(): * Entries without a generator expression are emitted unchanged. * On single-config generators a genex entry is evaluated once and emitted as one unconditional include. * On multi-config generators it is evaluated for every configuration; a config-independent result collapses to one unconditional include, otherwise each non-empty per-config result is guarded by a CTEST_CONFIGURATION_TYPE branch, mirroring add_test(). An entry that evaluates to empty adds no include. Promote cmScriptGenerator::CreateConfigTest to a public static helper so the include guards reuse the exact add_test() config-test encoding; the instance overloads now delegate to it. Evaluated results are quoted via cmScriptGenerator::Quote, while plain entries keep their raw serialization. Fixes: #27941
This commit is contained in:
@@ -12,3 +12,9 @@ included and processed when ``ctest`` is run on the directory.
|
||||
If both the ``TEST_INCLUDE_FILE`` and :prop_dir:`TEST_INCLUDE_FILES` directory
|
||||
properties are set, the script specified in ``TEST_INCLUDE_FILE`` is included
|
||||
first, followed by the scripts listed in ``TEST_INCLUDE_FILES``.
|
||||
|
||||
.. versionadded:: 4.5
|
||||
|
||||
The include path may use :manual:`generator expressions
|
||||
<cmake-generator-expressions(7)>`, with the same per-configuration semantics
|
||||
as :prop_dir:`TEST_INCLUDE_FILES`.
|
||||
|
||||
@@ -13,6 +13,19 @@ were CTest dashboard scripts. It is common to generate such scripts dynamically
|
||||
since many variables and commands available during configuration are not
|
||||
accessible at test phase.
|
||||
|
||||
.. versionadded:: 4.5
|
||||
|
||||
Include paths may use :manual:`generator expressions
|
||||
<cmake-generator-expressions(7)>`. This is most useful with
|
||||
:prop_gbl:`multi-config generators <GENERATOR_IS_MULTI_CONFIG>`, where a
|
||||
``$<CONFIG>``-parameterized path selects a different script per
|
||||
configuration. On multi-config generators, an entry whose evaluated result
|
||||
varies by configuration is emitted under a per-configuration guard, so it is
|
||||
included only for the matching ``ctest -C <config>`` run. A path whose result
|
||||
is the same for all configurations is included unconditionally.
|
||||
|
||||
No build dependency is added for targets referenced in an include path.
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
@@ -38,3 +51,20 @@ Setting this directory property to append one or more CMake scripts:
|
||||
execute_process(
|
||||
COMMAND "@CMAKE_COMMAND@" -E echo "script.cmake executed during CTest"
|
||||
)
|
||||
|
||||
Selecting a per-configuration script with a generator expression:
|
||||
|
||||
.. code-block:: cmake
|
||||
:caption: CMakeLists.txt
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT "props_$<CONFIG>.cmake"
|
||||
CONTENT "set_tests_properties(some.test PROPERTIES LABELS \"$<CONFIG>\")\n"
|
||||
)
|
||||
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY TEST_INCLUDE_FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/props_$<CONFIG>.cmake"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
test-include-files-genex
|
||||
------------------------
|
||||
|
||||
* The :prop_dir:`TEST_INCLUDE_FILES` and :prop_dir:`TEST_INCLUDE_FILE`
|
||||
directory properties now support :manual:`generator expressions
|
||||
<cmake-generator-expressions(7)>` in the include path. On multi-config
|
||||
generators a ``$<CONFIG>``-parameterized path can select a different script
|
||||
per configuration.
|
||||
@@ -386,16 +386,91 @@ void cmLocalGenerator::GenerateTestFiles()
|
||||
fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n";
|
||||
}
|
||||
|
||||
auto writeTestIncludeFile = [this, &fout, &configurationTypes,
|
||||
&config](std::string const& entry) {
|
||||
// Entries without a generator expression are emitted verbatim,
|
||||
// preserving CTest-time ${VAR} expansion of the path.
|
||||
if (cmGeneratorExpression::Find(entry) == std::string::npos) {
|
||||
fout << "include(\"" << entry << "\")\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit one include() per path in an evaluated result. As for list-valued
|
||||
// properties, the result is split on ';', and each path is quoted so that
|
||||
// any '"', '$', or '\' cannot break the include() argument or trigger a
|
||||
// second-stage CTest ${...} expansion. An empty result adds no include.
|
||||
auto writeIncludes = [&fout](std::vector<std::string> const& paths,
|
||||
char const* indent) {
|
||||
for (std::string const& path : paths) {
|
||||
fout << indent << "include(" << cmScriptGenerator::Quote(path)
|
||||
<< ")\n";
|
||||
}
|
||||
};
|
||||
|
||||
if (!this->GlobalGenerator->IsMultiConfig() ||
|
||||
configurationTypes.empty()) {
|
||||
// Single-config generator, or a multi-config generator with no
|
||||
// configuration types: evaluate once with the default configuration
|
||||
// and emit unconditional includes.
|
||||
std::vector<std::string> paths;
|
||||
cmExpandList(cmGeneratorExpression::Evaluate(entry, this, config),
|
||||
paths);
|
||||
writeIncludes(paths, "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Multi-config generator: evaluate the entry for every configuration.
|
||||
std::vector<std::string> results;
|
||||
results.reserve(configurationTypes.size());
|
||||
bool allSame = true;
|
||||
for (std::string const& ct : configurationTypes) {
|
||||
results.emplace_back(cmGeneratorExpression::Evaluate(entry, this, ct));
|
||||
if (results.back() != results.front()) {
|
||||
allSame = false;
|
||||
}
|
||||
}
|
||||
|
||||
// A config-independent result collapses to unconditional includes, so it
|
||||
// still runs when ctest is invoked without -C.
|
||||
if (allSame) {
|
||||
std::vector<std::string> paths;
|
||||
cmExpandList(results.front(), paths);
|
||||
writeIncludes(paths, "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise guard each per-config result to match the config guards used
|
||||
// for add_test(). A configuration whose result yields no include is
|
||||
// skipped so no empty guard is emitted.
|
||||
bool first = true;
|
||||
for (size_t i = 0; i < configurationTypes.size(); ++i) {
|
||||
std::vector<std::string> paths;
|
||||
cmExpandList(results[i], paths);
|
||||
if (paths.empty()) {
|
||||
continue;
|
||||
}
|
||||
fout << (first ? "if(" : "elseif(")
|
||||
<< cmScriptGenerator::CreateConfigTest("CTEST_CONFIGURATION_TYPE",
|
||||
configurationTypes[i])
|
||||
<< ")\n";
|
||||
writeIncludes(paths, " ");
|
||||
first = false;
|
||||
}
|
||||
if (!first) {
|
||||
fout << "endif()\n";
|
||||
}
|
||||
};
|
||||
|
||||
cmValue testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
|
||||
if (testIncludeFile) {
|
||||
fout << "include(\"" << *testIncludeFile << "\")\n";
|
||||
writeTestIncludeFile(*testIncludeFile);
|
||||
}
|
||||
|
||||
cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
|
||||
if (testIncludeFiles) {
|
||||
cmList includesList{ *testIncludeFiles };
|
||||
for (std::string const& i : includesList) {
|
||||
fout << "include(\"" << i << "\")\n";
|
||||
writeTestIncludeFile(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,9 +100,10 @@ static void cmScriptGeneratorEncodeConfig(std::string const& config,
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmScriptGenerator::CreateConfigTest(std::string const& config)
|
||||
std::string cmScriptGenerator::CreateConfigTest(std::string const& configVar,
|
||||
std::string const& config)
|
||||
{
|
||||
std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
|
||||
std::string result = cmStrCat(configVar, " MATCHES \"^(");
|
||||
if (!config.empty()) {
|
||||
cmScriptGeneratorEncodeConfig(config, result);
|
||||
}
|
||||
@@ -111,9 +112,9 @@ std::string cmScriptGenerator::CreateConfigTest(std::string const& config)
|
||||
}
|
||||
|
||||
std::string cmScriptGenerator::CreateConfigTest(
|
||||
std::vector<std::string> const& configs)
|
||||
std::string const& configVar, std::vector<std::string> const& configs)
|
||||
{
|
||||
std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
|
||||
std::string result = cmStrCat(configVar, " MATCHES \"^(");
|
||||
char const* sep = "";
|
||||
for (std::string const& config : configs) {
|
||||
result += sep;
|
||||
@@ -124,6 +125,19 @@ std::string cmScriptGenerator::CreateConfigTest(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string cmScriptGenerator::CreateConfigTest(std::string const& config)
|
||||
{
|
||||
return cmScriptGenerator::CreateConfigTest(this->RuntimeConfigVariable,
|
||||
config);
|
||||
}
|
||||
|
||||
std::string cmScriptGenerator::CreateConfigTest(
|
||||
std::vector<std::string> const& configs)
|
||||
{
|
||||
return cmScriptGenerator::CreateConfigTest(this->RuntimeConfigVariable,
|
||||
configs);
|
||||
}
|
||||
|
||||
void cmScriptGenerator::GenerateScript(std::ostream& os)
|
||||
{
|
||||
// Track indentation.
|
||||
|
||||
@@ -78,6 +78,11 @@ public:
|
||||
|
||||
static cmScriptGeneratorQuoted Quote(cm::string_view value);
|
||||
|
||||
static std::string CreateConfigTest(std::string const& configVar,
|
||||
std::string const& config);
|
||||
static std::string CreateConfigTest(std::string const& configVar,
|
||||
std::vector<std::string> const& configs);
|
||||
|
||||
protected:
|
||||
using Indent = cmScriptGeneratorIndent;
|
||||
virtual void GenerateScript(std::ostream& os);
|
||||
|
||||
@@ -19,3 +19,28 @@ function(run_TID)
|
||||
endfunction()
|
||||
|
||||
run_TID()
|
||||
|
||||
function(run_TIDGenex)
|
||||
# Generator expressions in TEST_INCLUDE_FILE(S) include paths.
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TIDGenex-build)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
|
||||
endif()
|
||||
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
||||
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
||||
run_cmake(TIDGenex)
|
||||
run_cmake_command(TIDGenex-ctest-noC ${CMAKE_CTEST_COMMAND})
|
||||
run_cmake_command(TIDGenex-ctest-Debug ${CMAKE_CTEST_COMMAND} -C Debug)
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
run_cmake_command(TIDGenex-ctest-Release ${CMAKE_CTEST_COMMAND} -C Release)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
run_TIDGenex()
|
||||
|
||||
# Serialization/quoting rules for genex-evaluated include paths (configure only).
|
||||
run_cmake(TIDGenexQuoting)
|
||||
|
||||
# An unknown generator expression must fail at generate time.
|
||||
run_cmake(TIDGenexBadGenex)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Assert the serialization of the generated CTestTestfile.cmake for the
|
||||
# TEST_INCLUDE_FILE(S) generator-expression feature.
|
||||
set(ctf "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake")
|
||||
if(NOT EXISTS "${ctf}")
|
||||
set(RunCMake_TEST_FAILED "CTestTestfile.cmake not found:\n ${ctf}")
|
||||
return()
|
||||
endif()
|
||||
file(READ "${ctf}" content)
|
||||
|
||||
# Plain (singular) entry stays a bare, double-quoted include (regression).
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*plain[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"plain include not emitted as a bare double-quoted include\n")
|
||||
endif()
|
||||
|
||||
# Config-independent genex collapses to one unconditional bare include.
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*indep[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"config-independent genex not collapsed to one unconditional include\n")
|
||||
endif()
|
||||
|
||||
# A conditional-empty genex must never emit an empty include().
|
||||
if(content MATCHES "include\\(\"\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED "empty include() emitted\n")
|
||||
endif()
|
||||
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
if(NOT content MATCHES "CTEST_CONFIGURATION_TYPE MATCHES \"\\^\\(\\[Dd\\]\\[Ee\\]\\[Bb\\]\\[Uu\\]\\[Gg\\]\\)[$]\"")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"expected per-config Debug guard not found on multi-config\n")
|
||||
endif()
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*props_Release[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"expected props_Release.cmake per-config branch not found\n")
|
||||
endif()
|
||||
else()
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*props_Debug[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"expected unconditional props_Debug.cmake include not found\n")
|
||||
endif()
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*dbgonly[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"expected unconditional dbgonly.cmake include not found\n")
|
||||
endif()
|
||||
if(content MATCHES "CTEST_CONFIGURATION_TYPE MATCHES")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"unexpected per-config guard on single-config generator\n")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,19 @@
|
||||
# ctest -C Debug: the Debug per-config include and the Debug-only conditional
|
||||
# include both run; the Release per-config include does not.
|
||||
if(NOT actual_stdout MATCHES "plain_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "plain_test missing with -C Debug\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "indep_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "indep_test missing with -C Debug\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "config_Debug")
|
||||
string(APPEND RunCMake_TEST_FAILED "config_Debug missing with -C Debug\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "dbgonly_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "dbgonly_test missing with -C Debug\n")
|
||||
endif()
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
if(actual_stdout MATCHES "config_Release")
|
||||
string(APPEND RunCMake_TEST_FAILED "config_Release ran under -C Debug\n")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,17 @@
|
||||
# ctest -C Release (multi-config only): the Release per-config include runs;
|
||||
# the Debug per-config include and the Debug-only conditional include do not.
|
||||
if(NOT actual_stdout MATCHES "plain_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "plain_test missing with -C Release\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "indep_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "indep_test missing with -C Release\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "config_Release")
|
||||
string(APPEND RunCMake_TEST_FAILED "config_Release missing with -C Release\n")
|
||||
endif()
|
||||
if(actual_stdout MATCHES "config_Debug")
|
||||
string(APPEND RunCMake_TEST_FAILED "config_Debug ran under -C Release\n")
|
||||
endif()
|
||||
if(actual_stdout MATCHES "dbgonly_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "dbgonly_test ran under -C Release\n")
|
||||
endif()
|
||||
@@ -0,0 +1,27 @@
|
||||
# ctest invoked WITHOUT -C. Unconditional includes always run; guarded
|
||||
# per-config includes run only on single-config (where they collapse).
|
||||
if(NOT actual_stdout MATCHES "plain_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "plain_test missing without -C\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "indep_test")
|
||||
string(APPEND RunCMake_TEST_FAILED "indep_test missing without -C\n")
|
||||
endif()
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
if(actual_stdout MATCHES "config_Debug|config_Release")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"guarded config-dependent test ran without -C on multi-config\n")
|
||||
endif()
|
||||
if(actual_stdout MATCHES "dbgonly_test")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"dbgonly_test ran without -C on multi-config\n")
|
||||
endif()
|
||||
else()
|
||||
if(NOT actual_stdout MATCHES "config_Debug")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"config_Debug missing on single-config without -C\n")
|
||||
endif()
|
||||
if(NOT actual_stdout MATCHES "dbgonly_test")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"dbgonly_test missing on single-config without -C\n")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,30 @@
|
||||
enable_testing()
|
||||
|
||||
set(gen_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
# Plain include script (no generator expression in the path); used via the
|
||||
# deprecated singular TEST_INCLUDE_FILE to also cover singular-first ordering.
|
||||
file(GENERATE OUTPUT "${gen_dir}/plain.cmake"
|
||||
CONTENT "add_test(plain_test \"${CMAKE_COMMAND}\" -E true)\n")
|
||||
|
||||
# Per-configuration script selected by $<CONFIG> in the include path.
|
||||
file(GENERATE OUTPUT "${gen_dir}/props_$<CONFIG>.cmake"
|
||||
CONTENT "add_test(config_$<CONFIG> \"${CMAKE_COMMAND}\" -E true)\n")
|
||||
|
||||
# Config-independent generator expression in the path: collapses to a single
|
||||
# unconditional include (still runs without -C).
|
||||
file(GENERATE OUTPUT "${gen_dir}/indep.cmake"
|
||||
CONTENT "add_test(indep_test \"${CMAKE_COMMAND}\" -E true)\n")
|
||||
|
||||
# Debug-only include via a conditional-empty generator expression.
|
||||
file(GENERATE OUTPUT "${gen_dir}/dbgonly.cmake"
|
||||
CONTENT "add_test(dbgonly_test \"${CMAKE_COMMAND}\" -E true)\n")
|
||||
|
||||
set_property(DIRECTORY PROPERTY TEST_INCLUDE_FILE
|
||||
"${gen_dir}/plain.cmake")
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"${gen_dir}/props_$<CONFIG>.cmake")
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"$<1:${gen_dir}/indep.cmake>")
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"$<$<CONFIG:Debug>:${gen_dir}/dbgonly.cmake>")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
Error evaluating generator expression:.*
|
||||
.*NOTAGENEX
|
||||
@@ -0,0 +1,6 @@
|
||||
enable_testing()
|
||||
|
||||
# An unknown generator expression in the include path must fail at generate
|
||||
# time (diagnostics are best-effort: they need not name the set_property call).
|
||||
set_property(DIRECTORY PROPERTY TEST_INCLUDE_FILE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/x_$<NOTAGENEX>.cmake")
|
||||
@@ -0,0 +1,44 @@
|
||||
set(ctf "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake")
|
||||
if(NOT EXISTS "${ctf}")
|
||||
set(RunCMake_TEST_FAILED "CTestTestfile.cmake not found:\n ${ctf}")
|
||||
return()
|
||||
endif()
|
||||
file(READ "${ctf}" content)
|
||||
|
||||
# (1) ';' result: split into two separate double-quoted includes (fan-out),
|
||||
# not one combined include.
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*/a\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"semicolon result first element not emitted as its own include\n")
|
||||
endif()
|
||||
if(NOT content MATCHES "include\\(\"b[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"semicolon result second element not emitted as its own include\n")
|
||||
endif()
|
||||
if(content MATCHES "include\\(\"[^\n]*a;b[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"semicolon result was not split into multiple includes\n")
|
||||
endif()
|
||||
|
||||
# (2) space result: double-quoted.
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*a b[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED "space result not double-quoted\n")
|
||||
endif()
|
||||
|
||||
# (3) '$' result: bracket form, and NOT double-quoted.
|
||||
if(NOT content MATCHES "include\\(\\[=*\\[[^\n]*x[$]y[.]cmake[^\n]*\\]=*\\]\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED "dollar result not emitted in bracket form\n")
|
||||
endif()
|
||||
if(content MATCHES "include\\(\"[^\n]*x[$]y[.]cmake")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"dollar result was double-quoted (should be bracketed)\n")
|
||||
endif()
|
||||
|
||||
# (4) plain ${VAR} entry preserved raw and bare (double-quoted, not bracketed).
|
||||
if(NOT content MATCHES "include\\(\"[^\n]*lit_[^\n]*MY_VAR[^\n]*[.]cmake\"\\)")
|
||||
string(APPEND RunCMake_TEST_FAILED "plain \${VAR} entry not preserved raw\n")
|
||||
endif()
|
||||
if(content MATCHES "include\\(\\[=*\\[[^\n]*MY_VAR")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"plain \${VAR} entry was bracketed (should stay raw double-quoted)\n")
|
||||
endif()
|
||||
@@ -0,0 +1,27 @@
|
||||
enable_testing()
|
||||
|
||||
set(d "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
# This case only asserts serialization of the generated CTestTestfile.cmake;
|
||||
# ctest is never run, so the referenced paths need not exist.
|
||||
|
||||
# (1) A genex result containing ';' is split into multiple includes (list
|
||||
# semantics, as for usage-requirement properties). $<SEMICOLON> keeps the
|
||||
# ';' out of the pre-eval list split so it appears only in the evaluated
|
||||
# result, which is then re-split into one include() per element.
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"$<1:${d}/a$<SEMICOLON>b.cmake>")
|
||||
|
||||
# (2) A genex result containing a space stays double-quoted.
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"$<1:${d}/a b.cmake>")
|
||||
|
||||
# (3) A genex result containing '$' is forced to bracket form so CTest does not
|
||||
# perform a second-stage ${...} expansion. $<1:$> composes a literal '$'.
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"$<1:${d}/x$<1:$>y.cmake>")
|
||||
|
||||
# (4) A plain entry containing ${VAR} stays a raw, bare double-quoted include so
|
||||
# CTest still expands it at test time (must NOT be routed through Quote).
|
||||
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
|
||||
"${d}/lit_\${MY_VAR}.cmake")
|
||||
Reference in New Issue
Block a user