Browse Source

Merge topic 'run-include-what-you-use'

ada5ffce Add options to run include-what-you-use with the compiler
67fa3da9 cmake: Add internal -E mode to run include-what-you-use with the compiler
Brad King 10 years ago
parent
commit
03a65dab30
28 changed files with 207 additions and 0 deletions
  1. 1 0
      Help/manual/cmake-properties.7.rst
  2. 1 0
      Help/manual/cmake-variables.7.rst
  3. 13 0
      Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst
  4. 8 0
      Help/release/dev/run-include-what-you-use.rst
  5. 6 0
      Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst
  6. 14 0
      Source/cmMakefileTargetGenerator.cxx
  7. 17 0
      Source/cmNinjaTargetGenerator.cxx
  8. 2 0
      Source/cmTarget.cxx
  9. 82 0
      Source/cmcmd.cxx
  10. 5 0
      Tests/RunCMake/CMakeLists.txt
  11. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-result.txt
  12. 2 0
      Tests/RunCMake/CommandLine/E___run_iwyu-bad-iwyu-stderr.txt
  13. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no----result.txt
  14. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no----stderr.txt
  15. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-result.txt
  16. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no-cc-stderr.txt
  17. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-result.txt
  18. 1 0
      Tests/RunCMake/CommandLine/E___run_iwyu-no-iwyu-stderr.txt
  19. 5 0
      Tests/RunCMake/CommandLine/RunCMakeTest.cmake
  20. 4 0
      Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt
  21. 3 0
      Tests/RunCMake/IncludeWhatYouUse/C.cmake
  22. 3 0
      Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt
  23. 4 0
      Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt
  24. 3 0
      Tests/RunCMake/IncludeWhatYouUse/CXX.cmake
  25. 18 0
      Tests/RunCMake/IncludeWhatYouUse/RunCMakeTest.cmake
  26. 1 0
      Tests/RunCMake/IncludeWhatYouUse/main.c
  27. 1 0
      Tests/RunCMake/IncludeWhatYouUse/main.cxx
  28. 7 0
      Tests/RunCMake/pseudo_iwyu.c

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -177,6 +177,7 @@ Properties on Targets
    /prop_tgt/JOB_POOL_COMPILE
    /prop_tgt/JOB_POOL_LINK
    /prop_tgt/LABELS
+   /prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
    /prop_tgt/LANG_VISIBILITY_PRESET
    /prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG
    /prop_tgt/LIBRARY_OUTPUT_DIRECTORY

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -235,6 +235,7 @@ Variables that Control the Build
    /variable/CMAKE_INSTALL_NAME_DIR
    /variable/CMAKE_INSTALL_RPATH
    /variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
+   /variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
    /variable/CMAKE_LANG_VISIBILITY_PRESET
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG

+ 13 - 0
Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst

@@ -0,0 +1,13 @@
+<LANG>_INCLUDE_WHAT_YOU_USE
+---------------------------
+
+This property is implemented only when ``<LANG>`` is ``C`` or ``CXX``.
+
+Specify a :ref:`;-list <CMake Language Lists>` containing a command
+line for the ``include-what-you-use`` tool.  The :ref:`Makefile Generators`
+and the :generator:`Ninja` generator will run this tool along with the
+compiler and report a warning if the tool reports any problems.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE` variable if it is set
+when a target is created.

+ 8 - 0
Help/release/dev/run-include-what-you-use.rst

@@ -0,0 +1,8 @@
+run-include-what-you-use
+------------------------
+
+* The :ref:`Makefile Generators` and the :generator:`Ninja` generator
+  learned to optionally run ``include-what-you-use`` along with the
+  compiler for ``C`` and ``CXX`` languages.  See the
+  :variable:`CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE` variable and
+  :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` target property for details.

+ 6 - 0
Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst

@@ -0,0 +1,6 @@
+CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE
+---------------------------------
+
+Default value for :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` target property.
+This variable is used to initialize the property on each target as it is
+created.  This is done only when ``<LANG>`` is ``C`` or ``CXX``.

+ 14 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -768,6 +768,20 @@ cmMakefileTargetGenerator
     this->LocalGenerator->ExpandRuleVariables(*i, vars);
     }
 
+  // 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";
+    const char *iwyu = this->Target->GetProperty(iwyu_prop);
+    if (iwyu && *iwyu)
+      {
+      std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu --iwyu=";
+      run_iwyu += this->LocalGenerator->EscapeForShell(iwyu);
+      run_iwyu += " -- ";
+      compileCommands.front().insert(0, run_iwyu);
+      }
+    }
+
   // Change the command working directory to the local build tree.
   this->LocalGenerator->CreateCDCommand
     (compileCommands,

+ 17 - 0
Source/cmNinjaTargetGenerator.cxx

@@ -458,6 +458,23 @@ cmNinjaTargetGenerator
   std::vector<std::string> compileCmds;
   cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
 
+  // 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";
+    const char *iwyu = this->Target->GetProperty(iwyu_prop);
+    if (iwyu && *iwyu)
+      {
+      std::string run_iwyu =
+        this->GetLocalGenerator()->ConvertToOutputFormat(
+          cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+      run_iwyu += " -E __run_iwyu --iwyu=";
+      run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
+      run_iwyu += " -- ";
+      compileCmds.front().insert(0, run_iwyu);
+      }
+    }
+
   if (!compileCmds.empty())
     {
     compileCmds.front().insert(0, cldeps);

+ 2 - 0
Source/cmTarget.cxx

@@ -333,9 +333,11 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     this->SetPropertyDefault("MACOSX_BUNDLE", 0);
     this->SetPropertyDefault("MACOSX_RPATH", 0);
     this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0);
+    this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0);
     this->SetPropertyDefault("C_STANDARD", 0);
     this->SetPropertyDefault("C_STANDARD_REQUIRED", 0);
     this->SetPropertyDefault("C_EXTENSIONS", 0);
+    this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", 0);
     this->SetPropertyDefault("CXX_STANDARD", 0);
     this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0);
     this->SetPropertyDefault("CXX_EXTENSIONS", 0);

+ 82 - 0
Source/cmcmd.cxx

@@ -211,6 +211,88 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& 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<std::string> 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<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.
+      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" )
       {

+ 5 - 0
Tests/RunCMake/CMakeLists.txt

@@ -241,3 +241,8 @@ if(CMAKE_OSX_ARCHITECTURES AND XCODE AND NOT "${XCODE_VERSION}" MATCHES "^[^12]"
     PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CFG_INTDIR}"
     )
 endif()
+
+if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
+  add_executable(pseudo_iwyu pseudo_iwyu.c)
+  add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
+endif()

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

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

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

@@ -0,0 +1,2 @@
+^Error running 'iwyu-does-not-exist': [^
+]+$

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1 @@
+^__run_iwyu missing --iwyu=$

+ 5 - 0
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)

+ 4 - 0
Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt

@@ -0,0 +1,4 @@
+Warning: include-what-you-use reported diagnostics:
+should add these lines:
+*
+#include <\.\.\.>

+ 3 - 0
Tests/RunCMake/IncludeWhatYouUse/C.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args)
+add_executable(main main.c)

+ 3 - 0
Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.2)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 4 - 0
Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt

@@ -0,0 +1,4 @@
+Warning: include-what-you-use reported diagnostics:
+should add these lines:
+*
+#include <\.\.\.>

+ 3 - 0
Tests/RunCMake/IncludeWhatYouUse/CXX.cmake

@@ -0,0 +1,3 @@
+enable_language(CXX)
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args)
+add_executable(main main.cxx)

+ 18 - 0
Tests/RunCMake/IncludeWhatYouUse/RunCMakeTest.cmake

@@ -0,0 +1,18 @@
+include(RunCMake)
+
+set(RunCMake_TEST_OPTIONS "-DPSEUDO_IWYU=${PSEUDO_IWYU}")
+
+function(run_iwyu lang)
+  # Use a single build tree for tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${lang}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake(${lang})
+
+  set(RunCMake_TEST_OUTPUT_MERGE 1)
+  run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build .)
+endfunction()
+
+run_iwyu(C)
+run_iwyu(CXX)

+ 1 - 0
Tests/RunCMake/IncludeWhatYouUse/main.c

@@ -0,0 +1 @@
+int main(void) { return 0; }

+ 1 - 0
Tests/RunCMake/IncludeWhatYouUse/main.cxx

@@ -0,0 +1 @@
+int main() { return 0; }

+ 7 - 0
Tests/RunCMake/pseudo_iwyu.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  fprintf(stderr, "should add these lines:\n#include <...>\n");
+  return 0;
+}