diff options
31 files changed, 214 insertions, 8 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 02d164b..615254e 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/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 diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index e6c966b..bd02f8b 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/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 diff --git a/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst b/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst new file mode 100644 index 0000000..26f6d16 --- /dev/null +++ b/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. diff --git a/Help/release/dev/run-include-what-you-use.rst b/Help/release/dev/run-include-what-you-use.rst new file mode 100644 index 0000000..baac21f --- /dev/null +++ b/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. diff --git a/Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst b/Help/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE.rst new file mode 100644 index 0000000..2c8028a --- /dev/null +++ b/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``. diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake index 73ad86e..5938d6c 100644 --- a/Modules/CheckTypeSize.cmake +++ b/Modules/CheckTypeSize.cmake @@ -82,7 +82,7 @@ include(CheckIncludeFile) include(CheckIncludeFileCXX) cmake_policy(PUSH) -cmake_policy(VERSION 3.0) +cmake_policy(SET CMP0054 NEW) get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) @@ -112,9 +112,9 @@ function(__check_type_size_impl type var map builtin language) # Perform the check. - if("${language}" STREQUAL "C") + if(language STREQUAL "C") set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.c) - elseif("${language}" STREQUAL "CXX") + elseif(language STREQUAL "CXX") set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.cpp) else() message(FATAL_ERROR "Unknown language:\n ${language}\nSupported languages: C, CXX.\n") @@ -229,11 +229,11 @@ macro(CHECK_TYPE_SIZE TYPE VARIABLE) set(_builtin 0) else() set(_builtin 1) - if("${_language}" STREQUAL "C") + if(_language STREQUAL "C") check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stddef.h HAVE_STDDEF_H) - elseif("${_language}" STREQUAL "CXX") + elseif(_language STREQUAL "CXX") check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H) check_include_file_cxx(stdint.h HAVE_STDINT_H) check_include_file_cxx(stddef.h HAVE_STDDEF_H) diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake index 27f8a82..70c3fd7 100644 --- a/Modules/FortranCInterface.cmake +++ b/Modules/FortranCInterface.cmake @@ -144,9 +144,8 @@ if(FortranCInterface_SOURCE_DIR) return() endif() -# Use CMake 2.8.0 behavior for this module regardless of including context. cmake_policy(PUSH) -cmake_policy(VERSION 2.8.0) +cmake_policy(SET CMP0007 NEW) #----------------------------------------------------------------------------- # Verify that C and Fortran are available. diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 060aedd..54779a5 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 2) -set(CMake_VERSION_PATCH 20150519) +set(CMake_VERSION_PATCH 20150521) #set(CMake_VERSION_RC 1) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 9afe09c..0c8acc7 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/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, diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index cdc9cc8..879d6b7 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/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); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 8feb7a5..70005b4 100644 --- a/Source/cmTarget.cxx +++ b/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); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 3400625..3ea2186 100644 --- a/Source/cmcmd.cxx +++ b/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" ) { diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 16fb056..2100b55 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/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() 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 0000000..d00491f --- /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 0000000..338f7c4 --- /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 0000000..d00491f --- /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 0000000..c251adf --- /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 0000000..d00491f --- /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 0000000..1998abb --- /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 0000000..d00491f --- /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 0000000..0024097 --- /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 644e5ae..69beed9 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) diff --git a/Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt b/Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt new file mode 100644 index 0000000..cb74677 --- /dev/null +++ b/Tests/RunCMake/IncludeWhatYouUse/C-Build-stdout.txt @@ -0,0 +1,4 @@ +Warning: include-what-you-use reported diagnostics: +should add these lines: +* +#include <\.\.\.> diff --git a/Tests/RunCMake/IncludeWhatYouUse/C.cmake b/Tests/RunCMake/IncludeWhatYouUse/C.cmake new file mode 100644 index 0000000..f400e86 --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt b/Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt new file mode 100644 index 0000000..18dfd26 --- /dev/null +++ b/Tests/RunCMake/IncludeWhatYouUse/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.2) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt b/Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt new file mode 100644 index 0000000..cb74677 --- /dev/null +++ b/Tests/RunCMake/IncludeWhatYouUse/CXX-Build-stdout.txt @@ -0,0 +1,4 @@ +Warning: include-what-you-use reported diagnostics: +should add these lines: +* +#include <\.\.\.> diff --git a/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake b/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake new file mode 100644 index 0000000..896930c --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/IncludeWhatYouUse/RunCMakeTest.cmake b/Tests/RunCMake/IncludeWhatYouUse/RunCMakeTest.cmake new file mode 100644 index 0000000..68c6bd7 --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/IncludeWhatYouUse/main.c b/Tests/RunCMake/IncludeWhatYouUse/main.c new file mode 100644 index 0000000..78f2de1 --- /dev/null +++ b/Tests/RunCMake/IncludeWhatYouUse/main.c @@ -0,0 +1 @@ +int main(void) { return 0; } diff --git a/Tests/RunCMake/IncludeWhatYouUse/main.cxx b/Tests/RunCMake/IncludeWhatYouUse/main.cxx new file mode 100644 index 0000000..76e8197 --- /dev/null +++ b/Tests/RunCMake/IncludeWhatYouUse/main.cxx @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/Tests/RunCMake/pseudo_iwyu.c b/Tests/RunCMake/pseudo_iwyu.c new file mode 100644 index 0000000..1e25de7 --- /dev/null +++ b/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; +} |