From 9cf3547e1cd56d42bc96c3dc3adf9f745faea5ee Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 2 Jul 2013 14:30:10 +0200 Subject: [PATCH] Add the INTERFACE_SYSTEM_INCLUDE_DIRECTORIES target property. Unlike other target properties, this does not have a corresponding non-INTERFACE variant. This allows propagation of system attribute on include directories from link dependents. --- Source/cmExportInstallFileGenerator.cxx | 4 ++ Source/cmGeneratorExpressionDAGChecker.cxx | 8 ++++ Source/cmGeneratorExpressionDAGChecker.h | 2 + Source/cmGeneratorExpressionEvaluator.cxx | 4 ++ Source/cmGeneratorTarget.cxx | 44 ++++++++++++++----- Source/cmGeneratorTarget.h | 2 + Source/cmGlobalGenerator.cxx | 11 +++++ Source/cmTarget.cxx | 44 +++++++++++++++++++ Source/cmTarget.h | 3 ++ Source/cmTargetIncludeDirectoriesCommand.cxx | 19 ++++++-- Source/cmTargetIncludeDirectoriesCommand.h | 8 ++++ Tests/IncludeDirectories/CMakeLists.txt | 17 +++++++ .../SystemIncludeDirectories/CMakeLists.txt | 19 ++++++++ .../SystemIncludeDirectories/consumer.cpp | 7 +++ .../SystemIncludeDirectories/systemlib.cpp | 4 ++ .../systemlib/systemlib.h | 19 ++++++++ .../SystemIncludeDirectories/upstream.cpp | 4 ++ .../SystemIncludeDirectories/upstream.h | 12 +++++ 18 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp create mode 100644 Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index a966b1605..43b17c602 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -126,6 +126,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateIncludeDirectoriesInterface(te, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, cmGeneratorExpression::InstallInterface, diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 5b79e3531..d04e19542 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -171,6 +171,14 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 ); } +//---------------------------------------------------------------------------- +bool +cmGeneratorExpressionDAGChecker::EvaluatingSystemIncludeDirectories() const +{ + const char *prop = this->Property.c_str(); + return strcmp(prop, "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") == 0; +} + //---------------------------------------------------------------------------- bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const { diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 95d466ae3..f0524f290 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -18,11 +18,13 @@ #define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \ F(EvaluatingIncludeDirectories) \ + F(EvaluatingSystemIncludeDirectories) \ F(EvaluatingCompileDefinitions) \ F(EvaluatingCompileOptions) #define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \ F(INTERFACE_INCLUDE_DIRECTORIES) \ + F(INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) \ F(INTERFACE_COMPILE_DEFINITIONS) \ F(INTERFACE_COMPILE_OPTIONS) diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 05bbc1ce8..53fb35d6e 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -879,6 +879,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode { interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES"; } + else if (propertyName == "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") + { + interfacePropertyName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"; + } else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS" || propertyName == "COMPILE_DEFINITIONS" || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 9167b25a3..5ce0e6be1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -51,21 +51,43 @@ const char *cmGeneratorTarget::GetProperty(const char *prop) bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, const char *config) { - for (std::set::const_iterator - it = this->Target->GetSystemIncludeDirectories().begin(); - it != this->Target->GetSystemIncludeDirectories().end(); ++it) + std::string config_upper; + if(config && *config) { - cmListFileBacktrace lfbt; - cmGeneratorExpression ge(lfbt); + config_upper = cmSystemTools::UpperCase(config); + } - std::vector incs; - cmSystemTools::ExpandListArgument(ge.Parse(*it) - ->Evaluate(this->Makefile, - config, false), incs); - if (std::find(incs.begin(), incs.end(), dir) != incs.end()) + typedef std::map > IncludeCacheType; + IncludeCacheType::iterator iter = + this->SystemIncludesCache.find(config_upper); + + if (iter == this->SystemIncludesCache.end()) + { + std::vector result; + for (std::set::const_iterator + it = this->Target->GetSystemIncludeDirectories().begin(); + it != this->Target->GetSystemIncludeDirectories().end(); ++it) { - return true; + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", 0, 0); + + cmSystemTools::ExpandListArgument(ge.Parse(*it) + ->Evaluate(this->Makefile, + config, false, this->Target, + &dagChecker), result); } + IncludeCacheType::value_type entry(config_upper, result); + iter = this->SystemIncludesCache.insert(entry).first; + } + + if (std::find(iter->second.begin(), + iter->second.end(), dir) != iter->second.end()) + { + return true; } return false; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index c0fd7726c..dedfa60aa 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -78,6 +78,8 @@ private: void ClassifySources(); void LookupObjectLibraries(); + std::map > SystemIncludesCache; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ad74767f7..2897114ab 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1001,6 +1001,17 @@ void cmGlobalGenerator::Generate() // it builds by default. this->FillLocalGeneratorToTargetMap(); + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + cmMakefile* mf = this->LocalGenerators[i]->GetMakefile(); + cmTargets* targets = &(mf->GetTargets()); + for ( cmTargets::iterator it = targets->begin(); + it != targets->end(); ++ it ) + { + it->second.FinalizeSystemIncludeDirectories(); + } + } + // Generate project files for (i = 0; i < this->LocalGenerators.size(); ++i) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 7ad42f826..806f77c34 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -842,6 +842,17 @@ void cmTarget::DefineProperties(cmake *cm) CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); + cm->DefineProperty + ("SYSTEM_INTERFACE_INCLUDE_DIRECTORIES", cmProperty::TARGET, + "List of public system include directories for a library.", + "Targets may populate this property to publish the include directories " + "which contain system headers, and therefore should not result in " + "compiler warnings. Consuming targets will then mark the same include " + "directories as system headers." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); + cm->DefineProperty ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, "List of public compile definitions for a library.", @@ -2555,6 +2566,39 @@ cmTarget::AddSystemIncludeDirectories(const std::vector &incs) } } +//---------------------------------------------------------------------------- +void cmTarget::FinalizeSystemIncludeDirectories() +{ + for (std::vector::const_iterator + it = this->Internal->LinkInterfacePropertyEntries.begin(), + end = this->Internal->LinkInterfacePropertyEntries.end(); + it != end; ++it) + { + { + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr cge = + ge.Parse(it->Value); + std::string targetName = cge->Evaluate(this->Makefile, 0, + false, this, 0, 0); + if (!this->Makefile->FindTargetToUse(targetName.c_str())) + { + continue; + } + } + std::string includeGenex = "$Value + ",INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>"; + if (cmGeneratorExpression::Find(it->Value) != std::string::npos) + { + // Because it->Value is a generator expression, ensure that it + // evaluates to the non-empty string before being used in the + // TARGET_PROPERTY expression. + includeGenex = "$<$Value + ">:" + includeGenex + ">"; + } + this->SystemIncludeDirectories.insert(includeGenex); + } +} + //---------------------------------------------------------------------------- void cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) diff --git a/Source/cmTarget.h b/Source/cmTarget.h index ff6d9235d..09cddaf45 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -538,6 +538,9 @@ public: void AddSystemIncludeDirectories(const std::vector &incs); std::set const & GetSystemIncludeDirectories() const { return this->SystemIncludeDirectories; } + + void FinalizeSystemIncludeDirectories(); + private: // The set of include directories that are marked as system include // directories. diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index ee915212c..e7b906c9e 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -84,10 +84,21 @@ void cmTargetIncludeDirectoriesCommand const std::vector &content, bool prepend, bool system) { - if (system) - { - // Error. - } cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend, system); + + if (system) + { + std::string joined; + std::string sep; + for(std::vector::const_iterator it = content.begin(); + it != content.end(); ++it) + { + joined += sep; + sep = ";"; + joined += *it; + } + tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", + joined.c_str()); + } } diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h index a84ddd0cd..29686183c 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.h +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -71,6 +71,14 @@ public: "The following arguments specify include directories. Specified " "include directories may be absolute paths or relative paths. " "Repeated calls for the same append items in the order called." + "If SYSTEM is specified, the compiler will be told the " + "directories are meant as system include directories on some " + "platforms (signalling this setting might achieve effects such as " + "the compiler skipping warnings, or these fixed-install system files " + "not being considered in dependency calculations - see compiler " + "docs). If SYSTEM is used together with PUBLIC or INTERFACE, the " + "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES target property will be " + "populated with the specified directories." "\n" "Arguments to target_include_directories may use \"generator " "expressions\" with the syntax \"$<...>\". " diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt index 3e3ecc90d..596a28066 100644 --- a/Tests/IncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/CMakeLists.txt @@ -1,6 +1,23 @@ cmake_minimum_required (VERSION 2.6) project(IncludeDirectories) +if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4) + OR CMAKE_C_COMPILER_ID STREQUAL Clang) + AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL "Ninja")) + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test) + if(run_sys_includes_test) + # The Bullseye wrapper appears to break the -isystem effect. + execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out) + if("x${out}" MATCHES "Bullseye") + set(run_sys_includes_test 0) + endif() + endif() + if (run_sys_includes_test) + add_subdirectory(SystemIncludeDirectories) + endif() +endif() + file(WRITE ${CMAKE_BINARY_DIR}/Flags/Flags.h "//Flags.h ") diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt new file mode 100644 index 000000000..aec6ff981 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt @@ -0,0 +1,19 @@ + +cmake_minimum_required(VERSION 2.8) + +project(SystemIncludeDirectories) + +add_library(systemlib systemlib.cpp) +target_include_directories(systemlib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/systemlib") + +add_library(upstream upstream.cpp) +target_link_libraries(upstream LINK_PUBLIC systemlib) +target_compile_options(upstream PRIVATE -Werror=unused-variable) + +target_include_directories(upstream SYSTEM PUBLIC + $ +) + +add_library(consumer consumer.cpp) +target_link_libraries(consumer upstream) +target_compile_options(consumer PRIVATE -Werror=unused-variable) diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp new file mode 100644 index 000000000..197dae86d --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp @@ -0,0 +1,7 @@ + +#include "upstream.h" + +int consumer() +{ + return upstream(); +} diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp new file mode 100644 index 000000000..f111bfa55 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp @@ -0,0 +1,4 @@ + +#include "systemlib.h" + +int systemlib() { return 0; } diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h new file mode 100644 index 000000000..c84de6a28 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/systemlib/systemlib.h @@ -0,0 +1,19 @@ + +#ifndef SYSTEMLIB_H +#define SYSTEMLIB_H + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int systemlib(); + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int unusedFunc() +{ + int unused; + return systemlib(); +} + +#endif diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp new file mode 100644 index 000000000..f716b99e6 --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp @@ -0,0 +1,4 @@ + +#include "upstream.h" + +int upstream() { return systemlib(); } diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h new file mode 100644 index 000000000..3628568cf --- /dev/null +++ b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h @@ -0,0 +1,12 @@ + +#ifndef UPSTREAM_H +#define UPSTREAM_H + +#include "systemlib.h" + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int upstream(); + +#endif