From 67fa3da9e84888029d128280f35a8e7b3d208377 Mon Sep 17 00:00:00 2001 From: Bill Hoffman Date: Thu, 14 May 2015 13:31:32 -0400 Subject: [PATCH] cmake: Add internal -E mode to run include-what-you-use with the compiler Add an internal "cmake -E __run_iwyu" mode to wrap the compiler call. Run a given include-what-you-use command line with the compiler options and report a warning if it finds anything. Then run the real compiler. Co-Author: Brad King --- Source/cmcmd.cxx | 82 +++++++++++++++++++ .../E___run_iwyu-bad-iwyu-result.txt | 1 + .../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 + .../E___run_iwyu-no-iwyu-result.txt | 1 + .../E___run_iwyu-no-iwyu-stderr.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 5 ++ 10 files changed, 96 insertions(+) create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt create mode 100644 Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 12bb8ee5e..50254ffc4 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -211,6 +211,88 @@ int cmcmd::ExecuteCMakeCommand(std::vector& args) return 0; } + // 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. + else if (args[1] == "__run_iwyu") + { + if (args.size() < 3) + { + std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]" + " -- compile command\n"; + return 1; + } + bool doing_options = true; + std::vector orig_cmd; + std::string iwyu; + 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) + { + std::cerr << "__run_iwyu given unknown argument: " << arg << "\n"; + return 1; + } + else + { + orig_cmd.push_back(arg); + } + } + if (iwyu.empty()) + { + std::cerr << "__run_iwyu missing --iwyu=\n"; + return 1; + } + if (orig_cmd.empty()) + { + std::cerr << "__run_iwyu missing compile command after --\n"; + return 1; + } + + // 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. + int ret = 0; + std::string stdErr; + if(!cmSystemTools::RunSingleCommand(iwyu_cmd, 0, &stdErr, &ret, + 0, 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:") != stdErr.npos + || stdErr.find("should add these lines:") != stdErr.npos) + { + std::cerr << "Warning: include-what-you-use reported diagnostics:\n" + << stdErr << "\n"; + } + + // Now run the real compiler command and return its result value. + if(!cmSystemTools::RunSingleCommand(orig_cmd, 0, &stdErr, &ret, 0, + cmSystemTools::OUTPUT_PASSTHROUGH)) + { + std::cerr << "Error running '" << orig_cmd[0] << "': " + << stdErr << "\n"; + return 1; + } + return ret; + } + // Echo string else if (args[1] == "echo" ) { diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..338f7c4e6 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt @@ -0,0 +1,2 @@ +^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 new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt b/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt new file mode 100644 index 000000000..c251adf00 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt @@ -0,0 +1 @@ +^__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 new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..1998abb22 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt @@ -0,0 +1 @@ +^__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 new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..002409748 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt @@ -0,0 +1 @@ +^__run_iwyu missing --iwyu=$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 644e5ae99..69beed932 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -12,6 +12,11 @@ run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append) run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename) run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate) +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(G_no-arg ${CMAKE_COMMAND} -G) run_cmake_command(G_bad-arg ${CMAKE_COMMAND} -G NoSuchGenerator) run_cmake_command(P_no-arg ${CMAKE_COMMAND} -P)