From 3bbe95f58a8fb83e56ca9023ef01b9e70b391b05 Mon Sep 17 00:00:00 2001 From: Bill Hoffman Date: Mon, 28 Aug 2017 18:25:13 -0400 Subject: Clean up iwyu code to not be one big if statement. This commit changes the internal -E__run_iwyu to be -E__run_co_compile. This is used for co-compile commands. These are tools that want to mirror the compiler. For each compiler invocation the tool will be invoked first. This started as a way to implement include what you use (iwyu), but has expanded to include cpplint, cppcheck and others. Likely there will be more in the future as well. This commit implements each one in its own function and provides a way to add additional ones in the future with less work. --- Source/cmMakefileExecutableTargetGenerator.cxx | 2 +- Source/cmMakefileLibraryTargetGenerator.cxx | 2 +- Source/cmMakefileTargetGenerator.cxx | 2 +- Source/cmNinjaNormalTargetGenerator.cxx | 2 +- Source/cmNinjaTargetGenerator.cxx | 2 +- Source/cmcmd.cxx | 507 ++++++++++++--------- Source/cmcmd.h | 19 + .../E___run_co_compile-bad-iwyu-result.txt | 1 + .../E___run_co_compile-bad-iwyu-stderr.txt | 2 + .../E___run_co_compile-no----result.txt | 1 + .../E___run_co_compile-no----stderr.txt | 1 + .../E___run_co_compile-no-cc-result.txt | 1 + .../E___run_co_compile-no-cc-stderr.txt | 1 + .../E___run_co_compile-no-iwyu-result.txt | 1 + .../E___run_co_compile-no-iwyu-stderr.txt | 5 + .../CommandLine/E___run_iwyu-bad-iwyu-result.txt | 1 - .../CommandLine/E___run_iwyu-bad-iwyu-stderr.txt | 2 - .../CommandLine/E___run_iwyu-no----result.txt | 1 - .../CommandLine/E___run_iwyu-no----stderr.txt | 1 - .../CommandLine/E___run_iwyu-no-cc-result.txt | 1 - .../CommandLine/E___run_iwyu-no-cc-stderr.txt | 1 - .../CommandLine/E___run_iwyu-no-iwyu-result.txt | 1 - .../CommandLine/E___run_iwyu-no-iwyu-stderr.txt | 1 - Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 8 +- Tests/RunCMake/Cppcheck/C-bad-Build-result.txt | 1 + Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt | 2 + Tests/RunCMake/Cppcheck/C-bad.cmake | 3 + Tests/RunCMake/Cppcheck/RunCMakeTest.cmake | 1 + Tests/RunCMake/pseudo_cppcheck.c | 13 +- 29 files changed, 339 insertions(+), 247 deletions(-) create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt delete mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt create mode 100644 Tests/RunCMake/Cppcheck/C-bad-Build-result.txt create mode 100644 Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt create mode 100644 Tests/RunCMake/Cppcheck/C-bad.cmake diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index b9b3c2f..e120e16 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -619,7 +619,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); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 2faef67..c863d28 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -939,7 +939,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); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c1cf103..11f3e88 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -637,7 +637,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); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index ddac20e..d49b07a 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -499,7 +499,7 @@ std::vector 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)); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index b08c19b..3733d35 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -623,7 +623,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); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 0791cb3..10d68df 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -34,11 +34,14 @@ #include "cmsys/Process.h" #include "cmsys/Terminal.h" #include +#include #include +#include #include #include #include #include +#include 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& orig_cmd) +{ + // Construct the iwyu command line by taking what was given + // and adding all the arguments we give to the compiler. + std::vector 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& 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 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&) +{ + // Construct the ldd -r -u (link what you use lwyu) command line + // ldd -u -r lwuy target + std::vector 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&) +{ + // Construct the cpplint command line. + std::vector 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& orig_cmd) +{ + // Construct the cpplint command line. + std::vector 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& args) +{ + // initialize a map from command option to handler function + std::map&)>> + 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 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 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::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& args) { // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx @@ -280,234 +557,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector& 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 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 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 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 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 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 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 diff --git a/Source/cmcmd.h b/Source/cmcmd.h index faac1d2..541fe05 100644 --- a/Source/cmcmd.h +++ b/Source/cmcmd.h @@ -18,7 +18,26 @@ public: */ static int ExecuteCMakeCommand(std::vector&); + // 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& orig_cmd); + static int HandleTidy(const std::string& runCmd, + const std::string& sourceFile, + const std::vector& orig_cmd); + static int HandleLWYU(const std::string& runCmd, + const std::string& sourceFile, + const std::vector& orig_cmd); + static int HandleCppLint(const std::string& runCmd, + const std::string& sourceFile, + const std::vector& orig_cmd); + static int HandleCppCheck(const std::string& runCmd, + const std::string& sourceFile, + const std::vector& orig_cmd); + protected: + static int HandleCoCompileCommands(std::vector& args); static int HashSumFile(std::vector& args, cmCryptoHash::Algo algo); static int SymlinkLibrary(std::vector& args); diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt new file mode 100644 index 0000000..338f7c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-bad-iwyu-stderr.txt @@ -0,0 +1,2 @@ +^Error running 'iwyu-does-not-exist': [^ +]+$ diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-no----result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt new file mode 100644 index 0000000..f0597d2 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-no----stderr.txt @@ -0,0 +1 @@ +^__run_co_compile given unknown argument: command-does-not-exist$ diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt new file mode 100644 index 0000000..bba846e --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-no-cc-stderr.txt @@ -0,0 +1 @@ +^__run_co_compile missing compile command after --$ diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt b/Tests/RunCMake/CommandLine/E___run_co_compile-no-iwyu-stderr.txt new file mode 100644 index 0000000..ffa1da8 --- /dev/null +++ b/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= diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt deleted file mode 100644 index 338f7c4..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt +++ /dev/null @@ -1,2 +0,0 @@ -^Error running 'iwyu-does-not-exist': [^ -]+$ diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt deleted file mode 100644 index c251adf..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt +++ /dev/null @@ -1 +0,0 @@ -^__run_iwyu given unknown argument: command-does-not-exist$ diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt deleted file mode 100644 index 1998abb..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt +++ /dev/null @@ -1 +0,0 @@ -^__run_iwyu missing compile command after --$ diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt deleted file mode 100644 index 9db95f8..0000000 --- a/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt +++ /dev/null @@ -1 +0,0 @@ -^__run_iwyu missing --cpplint=, --iwyu=, --lwyu=, --cppcheck= and/or --tidy=$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 6efcc12..55eac5e 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/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) diff --git a/Tests/RunCMake/Cppcheck/C-bad-Build-result.txt b/Tests/RunCMake/Cppcheck/C-bad-Build-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/Cppcheck/C-bad-Build-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt b/Tests/RunCMake/Cppcheck/C-bad-Build-stdout.txt new file mode 100644 index 0000000..2370ce1 --- /dev/null +++ b/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' diff --git a/Tests/RunCMake/Cppcheck/C-bad.cmake b/Tests/RunCMake/Cppcheck/C-bad.cmake new file mode 100644 index 0000000..920e4b4 --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/Cppcheck/RunCMakeTest.cmake b/Tests/RunCMake/Cppcheck/RunCMakeTest.cmake index ae14f8c..5fd4ead 100644 --- a/Tests/RunCMake/Cppcheck/RunCMakeTest.cmake +++ b/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) diff --git a/Tests/RunCMake/pseudo_cppcheck.c b/Tests/RunCMake/pseudo_cppcheck.c index 32e6e28..8667e5e 100644 --- a/Tests/RunCMake/pseudo_cppcheck.c +++ b/Tests/RunCMake/pseudo_cppcheck.c @@ -1,7 +1,18 @@ #include +#include +#include -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"); -- cgit v0.12