Просмотр исходного кода

Merge topic 'refactor-iwyu-code'

3bbe95f5 Clean up iwyu code to not be one big if statement.

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1247
Brad King 8 лет назад
Родитель
Сommit
c0c5f924fe
24 измененных файлов с 333 добавлено и 241 удалено
  1. 1 1
      Source/cmMakefileExecutableTargetGenerator.cxx
  2. 1 1
      Source/cmMakefileLibraryTargetGenerator.cxx
  3. 1 1
      Source/cmMakefileTargetGenerator.cxx
  4. 1 1
      Source/cmNinjaNormalTargetGenerator.cxx
  5. 1 1
      Source/cmNinjaTargetGenerator.cxx
  6. 279 228
      Source/cmcmd.cxx
  7. 19 0
      Source/cmcmd.h
  8. 0 0
      Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt
  9. 0 0
      Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt
  10. 0 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt
  11. 1 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt
  12. 0 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt
  13. 1 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt
  14. 0 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt
  15. 5 0
      Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt
  16. 0 1
      Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt
  17. 0 1
      Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt
  18. 0 1
      Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt
  19. 4 4
      Tests/RunCMake/CommandLine/RunCMakeTest.cmake
  20. 1 0
      Tests/RunCMake/Cppcheck/C-bad-Build-result.txt
  21. 2 0
      Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt
  22. 3 0
      Tests/RunCMake/Cppcheck/C-bad.cmake
  23. 1 0
      Tests/RunCMake/Cppcheck/RunCMakeTest.cmake
  24. 12 1
      Tests/RunCMake/pseudo_cppcheck.c

+ 1 - 1
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -618,7 +618,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
       std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat(
         cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
-      cmakeCommand += " -E __run_iwyu --lwyu=";
+      cmakeCommand += " -E __run_co_compile --lwyu=";
       cmakeCommand += targetOutPathReal;
       real_link_commands.push_back(cmakeCommand);
     }

+ 1 - 1
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -932,7 +932,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
           (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY)) {
         std::string cmakeCommand = this->LocalGenerator->ConvertToOutputFormat(
           cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
-        cmakeCommand += " -E __run_iwyu --lwyu=";
+        cmakeCommand += " -E __run_co_compile --lwyu=";
         cmakeCommand += targetOutPathReal;
         real_link_commands.push_back(cmakeCommand);
       }

+ 1 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -629,7 +629,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
       const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
       if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) ||
           (cppcheck && *cppcheck)) {
-        std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu";
+        std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile";
         if (iwyu && *iwyu) {
           run_iwyu += " --iwyu=";
           run_iwyu += this->LocalGenerator->EscapeForShell(iwyu);

+ 1 - 1
Source/cmNinjaNormalTargetGenerator.cxx

@@ -495,7 +495,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
         std::string cmakeCommand =
           this->GetLocalGenerator()->ConvertToOutputFormat(
             cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
-        cmakeCommand += " -E __run_iwyu --lwyu=";
+        cmakeCommand += " -E __run_co_compile --lwyu=";
         cmGeneratorTarget& gt = *this->GetGeneratorTarget();
         const std::string cfgName = this->GetConfigName();
         std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));

+ 1 - 1
Source/cmNinjaTargetGenerator.cxx

@@ -619,7 +619,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
         (cppcheck && *cppcheck)) {
       std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
         cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
-      run_iwyu += " -E __run_iwyu";
+      run_iwyu += " -E __run_co_compile";
       if (iwyu && *iwyu) {
         run_iwyu += " --iwyu=";
         run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);

+ 279 - 228
Source/cmcmd.cxx

@@ -34,11 +34,14 @@
 #include "cmsys/Process.h"
 #include "cmsys/Terminal.h"
 #include <algorithm>
+#include <functional>
 #include <iostream>
+#include <map>
 #include <sstream>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
+#include <utility>
 
 class cmConnection;
 
@@ -157,6 +160,280 @@ static bool cmTarFilesFrom(std::string const& file,
   return true;
 }
 
+int cmcmd::HandleIWYU(const std::string& runCmd, const std::string&,
+                      const std::vector<std::string>& orig_cmd)
+{
+  // Construct the iwyu command line by taking what was given
+  // and adding all the arguments we give to the compiler.
+  std::vector<std::string> iwyu_cmd;
+  cmSystemTools::ExpandListArgument(runCmd, iwyu_cmd, true);
+  iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin() + 1, orig_cmd.end());
+  // Run the iwyu command line.  Capture its stderr and hide its stdout.
+  // Ignore its return code because the tool always returns non-zero.
+  std::string stdErr;
+  int ret;
+  if (!cmSystemTools::RunSingleCommand(iwyu_cmd, nullptr, &stdErr, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr << "\n";
+    return 1;
+  }
+  // Warn if iwyu reported anything.
+  if (stdErr.find("should remove these lines:") != std::string::npos ||
+      stdErr.find("should add these lines:") != std::string::npos) {
+    std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
+              << stdErr << "\n";
+  }
+  // always return 0 we don't want to break the compile
+  return 0;
+}
+
+int cmcmd::HandleTidy(const std::string& runCmd, const std::string& sourceFile,
+                      const std::vector<std::string>& orig_cmd)
+{
+  // Construct the clang-tidy command line by taking what was given
+  // and adding our compiler command line.  The clang-tidy tool will
+  // automatically skip over the compiler itself and extract the
+  // options.
+  int ret;
+  std::vector<std::string> tidy_cmd;
+  cmSystemTools::ExpandListArgument(runCmd, tidy_cmd, true);
+  tidy_cmd.push_back(sourceFile);
+  tidy_cmd.push_back("--");
+  tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin(), orig_cmd.end());
+
+  // Run the tidy command line.  Capture its stdout and hide its stderr.
+  std::string stdOut;
+  std::string stdErr;
+  if (!cmSystemTools::RunSingleCommand(tidy_cmd, &stdOut, &stdErr, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << tidy_cmd[0] << "': " << stdErr << "\n";
+    return 1;
+  }
+  // Output the stdout from clang-tidy to stderr
+  std::cerr << stdOut;
+  // If clang-tidy exited with an error do the same.
+  if (ret != 0) {
+    std::cerr << stdErr;
+  }
+  return ret;
+}
+
+int cmcmd::HandleLWYU(const std::string& runCmd, const std::string&,
+                      const std::vector<std::string>&)
+{
+  // Construct the ldd -r -u (link what you use lwyu) command line
+  // ldd -u -r lwuy target
+  std::vector<std::string> lwyu_cmd;
+  lwyu_cmd.push_back("ldd");
+  lwyu_cmd.push_back("-u");
+  lwyu_cmd.push_back("-r");
+  lwyu_cmd.push_back(runCmd);
+
+  // Run the ldd -u -r command line.
+  // Capture its stdout and hide its stderr.
+  // Ignore its return code because the tool always returns non-zero
+  // if there are any warnings, but we just want to warn.
+  std::string stdOut;
+  std::string stdErr;
+  int ret;
+  if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, &stdErr, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << lwyu_cmd[0] << "': " << stdErr << "\n";
+    return 1;
+  }
+
+  // Output the stdout from ldd -r -u to stderr
+  // Warn if lwyu reported anything.
+  if (stdOut.find("Unused direct dependencies:") != std::string::npos) {
+    std::cerr << "Warning: " << stdOut;
+  }
+  return 0;
+}
+
+int cmcmd::HandleCppLint(const std::string& runCmd,
+                         const std::string& sourceFile,
+                         const std::vector<std::string>&)
+{
+  // Construct the cpplint command line.
+  std::vector<std::string> cpplint_cmd;
+  cmSystemTools::ExpandListArgument(runCmd, cpplint_cmd, true);
+  cpplint_cmd.push_back(sourceFile);
+
+  // Run the cpplint command line.  Capture its output.
+  std::string stdOut;
+  int ret;
+  if (!cmSystemTools::RunSingleCommand(cpplint_cmd, &stdOut, &stdOut, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << cpplint_cmd[0] << "': " << stdOut
+              << "\n";
+    return 1;
+  }
+
+  // Output the output from cpplint to stderr
+  std::cerr << stdOut;
+  return ret;
+}
+
+int cmcmd::HandleCppCheck(const std::string& runCmd,
+                          const std::string& sourceFile,
+                          const std::vector<std::string>& orig_cmd)
+{
+  // Construct the cpplint command line.
+  std::vector<std::string> cppcheck_cmd;
+  cmSystemTools::ExpandListArgument(runCmd, cppcheck_cmd, true);
+  // extract all the -D, -U, and -I options from the compile line
+  for (size_t i = 0; i < orig_cmd.size(); i++) {
+    const std::string& opt = orig_cmd[i];
+    if (opt.size() > 2) {
+      if ((opt[0] == '-') &&
+          ((opt[1] == 'D') || (opt[1] == 'I') || (opt[1] == 'U'))) {
+        cppcheck_cmd.push_back(opt);
+// convert cl / options to - options if needed
+#if defined(_WIN32)
+      } else if ((opt[0] == '/') &&
+                 ((opt[1] == 'D') || (opt[1] == 'I') || (opt[1] == 'U'))) {
+        std::string optcopy = opt;
+        optcopy[0] = '-';
+        cppcheck_cmd.push_back(optcopy);
+#endif
+      }
+    }
+  }
+  // add the source file
+  cppcheck_cmd.push_back(sourceFile);
+
+  // Run the cpplint command line.  Capture its output.
+  std::string stdOut;
+  std::string stdErr;
+  int ret;
+  if (!cmSystemTools::RunSingleCommand(cppcheck_cmd, &stdOut, &stdErr, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << cppcheck_cmd[0] << "': " << stdOut
+              << "\n";
+    return 1;
+  }
+  std::cerr << stdOut;
+  // Output the output from cpplint to stderr
+  if (stdErr.find("(error)") != std::string::npos ||
+      stdErr.find("(warning)") != std::string::npos ||
+      stdErr.find("(style)") != std::string::npos ||
+      stdErr.find("(performance)") != std::string::npos ||
+      stdErr.find("(portability)") != std::string::npos ||
+      stdErr.find("(information)") != std::string::npos) {
+    std::cerr << "Warning: cppcheck reported diagnostics:\n";
+  }
+  std::cerr << stdErr;
+  // ignore errors so build continues
+  return 0;
+}
+
+// called when args[0] == "__run_co_compile"
+int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
+{
+  // initialize a map from command option to handler function
+  std::map<std::string,
+           std::function<int(const std::string&, const std::string&,
+                             const std::vector<std::string>&)>>
+    coCompileTypes;
+  auto a1 = std::placeholders::_1;
+  auto a2 = std::placeholders::_2;
+  auto a3 = std::placeholders::_3;
+  // create a map from option to handler function for option
+  // if the option does not call the original command then it will need
+  // to set runOriginalCmd to false later in this function
+  coCompileTypes["--iwyu="] = std::bind(&cmcmd::HandleIWYU, a1, a2, a3);
+  coCompileTypes["--tidy="] = std::bind(&cmcmd::HandleTidy, a1, a2, a3);
+  coCompileTypes["--lwyu="] = std::bind(&cmcmd::HandleLWYU, a1, a2, a3);
+  coCompileTypes["--cpplint="] = std::bind(&cmcmd::HandleCppLint, a1, a2, a3);
+  coCompileTypes["--cppcheck="] =
+    std::bind(&cmcmd::HandleCppCheck, a1, a2, a3);
+  // copy the command options to a vector of strings
+  std::vector<std::string> commandOptions;
+  for (const auto& i : coCompileTypes) {
+    commandOptions.push_back(i.first);
+  }
+
+  std::string runCmd;       // command to be run from --thing=command
+  std::string sourceFile;   // store --source=
+  std::string commandFound; // the command that was in the args list
+  std::vector<std::string> orig_cmd;
+  bool doing_options = true;
+  for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+    std::string const& arg = args[cc];
+    // if the arg is -- then the rest of the args after
+    // go into orig_cmd
+    if (arg == "--") {
+      doing_options = false;
+    } else if (doing_options) {
+      bool optionFound = false;
+      // check arg against all the commandOptions
+      for (std::vector<std::string>::size_type i = 0;
+           i < commandOptions.size(); ++i) {
+        const std::string& command = commandOptions[i];
+        if (arg.compare(0, command.size(), command) == 0) {
+          optionFound = true;
+          runCmd = arg.substr(command.size());
+          commandFound = command;
+        }
+      }
+      // check arg with --source=
+      if (cmHasLiteralPrefix(arg, "--source=")) {
+        sourceFile = arg.substr(9);
+        optionFound = true;
+      }
+      // if it was not a commandOptions or --source then error
+      if (!optionFound) {
+        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);
+    }
+  }
+  if (commandFound.empty()) {
+    std::cerr << "__run_co_compile missing command to run. Looking for one of "
+                 "the following:\n";
+    for (const auto& i : commandOptions) {
+      std::cerr << i << "\n";
+    }
+    return 1;
+  }
+  // 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
+  // lwyu does that.
+  bool runOriginalCmd = true;
+  if (commandFound == "--lwyu=") {
+    runOriginalCmd = false;
+  }
+  if (runOriginalCmd && orig_cmd.empty()) {
+    std::cerr << "__run_co_compile missing compile command after --\n";
+    return 1;
+  }
+
+  // call the command handler here
+  int ret = coCompileTypes[commandFound](runCmd, sourceFile, orig_cmd);
+  // if the command returns non-zero then return and fail.
+  // for commands that do not want to break the build, they should return
+  // 0 no matter what.
+  if (ret != 0) {
+    return ret;
+  }
+  // if there is no original command to run return now
+  if (!runOriginalCmd) {
+    return ret;
+  }
+  // Now run the real compiler command and return its result value
+  if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret,
+                                       nullptr,
+                                       cmSystemTools::OUTPUT_PASSTHROUGH)) {
+    std::cerr << "Error running '" << orig_cmd[0] << "'\n";
+    return 1;
+  }
+  // return the return value from the original compiler command
+  return ret;
+}
+
 int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
 {
   // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
@@ -280,234 +557,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
       return 0;
     }
 #endif
-    // run include what you use command and then run the compile
-    // command. This is an internal undocumented option and should
-    // only be used by CMake itself when running iwyu.
-    if (args[1] == "__run_iwyu") {
-      if (args.size() < 3) {
-        std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]"
-                     " [--cpplint=/path/cpplint] [--tidy=/path/tidy]"
-                     " -- compile command\n";
-        return 1;
-      }
-      bool doing_options = true;
-      std::vector<std::string> orig_cmd;
-      std::string iwyu;
-      std::string tidy;
-      std::string sourceFile;
-      std::string lwyu;
-      std::string cpplint;
-      std::string cppcheck;
-      for (std::string::size_type cc = 2; cc < args.size(); cc++) {
-        std::string const& arg = args[cc];
-        if (arg == "--") {
-          doing_options = false;
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--iwyu=")) {
-          iwyu = arg.substr(7);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--tidy=")) {
-          tidy = arg.substr(7);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--source=")) {
-          sourceFile = arg.substr(9);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--lwyu=")) {
-          lwyu = arg.substr(7);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--cpplint=")) {
-          cpplint = arg.substr(10);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "--cppcheck=")) {
-          cppcheck = arg.substr(11);
-        } else if (doing_options) {
-          std::cerr << "__run_iwyu given unknown argument: " << arg << "\n";
-          return 1;
-        } else {
-          orig_cmd.push_back(arg);
-        }
-      }
-      if (tidy.empty() && iwyu.empty() && lwyu.empty() && cpplint.empty() &&
-          cppcheck.empty()) {
-        std::cerr << "__run_iwyu missing --cpplint=, --iwyu=, --lwyu=, "
-                     "--cppcheck= and/or --tidy=\n";
-        return 1;
-      }
-      if ((!cpplint.empty() || !tidy.empty() || !cppcheck.empty()) &&
-          sourceFile.empty()) {
-        std::cerr << "__run_iwyu --cpplint=, __run_iwyu --tidy="
-                     ", __run_iwyu --cppcheck require --source=\n";
-        return 1;
-      }
-      if (orig_cmd.empty() && lwyu.empty()) {
-        std::cerr << "__run_iwyu missing compile command after --\n";
-        return 1;
-      }
-
-      int ret = 0;
-
-      if (!iwyu.empty()) {
-        // Construct the iwyu command line by taking what was given
-        // and adding all the arguments we give to the compiler.
-        std::vector<std::string> iwyu_cmd;
-        cmSystemTools::ExpandListArgument(iwyu, iwyu_cmd, true);
-        iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin() + 1, orig_cmd.end());
-
-        // Run the iwyu command line.  Capture its stderr and hide its stdout.
-        // Ignore its return code because the tool always returns non-zero.
-        std::string stdErr;
-        if (!cmSystemTools::RunSingleCommand(iwyu_cmd, nullptr, &stdErr, &ret,
-                                             nullptr,
-                                             cmSystemTools::OUTPUT_NONE)) {
-          std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr
-                    << "\n";
-          return 1;
-        }
-
-        // Warn if iwyu reported anything.
-        if (stdErr.find("should remove these lines:") != std::string::npos ||
-            stdErr.find("should add these lines:") != std::string::npos) {
-          std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
-                    << stdErr << "\n";
-        }
-      }
-
-      if (!tidy.empty()) {
-        // Construct the clang-tidy command line by taking what was given
-        // and adding our compiler command line.  The clang-tidy tool will
-        // automatically skip over the compiler itself and extract the
-        // options.
-        std::vector<std::string> tidy_cmd;
-        cmSystemTools::ExpandListArgument(tidy, tidy_cmd, true);
-        tidy_cmd.push_back(sourceFile);
-        tidy_cmd.push_back("--");
-        tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin(), orig_cmd.end());
-
-        // Run the tidy command line.  Capture its stdout and hide its stderr.
-        std::string stdOut;
-        std::string stdErr;
-        if (!cmSystemTools::RunSingleCommand(tidy_cmd, &stdOut, &stdErr, &ret,
-                                             nullptr,
-                                             cmSystemTools::OUTPUT_NONE)) {
-          std::cerr << "Error running '" << tidy_cmd[0] << "': " << stdErr
-                    << "\n";
-          return 1;
-        }
-        // Output the stdout from clang-tidy to stderr
-        std::cerr << stdOut;
-        // If clang-tidy exited with an error do the same.
-        if (ret != 0) {
-          std::cerr << stdErr;
-          return ret;
-        }
-      }
-      if (!lwyu.empty()) {
-        // Construct the ldd -r -u (link what you use lwyu) command line
-        // ldd -u -r lwuy target
-        std::vector<std::string> lwyu_cmd;
-        lwyu_cmd.push_back("ldd");
-        lwyu_cmd.push_back("-u");
-        lwyu_cmd.push_back("-r");
-        lwyu_cmd.push_back(lwyu);
-
-        // Run the ldd -u -r command line.
-        // Capture its stdout and hide its stderr.
-        // Ignore its return code because the tool always returns non-zero
-        // if there are any warnings, but we just want to warn.
-        std::string stdOut;
-        std::string stdErr;
-        if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, &stdErr, &ret,
-                                             nullptr,
-                                             cmSystemTools::OUTPUT_NONE)) {
-          std::cerr << "Error running '" << lwyu_cmd[0] << "': " << stdErr
-                    << "\n";
-          return 1;
-        }
-
-        // Output the stdout from ldd -r -u to stderr
-        // Warn if lwyu reported anything.
-        if (stdOut.find("Unused direct dependencies:") != std::string::npos) {
-          std::cerr << "Warning: " << stdOut;
-        }
-      }
-
-      if (!cpplint.empty()) {
-        // Construct the cpplint command line.
-        std::vector<std::string> cpplint_cmd;
-        cmSystemTools::ExpandListArgument(cpplint, cpplint_cmd, true);
-        cpplint_cmd.push_back(sourceFile);
-
-        // Run the cpplint command line.  Capture its output.
-        std::string stdOut;
-        if (!cmSystemTools::RunSingleCommand(cpplint_cmd, &stdOut, &stdOut,
-                                             &ret, nullptr,
-                                             cmSystemTools::OUTPUT_NONE)) {
-          std::cerr << "Error running '" << cpplint_cmd[0] << "': " << stdOut
-                    << "\n";
-          return 1;
-        }
-
-        // Output the output from cpplint to stderr
-        std::cerr << stdOut;
-
-        // If cpplint exited with an error do the same.
-        if (ret != 0) {
-          return ret;
-        }
-      }
-
-      if (!cppcheck.empty()) {
-        // Construct the cpplint command line.
-        std::vector<std::string> cppcheck_cmd;
-        cmSystemTools::ExpandListArgument(cppcheck, cppcheck_cmd, true);
-        // extract all the -D, -U, and -I options from the compile line
-        for (size_t i = 0; i < orig_cmd.size(); i++) {
-          std::string& opt = orig_cmd[i];
-          if (opt.size() > 2) {
-            if ((opt[0] == '-') &&
-                ((opt[1] == 'D') || (opt[1] == 'I') || (opt[1] == 'U'))) {
-              cppcheck_cmd.push_back(opt);
-#if defined(_WIN32)
-            } else if ((opt[0] == '/') &&
-                       ((opt[1] == 'D') || (opt[1] == 'I') ||
-                        (opt[1] == 'U'))) {
-              std::string optcopy = opt;
-              optcopy[0] = '-';
-              cppcheck_cmd.push_back(optcopy);
-#endif
-            }
-          }
-        }
-        // add the source file
-        cppcheck_cmd.push_back(sourceFile);
-
-        // Run the cpplint command line.  Capture its output.
-        std::string stdOut;
-        if (!cmSystemTools::RunSingleCommand(cppcheck_cmd, &stdOut, &stdOut,
-                                             &ret, nullptr,
-                                             cmSystemTools::OUTPUT_NONE)) {
-          std::cerr << "Error running '" << cppcheck_cmd[0] << "': " << stdOut
-                    << "\n";
-          return 1;
-        }
-        // Output the output from cpplint to stderr
-        if (stdOut.find("(error)") != std::string::npos ||
-            stdOut.find("(warning)") != std::string::npos ||
-            stdOut.find("(style)") != std::string::npos ||
-            stdOut.find("(performance)") != std::string::npos ||
-            stdOut.find("(portability)") != std::string::npos ||
-            stdOut.find("(information)") != std::string::npos) {
-          std::cerr << "Warning: cppcheck reported diagnostics:\n";
-        }
-        std::cerr << stdOut;
-      }
-      // ignore the cppcheck error code because it is likely to have them
-      // from bad -D stuff
-      ret = 0;
-      // Now run the real compiler command and return its result value
-      // unless we are lwyu
-      if (lwyu.empty() &&
-          !cmSystemTools::RunSingleCommand(
-            orig_cmd, nullptr, nullptr, &ret, nullptr,
-            cmSystemTools::OUTPUT_PASSTHROUGH)) {
-        std::cerr << "Error running '" << orig_cmd[0] << "'\n";
-        return 1;
-      }
-      return ret;
+    if (args[1] == "__run_co_compile") {
+      return cmcmd::HandleCoCompileCommands(args);
     }
 
     // Echo string

+ 19 - 0
Source/cmcmd.h

@@ -18,7 +18,26 @@ public:
    */
   static int ExecuteCMakeCommand(std::vector<std::string>&);
 
+  // define co-compile command handlers they must be public
+  // because they are used in a std::function map
+  static int HandleIWYU(const std::string& runCmd,
+                        const std::string& sourceFile,
+                        const std::vector<std::string>& orig_cmd);
+  static int HandleTidy(const std::string& runCmd,
+                        const std::string& sourceFile,
+                        const std::vector<std::string>& orig_cmd);
+  static int HandleLWYU(const std::string& runCmd,
+                        const std::string& sourceFile,
+                        const std::vector<std::string>& orig_cmd);
+  static int HandleCppLint(const std::string& runCmd,
+                           const std::string& sourceFile,
+                           const std::vector<std::string>& orig_cmd);
+  static int HandleCppCheck(const std::string& runCmd,
+                            const std::string& sourceFile,
+                            const std::vector<std::string>& orig_cmd);
+
 protected:
+  static int HandleCoCompileCommands(std::vector<std::string>& args);
   static int HashSumFile(std::vector<std::string>& args,
                          cmCryptoHash::Algo algo);
   static int SymlinkLibrary(std::vector<std::string>& args);

+ 0 - 0
Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt → Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt


+ 0 - 0
Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt → Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt


+ 0 - 0
Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt → Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt


+ 1 - 0
Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt

@@ -0,0 +1 @@
+^__run_co_compile given unknown argument: command-does-not-exist$

+ 0 - 0
Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt → Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt


+ 1 - 0
Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt

@@ -0,0 +1 @@
+^__run_co_compile missing compile command after --$

+ 0 - 0
Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt → Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt


+ 5 - 0
Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt

@@ -0,0 +1,5 @@
+^__run_co_compile missing command to run. Looking for one of the following:
+.*--cppcheck=
+.*--cpplint=
+.*--iwyu=
+.*--tidy=

+ 0 - 1
Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt

@@ -1 +0,0 @@
-^__run_iwyu given unknown argument: command-does-not-exist$

+ 0 - 1
Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt

@@ -1 +0,0 @@
-^__run_iwyu missing compile command after --$

+ 0 - 1
Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt

@@ -1 +0,0 @@
-^__run_iwyu missing --cpplint=, --iwyu=, --lwyu=, --cppcheck= and/or --tidy=$

+ 4 - 4
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -21,10 +21,10 @@ run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate)
 run_cmake_command(E_time ${CMAKE_COMMAND} -E time ${CMAKE_COMMAND} -E echo "hello  world")
 run_cmake_command(E_time-no-arg ${CMAKE_COMMAND} -E time)
 
-run_cmake_command(E___run_iwyu-no-iwyu ${CMAKE_COMMAND} -E __run_iwyu -- command-does-not-exist)
-run_cmake_command(E___run_iwyu-bad-iwyu ${CMAKE_COMMAND} -E __run_iwyu --iwyu=iwyu-does-not-exist -- command-does-not-exist)
-run_cmake_command(E___run_iwyu-no--- ${CMAKE_COMMAND} -E __run_iwyu --iwyu=iwyu-does-not-exist command-does-not-exist)
-run_cmake_command(E___run_iwyu-no-cc ${CMAKE_COMMAND} -E __run_iwyu --iwyu=iwyu-does-not-exist --)
+run_cmake_command(E___run_co_compile-no-iwyu ${CMAKE_COMMAND} -E __run_co_compile -- command-does-not-exist)
+run_cmake_command(E___run_co_compile-bad-iwyu ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist -- command-does-not-exist)
+run_cmake_command(E___run_co_compile-no--- ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist command-does-not-exist)
+run_cmake_command(E___run_co_compile-no-cc ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist --)
 
 run_cmake_command(G_no-arg ${CMAKE_COMMAND} -G)
 run_cmake_command(G_bad-arg ${CMAKE_COMMAND} -G NoSuchGenerator)

+ 1 - 0
Tests/RunCMake/Cppcheck/C-bad-Build-result.txt

@@ -0,0 +1 @@
+0

+ 2 - 0
Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt

@@ -0,0 +1,2 @@
+stdout from bad command line arg '-bad'
+stderr from bad command line arg '-bad'

+ 3 - 0
Tests/RunCMake/Cppcheck/C-bad.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+set(CMAKE_C_CPPCHECK "${PSEUDO_CPPCHECK}" -bad)
+add_executable(main main.c)

+ 1 - 0
Tests/RunCMake/Cppcheck/RunCMakeTest.cmake

@@ -15,6 +15,7 @@ endfunction()
 
 run_cppcheck(C)
 run_cppcheck(CXX)
+run_cppcheck(C-bad)
 
 if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
   run_cppcheck(C-launch)

+ 12 - 1
Tests/RunCMake/pseudo_cppcheck.c

@@ -1,7 +1,18 @@
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-int main(void)
+int main(int argc, char* argv[])
 {
+  int i;
+  for (i = 1; i < argc; ++i) {
+    if (strcmp(argv[i], "-bad") == 0)
+      if (strcmp(argv[i], "-bad") == 0) {
+        fprintf(stdout, "stdout from bad command line arg '-bad'\n");
+        fprintf(stderr, "stderr from bad command line arg '-bad'\n");
+        return 1;
+      }
+  }
   fprintf(stderr,
           "[/foo/bar.c:2]: (error) Array 'abc[10]' accessed at index 12,"
           " which is out of bounds.\n");