From eaf9f69d41961353bf0fc9d63c543f957692d714 Mon Sep 17 00:00:00 2001 From: "Ilya A. Kriveshko" Date: Thu, 22 Feb 2018 08:01:07 -0500 Subject: Fix combined use of compiler launcher with lint tools When using ccache with clang-tidy, ccache needs to wrap compiler invocation, rather than cmake invocation. But it needs to do it without affecting the command line that iwyu-like tools are receiving. With this fix, if __run_co_compile is used, compile launcher is passed using the new --launcher option, but if __run_co_compile is not needed, compiler launcher is prepended to the command line as before. To better illustrate the change: with this fix if running clang-tidy with CXX_COMPILER_LAUNCHER set to "/usr/bin/time;-p;ccache" (time -p added strictly for illustration purposes), the command line changes from: /usr/bin/time -p ccache cmake -E __run_co_compile \ --tidy=clang-tidy ... -- g++ ... to: cmake -E __run_co_compile \ --launcher="/usr/bin/time;-p;ccache" \ --tidy=clang-tidy ... -- g++ ... This allows the compiler to be run via the launcher, but leaves tidy (& friends) invocations unaffected. Fixes: #16493 --- Source/cmMakefileTargetGenerator.cxx | 41 ++++++++++++++++++++++++------------ Source/cmNinjaTargetGenerator.cxx | 39 ++++++++++++++++++++++------------ Source/cmcmd.cxx | 26 +++++++++++++++-------- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 73cf1f0..abe5ff3 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -643,6 +643,18 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( source.GetFullPath(), workingDirectory, compileCommand); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || + lang == "Fortran" || lang == "CUDA")) { + std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + const char* clauncher = + this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -656,6 +668,13 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher= and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); @@ -682,21 +701,15 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } - // Maybe insert a compiler launcher like ccache or distcc - if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || - lang == "Fortran" || lang == "CUDA")) { - std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; - const char* clauncher = - this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - std::vector launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCommands.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCommands.empty() && !compilerLauncher.empty()) { + std::vector args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCommands.front().insert(0, cmJoin(args, " ") + " "); } std::string launcher; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f4faf47..60c5a65 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -653,6 +653,17 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) cmSystemTools::ExpandListArgument(compileCmd, compileCmds); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + if (!compileCmds.empty() && + (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { + std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -668,6 +679,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); run_iwyu += " -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher= and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu); @@ -693,20 +711,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } } - // Maybe insert a compiler launcher like ccache or distcc - if (!compileCmds.empty() && - (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { - std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; - const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - std::vector launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCmds.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCmds.empty() && !compilerLauncher.empty()) { + std::vector args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCmds.front().insert(0, cmJoin(args, " ") + " "); } if (!compileCmds.empty()) { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index e7d92d4..6f3a90f 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -359,7 +359,8 @@ struct CoCompileJob int cmcmd::HandleCoCompileCommands(std::vector& args) { std::vector jobs; - std::string sourceFile; // store --source= + std::string sourceFile; // store --source= + std::vector launchers; // store --launcher= // Default is to run the original command found after -- if the option // does not need to do that, it should be specified here, currently only @@ -390,15 +391,17 @@ int cmcmd::HandleCoCompileCommands(std::vector& args) } } } - if (cmHasLiteralPrefix(arg, "--source=")) { - sourceFile = arg.substr(9); - optionFound = true; - } - // if it was not a co-compiler or --source then error if (!optionFound) { - std::cerr << "__run_co_compile given unknown argument: " << arg - << "\n"; - return 1; + if (cmHasLiteralPrefix(arg, "--source=")) { + sourceFile = arg.substr(9); + } else if (cmHasLiteralPrefix(arg, "--launcher=")) { + cmSystemTools::ExpandListArgument(arg.substr(11), launchers, true); + } else { + // if it was not a co-compiler or --source/--launcher then error + std::cerr << "__run_co_compile given unknown argument: " << arg + << "\n"; + return 1; + } } } else { // if not doing_options then push to orig_cmd orig_cmd.push_back(arg); @@ -436,6 +439,11 @@ int cmcmd::HandleCoCompileCommands(std::vector& args) return 0; } + // Prepend launcher argument(s), if any + if (!launchers.empty()) { + orig_cmd.insert(orig_cmd.begin(), launchers.begin(), launchers.end()); + } + // Now run the real compiler command and return its result value int ret; if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret, -- cgit v0.12