summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorCraig Scott <craig.scott@crascit.com>2024-09-30 11:13:13 (GMT)
committerCraig Scott <craig.scott@crascit.com>2024-10-02 00:09:11 (GMT)
commitfc7aa3cd69eee1cdb001e6a28f36ddd01cefe720 (patch)
tree7e65266786f0db5d5ba66f9a95d58c756f408b09 /Source
parent9f1703530bae90704cd4a096c14cfec4ab1e7cec (diff)
downloadCMake-fc7aa3cd69eee1cdb001e6a28f36ddd01cefe720.zip
CMake-fc7aa3cd69eee1cdb001e6a28f36ddd01cefe720.tar.gz
CMake-fc7aa3cd69eee1cdb001e6a28f36ddd01cefe720.tar.bz2
tests: Preserve empty arguments in test command lines
This will now preserve empty values in the TEST_LAUNCHER and CROSSCOMPILING_EMULATOR target properties for tests added by: - The add_test() command. - The ExternalData_Add_Test() command from the ExternalData module. - The gtest_add_tests() or gtest_discover_tests() commands from the GoogleTest module. For the gtest_add_tests() and gtest_discover_tests() commands, empty elements in the values passed after the EXTRA_ARGS keyword are also now preserved. Policy CMP0178 is added to provide backward compatibility with the old behavior where empty values were silently discarded from the above cases. Fixes: #26337
Diffstat (limited to 'Source')
-rw-r--r--Source/cmAddTestCommand.cxx48
-rw-r--r--Source/cmPolicies.h2
-rw-r--r--Source/cmTest.cxx1
-rw-r--r--Source/cmTest.h13
-rw-r--r--Source/cmTestGenerator.cxx27
5 files changed, 84 insertions, 7 deletions
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
index a0d5732..ff17e87 100644
--- a/Source/cmAddTestCommand.cxx
+++ b/Source/cmAddTestCommand.cxx
@@ -2,14 +2,19 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmAddTestCommand.h"
+#include <algorithm>
+
#include <cm/memory>
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
+#include "cmPolicies.h"
#include "cmStringAlgorithms.h"
#include "cmTest.h"
#include "cmTestGenerator.h"
+static std::string const keywordCMP0178 = "__CMP0178";
+
static bool cmAddTestCommandHandleNameMode(
std::vector<std::string> const& args, cmExecutionStatus& status);
@@ -29,8 +34,30 @@ bool cmAddTestCommand(std::vector<std::string> const& args,
}
cmMakefile& mf = status.GetMakefile();
+ cmPolicies::PolicyStatus cmp0178;
+
+ // If the __CMP0178 keyword is present, it is always at the end
+ auto endOfCommandIter =
+ std::find(args.begin() + 2, args.end(), keywordCMP0178);
+ if (endOfCommandIter != args.end()) {
+ auto cmp0178Iter = endOfCommandIter + 1;
+ if (cmp0178Iter == args.end()) {
+ status.SetError(cmStrCat(keywordCMP0178, " keyword missing value"));
+ return false;
+ }
+ if (*cmp0178Iter == "NEW") {
+ cmp0178 = cmPolicies::PolicyStatus::NEW;
+ } else if (*cmp0178Iter == "OLD") {
+ cmp0178 = cmPolicies::PolicyStatus::OLD;
+ } else {
+ cmp0178 = cmPolicies::PolicyStatus::WARN;
+ }
+ } else {
+ cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178);
+ }
+
// Collect the command with arguments.
- std::vector<std::string> command(args.begin() + 1, args.end());
+ std::vector<std::string> command(args.begin() + 1, endOfCommandIter);
// Create the test but add a generator only the first time it is
// seen. This preserves behavior from before test generators.
@@ -46,6 +73,7 @@ bool cmAddTestCommand(std::vector<std::string> const& args,
} else {
test = mf.CreateTest(args[0]);
test->SetOldStyle(true);
+ test->SetCMP0178(cmp0178);
mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test));
}
test->SetCommand(command);
@@ -56,11 +84,14 @@ bool cmAddTestCommand(std::vector<std::string> const& args,
bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
+ cmMakefile& mf = status.GetMakefile();
+
std::string name;
std::vector<std::string> configurations;
std::string working_directory;
std::vector<std::string> command;
bool command_expand_lists = false;
+ cmPolicies::PolicyStatus cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178);
// Read the arguments.
enum Doing
@@ -69,6 +100,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
DoingCommand,
DoingConfigs,
DoingWorkingDirectory,
+ DoingCmp0178,
DoingNone
};
Doing doing = DoingName;
@@ -91,6 +123,8 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
return false;
}
doing = DoingWorkingDirectory;
+ } else if (args[i] == keywordCMP0178) {
+ doing = DoingCmp0178;
} else if (args[i] == "COMMAND_EXPAND_LISTS") {
if (command_expand_lists) {
status.SetError(" may be given at most one COMMAND_EXPAND_LISTS.");
@@ -108,6 +142,15 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
} else if (doing == DoingWorkingDirectory) {
working_directory = args[i];
doing = DoingNone;
+ } else if (doing == DoingCmp0178) {
+ if (args[i] == "NEW") {
+ cmp0178 = cmPolicies::PolicyStatus::NEW;
+ } else if (args[i] == "OLD") {
+ cmp0178 = cmPolicies::PolicyStatus::OLD;
+ } else {
+ cmp0178 = cmPolicies::PolicyStatus::WARN;
+ }
+ doing = DoingNone;
} else {
status.SetError(cmStrCat(" given unknown argument:\n ", args[i], "\n"));
return false;
@@ -126,8 +169,6 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
return false;
}
- cmMakefile& mf = status.GetMakefile();
-
// Require a unique test name within the directory.
if (mf.GetTest(name)) {
status.SetError(cmStrCat(" given test NAME \"", name,
@@ -138,6 +179,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
// Add the test.
cmTest* test = mf.CreateTest(name);
test->SetOldStyle(false);
+ test->SetCMP0178(cmp0178);
test->SetCommand(command);
if (!working_directory.empty()) {
test->SetProperty("WORKING_DIRECTORY", working_directory);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 88ced3f..e2254fe 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -543,6 +543,8 @@ class cmMakefile;
SELECT(POLICY, CMP0176, "execute_process() ENCODING is UTF-8 by default.", \
3, 31, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0177, "install() DESTINATION paths are normalized.", 3, \
+ 31, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0178, "Test command lines preserve empty arguments.", 3, \
31, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
index 8a39144..c72e020 100644
--- a/Source/cmTest.cxx
+++ b/Source/cmTest.cxx
@@ -10,6 +10,7 @@
cmTest::cmTest(cmMakefile* mf)
: Backtrace(mf->GetBacktrace())
, PolicyStatusCMP0158(mf->GetPolicyStatus(cmPolicies::CMP0158))
+ , PolicyStatusCMP0178(mf->GetPolicyStatus(cmPolicies::CMP0178))
{
this->Makefile = mf;
this->OldStyle = true;
diff --git a/Source/cmTest.h b/Source/cmTest.h
index 480966a..244aa62 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -61,12 +61,22 @@ public:
bool GetOldStyle() const { return this->OldStyle; }
void SetOldStyle(bool b) { this->OldStyle = b; }
- /** Get/Set if CMP0158 policy is NEW */
+ /** Get if CMP0158 policy is NEW */
bool GetCMP0158IsNew() const
{
return this->PolicyStatusCMP0158 == cmPolicies::NEW;
}
+ /** Get/Set the CMP0178 policy setting */
+ cmPolicies::PolicyStatus GetCMP0178() const
+ {
+ return this->PolicyStatusCMP0178;
+ }
+ void SetCMP0178(cmPolicies::PolicyStatus p)
+ {
+ this->PolicyStatusCMP0178 = p;
+ }
+
/** Set/Get whether lists in command lines should be expanded. */
bool GetCommandExpandLists() const;
void SetCommandExpandLists(bool b);
@@ -82,4 +92,5 @@ private:
cmMakefile* Makefile;
cmListFileBacktrace Backtrace;
cmPolicies::PolicyStatus PolicyStatusCMP0158;
+ cmPolicies::PolicyStatus PolicyStatusCMP0178;
};
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 840d8cf..ffb5e21 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -174,15 +174,36 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
if (!cmNonempty(launcher)) {
return;
}
- cmList launcherWithArgs{ ge.Parse(*launcher)->Evaluate(this->LG,
- config) };
+ const auto propVal = ge.Parse(*launcher)->Evaluate(this->LG, config);
+ cmList launcherWithArgs(propVal, cmList::ExpandElements::Yes,
+ this->Test->GetCMP0178() == cmPolicies::NEW
+ ? cmList::EmptyElements::Yes
+ : cmList::EmptyElements::No);
if (!launcherWithArgs.empty() && !launcherWithArgs[0].empty()) {
+ if (this->Test->GetCMP0178() == cmPolicies::WARN) {
+ cmList argsWithEmptyValuesPreserved(
+ propVal, cmList::ExpandElements::Yes, cmList::EmptyElements::Yes);
+ if (launcherWithArgs != argsWithEmptyValuesPreserved) {
+ this->Test->GetMakefile()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat("The ", propertyName, " property of target '",
+ target->GetName(),
+ "' contains empty list items. Those empty items are "
+ "being silently discarded to preserve backward "
+ "compatibility.\n",
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0178)));
+ }
+ }
std::string launcherExe(launcherWithArgs[0]);
cmSystemTools::ConvertToUnixSlashes(launcherExe);
os << cmOutputConverter::EscapeForCMake(launcherExe) << " ";
for (std::string const& arg :
cmMakeRange(launcherWithArgs).advance(1)) {
- os << cmOutputConverter::EscapeForCMake(arg) << " ";
+ if (arg.empty()) {
+ os << "\"\" ";
+ } else {
+ os << cmOutputConverter::EscapeForCMake(arg) << " ";
+ }
}
}
};