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
This commit is contained in:
Ilya A. Kriveshko
2018-02-22 08:01:07 -05:00
committed by Brad King
parent 020be379f4
commit eaf9f69d41
3 changed files with 70 additions and 36 deletions

View File

@@ -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=<maybe-list> 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<std::string> 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<std::string> 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;

View File

@@ -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=<maybe-list> 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<std::string> 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<std::string> 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()) {

View File

@@ -359,7 +359,8 @@ struct CoCompileJob
int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
{
std::vector<CoCompileJob> jobs;
std::string sourceFile; // store --source=
std::string sourceFile; // store --source=
std::vector<std::string> 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<std::string>& 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<std::string>& 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,