From bf1a2de409655ec8c6e2d78354527c45f008cfb3 Mon Sep 17 00:00:00 2001 From: Tyler Yankee Date: Wed, 16 Sep 2026 19:38:35 -0400 Subject: [PATCH 1/2] cmCommonTargetGenerator: Improve style --- Source/cmCommonTargetGenerator.cxx | 46 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index acd3740a0d..11fb4c7c5f 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -150,7 +150,7 @@ std::string cmCommonTargetGenerator::GetFlags(std::string const& l, std::string const& config, std::string const& arch) { - std::string const key = config + arch; + std::string const key = cmStrCat(config, arch); auto i = this->Configs[key].FlagsByLanguage.find(l); if (i == this->Configs[key].FlagsByLanguage.end()) { @@ -364,8 +364,8 @@ std::string cmCommonTargetGenerator::GetManifests(std::string const& config) std::vector manifests; manifests.reserve(manifest_srcs.size()); - std::string lang = this->GeneratorTarget->GetLinkerLanguage(config); - std::string manifestFlag = this->Makefile->GetDefinition( + std::string const lang = this->GeneratorTarget->GetLinkerLanguage(config); + std::string const manifestFlag = this->Makefile->GetDefinition( cmStrCat("CMAKE_", lang, "_LINKER_MANIFEST_FLAG")); for (cmSourceFile const* manifest_src : manifest_srcs) { manifests.push_back(manifestFlag + @@ -397,7 +397,8 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags, char const* name, bool so) { // Lookup the flag to specify the version. - std::string fvar = cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG"); + std::string const fvar = + cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG"); cmValue flag = this->Makefile->GetDefinition(fvar); // Skip if no such flag. @@ -409,9 +410,9 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags, int major; int minor; int patch; - std::string prop = cmStrCat("MACHO_", name, "_VERSION"); - std::string fallback_prop = so ? "SOVERSION" : "VERSION"; - this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major, + std::string const prop = cmStrCat("MACHO_", name, "_VERSION"); + std::string const fallbackProp = so ? "SOVERSION" : "VERSION"; + this->GeneratorTarget->GetTargetVersionFallback(prop, fallbackProp, major, minor, patch); if (major > 0 || minor > 0 || patch > 0) { // Append the flag since a non-zero version is specified. @@ -427,13 +428,13 @@ std::string cmCommonTargetGenerator::GetCompilerLauncher( std::string compilerLauncher; if (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || lang == "HIP" || lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX") { - std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER"); - cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - std::string const evaluatedClauncher = cmGeneratorExpression::Evaluate( - *clauncher, this->GeneratorTarget->GetLocalGenerator(), config, + std::string const propName = cmStrCat(lang, "_COMPILER_LAUNCHER"); + cmValue cLauncherValue = this->GeneratorTarget->GetProperty(propName); + std::string const evaluatedCLauncher = cmGeneratorExpression::Evaluate( + *cLauncherValue, this->GeneratorTarget->GetLocalGenerator(), config, this->GeneratorTarget, nullptr, this->GeneratorTarget, lang); - if (!evaluatedClauncher.empty()) { - compilerLauncher = evaluatedClauncher; + if (!evaluatedCLauncher.empty()) { + compilerLauncher = evaluatedCLauncher; } } return compilerLauncher; @@ -444,7 +445,7 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules( std::string const& cmakeCmd, std::string const& config, std::function const& pathConverter) { - auto const lang = source.GetLanguage(); + std::string const lang = source.GetLanguage(); std::string tidy; std::string iwyu; std::string cpplint; @@ -453,11 +454,11 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules( std::string pvs; auto evaluateProp = [&](std::string const& prop) -> std::string { - auto const value = this->GeneratorTarget->GetProperty(prop); + cmValue const value = this->GeneratorTarget->GetProperty(prop); if (!value) { return std::string{}; } - auto evaluatedProp = cmGeneratorExpression::Evaluate( + std::string evaluatedProp = cmGeneratorExpression::Evaluate( *value, this->GeneratorTarget->GetLocalGenerator(), config, this->GeneratorTarget, nullptr, this->GeneratorTarget, lang); return evaluatedProp; @@ -529,12 +530,13 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules( driverMode = lang == "C" ? "gcc" : "g++"; } - auto const generatorName = this->GeneratorTarget->GetLocalGenerator() - ->GetGlobalGenerator() - ->GetName(); - auto const clangTidyExportFixedDir = + std::string const generatorName = + this->GeneratorTarget->GetLocalGenerator() + ->GetGlobalGenerator() + ->GetName(); + std::string const clangTidyExportFixedDir = this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang); - auto fixesFile = this->GetClangTidyReplacementsFilePath( + std::string fixesFile = this->GetClangTidyReplacementsFilePath( clangTidyExportFixedDir, source, config); std::string exportFixes; if (!clangTidyExportFixedDir.empty()) { @@ -715,7 +717,7 @@ void cmCommonTargetGenerator::ComputeRustFlagsForObjects( obj, cmOutputConverter::SHELL); } }; - for (auto const& obj : objects) { + for (std::string const& obj : objects) { processObject(obj); } linkCrates += rlibsArgs.str(); From 721eb8a5a2d56317944892e905875f14c861279f Mon Sep 17 00:00:00 2001 From: Tyler Yankee Date: Sun, 20 Sep 2026 10:11:55 -0400 Subject: [PATCH 2/2] cmCommonTargetGenerator: Improve launcher shell conversion Encapsulate the shell escaping logic in `cmCommonTargetGenerator` and represent launchers via a vector of strings (as is done with custom commands, execute process commands, etc.) to make them easier to work with. This facilitates work in a future commit which will reuse this pathway. Issue: #27598, #27402 --- Source/cmCommonTargetGenerator.cxx | 57 ++++++++++++------- Source/cmCommonTargetGenerator.h | 11 ++-- Source/cmFastbuildNormalTargetGenerator.cxx | 19 +++---- .../cmMakefileExecutableTargetGenerator.cxx | 4 +- Source/cmMakefileLibraryTargetGenerator.cxx | 4 +- Source/cmMakefileTargetGenerator.cxx | 13 +---- Source/cmNinjaNormalTargetGenerator.cxx | 3 +- Source/cmNinjaTargetGenerator.cxx | 12 +--- .../C-special-args-Build-stdout.txt | 1 + .../C-special-args-cppcheck-Build-stdout.txt | 1 + .../C-special-args-cppcheck.cmake | 3 + .../CompilerLauncher/C-special-args.cmake | 4 ++ .../CompilerLauncher/RunCMakeTest.cmake | 7 +++ .../CompilerLauncher/check-special-args.cmake | 41 +++++++++++++ .../C-special-args-build-check.cmake | 12 ++++ .../LinkerLauncher/C-special-args.cmake | 4 ++ .../LinkerLauncher/RunCMakeTest.cmake | 6 ++ .../LinkerLauncher/check-special-args.cmake | 42 ++++++++++++++ 18 files changed, 183 insertions(+), 61 deletions(-) create mode 100644 Tests/RunCMake/CompilerLauncher/C-special-args-Build-stdout.txt create mode 100644 Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck-Build-stdout.txt create mode 100644 Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck.cmake create mode 100644 Tests/RunCMake/CompilerLauncher/C-special-args.cmake create mode 100644 Tests/RunCMake/CompilerLauncher/check-special-args.cmake create mode 100644 Tests/RunCMake/LinkerLauncher/C-special-args-build-check.cmake create mode 100644 Tests/RunCMake/LinkerLauncher/C-special-args.cmake create mode 100644 Tests/RunCMake/LinkerLauncher/check-special-args.cmake diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 11fb4c7c5f..6e3d9cde95 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -8,6 +8,7 @@ #include #include +#include #include #include "cmComputeLinkInformation.h" @@ -422,10 +423,10 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags, } } -std::string cmCommonTargetGenerator::GetCompilerLauncher( +std::vector cmCommonTargetGenerator::GetCompilerLauncher( std::string const& lang, std::string const& config) { - std::string compilerLauncher; + std::vector compilerLauncher; if (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || lang == "HIP" || lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX") { std::string const propName = cmStrCat(lang, "_COMPILER_LAUNCHER"); @@ -434,14 +435,15 @@ std::string cmCommonTargetGenerator::GetCompilerLauncher( *cLauncherValue, this->GeneratorTarget->GetLocalGenerator(), config, this->GeneratorTarget, nullptr, this->GeneratorTarget, lang); if (!evaluatedCLauncher.empty()) { - compilerLauncher = evaluatedCLauncher; + cm::append(compilerLauncher, + cmList{ evaluatedCLauncher, cmList::EmptyElements::Yes }); } } return compilerLauncher; } std::string cmCommonTargetGenerator::GenerateCodeCheckRules( - cmSourceFile const& source, std::string& compilerLauncher, + cmSourceFile const& source, std::vector& compilerLauncher, std::string const& cmakeCmd, std::string const& config, std::function const& pathConverter) { @@ -488,11 +490,14 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules( std::string code_check = cmakeCmd + " -E __run_co_compile"; if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied - // via --launcher= and consumed + // via --launcher= and consumed + for (std::string& arg : compilerLauncher) { + cmSystemTools::ReplaceString(arg, ";", "\\;"); + } code_check = cmStrCat(std::move(code_check), " --launcher=", this->GeneratorTarget->GetLocalGenerator()->EscapeForShell( - compilerLauncher)); + cmJoin(compilerLauncher, ";"))); compilerLauncher.clear(); } if (cmNonempty(iwyu)) { @@ -639,32 +644,44 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules( return ""; } -std::string cmCommonTargetGenerator::GetLinkerLauncher( +std::vector cmCommonTargetGenerator::GetLinkerLauncher( std::string const& config) { - std::string lang = this->GeneratorTarget->GetLinkerLanguage(config); - std::string propName = lang + "_LINKER_LAUNCHER"; + std::vector linkLauncher; + std::string const lang = this->GeneratorTarget->GetLinkerLanguage(config); + std::string const propName = cmStrCat(lang, "_LINKER_LAUNCHER"); cmValue launcherProp = this->GeneratorTarget->GetProperty(propName); if (cmNonempty(launcherProp)) { cm::GenEx::Context context(this->LocalCommonGenerator, config, lang); cmGeneratorExpressionDAGChecker dagChecker{ this->GeneratorTarget, propName, nullptr, nullptr, context }; - std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate( + + std::string const evaluatedLinkLauncher = cmGeneratorExpression::Evaluate( *launcherProp, context.LG, context.Config, this->GeneratorTarget, &dagChecker, this->GeneratorTarget, context.Language); - // Convert ;-delimited list to single string - cmList args{ evaluatedLinklauncher, cmList::EmptyElements::Yes }; - if (!args.empty()) { - args[0] = this->LocalCommonGenerator->ConvertToOutputFormat( - args[0], cmOutputConverter::SHELL); - for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) { - i = this->LocalCommonGenerator->EscapeForShell(i); - } - return cmJoin(args, " "); + if (!evaluatedLinkLauncher.empty()) { + cm::append(linkLauncher, + cmList{ evaluatedLinkLauncher, cmList::EmptyElements::Yes }); } } - return std::string(); + return linkLauncher; +} + +std::string cmCommonTargetGenerator::ConvertLauncherToShell( + std::vector const& launcher) const +{ + if (launcher.empty()) { + return std::string{}; + } + + std::vector args = launcher; + args[0] = this->LocalCommonGenerator->ConvertToOutputFormat( + args[0], cmOutputConverter::SHELL); + for (std::string& arg : cmMakeRange(args.begin() + 1, args.end())) { + arg = this->LocalCommonGenerator->EscapeForShell(arg); + } + return cmJoin(args, " "); } bool cmCommonTargetGenerator::HaveRequiredLanguages( diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index d8fd69499d..74c4604f89 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -68,12 +68,12 @@ protected: std::string GetManifests(std::string const& config); std::string GetAIXExports(std::string const& config); std::string GenerateCodeCheckRules( - cmSourceFile const& source, std::string& compilerLauncher, + cmSourceFile const& source, std::vector& compilerLauncher, std::string const& cmakeCmd, std::string const& config, std::function const& pathConverter); - std::string GetCompilerLauncher(std::string const& lang, - std::string const& config); + std::vector GetCompilerLauncher(std::string const& lang, + std::string const& config); struct LinkedTargetDirs { @@ -85,7 +85,10 @@ protected: std::string const& config) const; std::string ComputeTargetCompilePDB(std::string const& config) const; - std::string GetLinkerLauncher(std::string const& config); + std::vector GetLinkerLauncher(std::string const& config); + + std::string ConvertLauncherToShell( + std::vector const& launcher) const; bool HaveRequiredLanguages(std::vector const& sources, std::set& languagesNeeded) const; diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx index db1640c06f..6c4eb6d5dd 100644 --- a/Source/cmFastbuildNormalTargetGenerator.cxx +++ b/Source/cmFastbuildNormalTargetGenerator.cxx @@ -822,11 +822,12 @@ void cmFastbuildNormalTargetGenerator::AddCompilerLaunchersForLanguages() this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE", Config); // See if we need to use a compiler launcher like ccache or distcc for (std::string const& language : Languages) { - std::string const compilerLauncher = + std::vector expanded = cmCommonTargetGenerator::GetCompilerLauncher(language, Config); - LogMessage("compilerLauncher: " + compilerLauncher); - std::vector expanded; - cmExpandList(compilerLauncher, expanded); + LogMessage("compilerLauncher: " + cmJoin(expanded, ";")); + // FIXME(#27402): Empty arguments are not supported here. + expanded.erase(std::remove(expanded.begin(), expanded.end(), ""), + expanded.end()); if (!expanded.empty()) { std::string const exe = expanded[0]; @@ -844,14 +845,8 @@ void cmFastbuildNormalTargetGenerator::AddCompilerLaunchersForLanguages() } void cmFastbuildNormalTargetGenerator::AddLinkerLauncher() { - std::string const linkerLauncher = + std::vector args = cmCommonTargetGenerator::GetLinkerLauncher(Config); - std::vector args; -#ifdef _WIN32 - cmSystemTools::ParseWindowsCommandLine(linkerLauncher.c_str(), args); -#else - cmSystemTools::ParseUnixCommandLine(linkerLauncher.c_str(), args); -#endif if (!args.empty()) { std::string const exe = std::move(args[0]); args.erase(args.begin()); @@ -1191,7 +1186,7 @@ std::string cmFastbuildNormalTargetGenerator::ComputeCodeCheckOptions( if (skipCodeCheck) { return {}; } - std::string compilerLauncher; + std::vector compilerLauncher; std::string staticCheckRule = this->GenerateCodeCheckRules( srcFile, compilerLauncher, "", Config, nullptr); LogMessage(cmStrCat("CodeCheck: ", staticCheckRule)); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 77c040fef5..5bbaabe118 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -592,8 +592,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.LinkFlags = linkFlags.c_str(); vars.Manifests = manifests.c_str(); - std::string linkerLauncher = - this->GetLinkerLauncher(this->GetConfigName()); + std::string const linkerLauncher = this->ConvertLauncherToShell( + this->GetLinkerLauncher(this->GetConfigName())); if (cmNonempty(linkerLauncher)) { vars.Launcher = linkerLauncher.c_str(); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 9991868351..133e18423d 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -876,8 +876,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.LanguageCompileFlags = langFlags.c_str(); - std::string linkerLauncher = - this->GetLinkerLauncher(this->GetConfigName()); + std::string const linkerLauncher = this->ConvertLauncherToShell( + this->GetLinkerLauncher(this->GetConfigName())); if (cmNonempty(linkerLauncher)) { vars.Launcher = linkerLauncher.c_str(); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7cddd65f8f..4779ab1e34 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1106,7 +1106,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } // See if we need to use a compiler launcher like ccache or distcc - std::string compilerLauncher; + std::vector compilerLauncher; if (!compileCommands.empty()) { compilerLauncher = GetCompilerLauncher(lang, config); } @@ -1131,15 +1131,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // If compiler launcher was specified and not consumed above, it // goes to the beginning of the command line. if (!compileCommands.empty() && !compilerLauncher.empty()) { - cmList args{ compilerLauncher, cmList::EmptyElements::Yes }; - if (!args.empty()) { - args[0] = this->LocalGenerator->ConvertToOutputFormat( - args[0], cmOutputConverter::SHELL); - for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) { - i = this->LocalGenerator->EscapeForShell(i); - } - } - compileCommands.front().insert(0, args.join(" ") + " "); + compileCommands.front().insert( + 0, cmStrCat(this->ConvertLauncherToShell(compilerLauncher), ' ')); } std::string launcher; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 8a569188a3..c4c0b3db26 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -584,7 +584,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule( vars.LanguageCompileFlags = langFlags.c_str(); } - std::string linkerLauncher = this->GetLinkerLauncher(config); + std::string const linkerLauncher = + this->ConvertLauncherToShell(this->GetLinkerLauncher(config)); if (cmNonempty(linkerLauncher)) { vars.Launcher = linkerLauncher.c_str(); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index dece6cb8c2..f985d395df 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -47,7 +47,6 @@ #include "cmNinjaUtilityTargetGenerator.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmSourceFileLocationKind.h" @@ -1598,15 +1597,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // If compiler launcher was specified and not consumed above, it // goes to the beginning of the command line. if (!compilerLauncher.empty()) { - cmList args{ compilerLauncher, cmList::EmptyElements::Yes }; - if (!args.empty()) { - args[0] = this->LocalGenerator->ConvertToOutputFormat( - args[0], cmOutputConverter::SHELL); - for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) { - i = this->LocalGenerator->EscapeForShell(i); - } - vars["LAUNCHER"] = args.join(" ") + " "; - } + vars["LAUNCHER"] = + cmStrCat(this->ConvertLauncherToShell(compilerLauncher), ' '); } if (this->GetMakefile()->GetSafeDefinition( diff --git a/Tests/RunCMake/CompilerLauncher/C-special-args-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/C-special-args-Build-stdout.txt new file mode 100644 index 0000000000..be1afe7a9c --- /dev/null +++ b/Tests/RunCMake/CompilerLauncher/C-special-args-Build-stdout.txt @@ -0,0 +1 @@ +special-args launcher ok: compile diff --git a/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck-Build-stdout.txt new file mode 100644 index 0000000000..be1afe7a9c --- /dev/null +++ b/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck-Build-stdout.txt @@ -0,0 +1 @@ +special-args launcher ok: compile diff --git a/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck.cmake b/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck.cmake new file mode 100644 index 0000000000..602bf0d73a --- /dev/null +++ b/Tests/RunCMake/CompilerLauncher/C-special-args-cppcheck.cmake @@ -0,0 +1,3 @@ +# Lint tools run the launcher through "cmake -E __run_co_compile --launcher=...". +set(CMAKE_C_CPPCHECK "${CMAKE_COMMAND};-E;true") +include(C-special-args.cmake) diff --git a/Tests/RunCMake/CompilerLauncher/C-special-args.cmake b/Tests/RunCMake/CompilerLauncher/C-special-args.cmake new file mode 100644 index 0000000000..c4521b6e45 --- /dev/null +++ b/Tests/RunCMake/CompilerLauncher/C-special-args.cmake @@ -0,0 +1,4 @@ +set(check "${CMAKE_CURRENT_LIST_DIR}/check-special-args.cmake") +set(CMAKE_C_COMPILER_LAUNCHER + "${CMAKE_COMMAND};-P;${check};--;compile;;semi\\;colon;with space") +include(C-common.cmake) diff --git a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake index 16a42ce238..519f072f54 100644 --- a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake +++ b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake @@ -51,3 +51,10 @@ foreach(lang ${langs}) run_compiler_launcher_env(${lang}-launch-env) endif() endforeach() + +if(NOT RunCMake_GENERATOR MATCHES "FASTBuild") + # FIXME(#27402): FASTBuild builds its launcher command line without shell + # quoting, so it can't handle empty or special-character arguments. + run_compiler_launcher(C-special-args) + run_compiler_launcher(C-special-args-cppcheck) +endif() diff --git a/Tests/RunCMake/CompilerLauncher/check-special-args.cmake b/Tests/RunCMake/CompilerLauncher/check-special-args.cmake new file mode 100644 index 0000000000..930aa8bb06 --- /dev/null +++ b/Tests/RunCMake/CompilerLauncher/check-special-args.cmake @@ -0,0 +1,41 @@ +# Verifies that the launcher's own arguments arrive intact, then runs the +# launched command. + +set(base 4) # CMAKE_ARGV0..3 are: cmake -P