Browse Source

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.
Stephen Kelly 12 years ago
parent
commit
9cf3547e1c

+ 4 - 0
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,

+ 8 - 0
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
 {

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

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

+ 33 - 11
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<cmStdString>::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);
+    }
+
+  typedef std::map<std::string, std::vector<std::string> > IncludeCacheType;
+  IncludeCacheType::iterator iter =
+      this->SystemIncludesCache.find(config_upper);
 
-    std::vector<std::string> incs;
-    cmSystemTools::ExpandListArgument(ge.Parse(*it)
-                                       ->Evaluate(this->Makefile,
-                                                  config, false), incs);
-    if (std::find(incs.begin(), incs.end(), dir) != incs.end())
+  if (iter == this->SystemIncludesCache.end())
+    {
+    std::vector<std::string> result;
+    for (std::set<cmStdString>::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;
 }

+ 2 - 0
Source/cmGeneratorTarget.h

@@ -78,6 +78,8 @@ private:
   void ClassifySources();
   void LookupObjectLibraries();
 
+  std::map<std::string, std::vector<std::string> > SystemIncludesCache;
+
   cmGeneratorTarget(cmGeneratorTarget const&);
   void operator=(cmGeneratorTarget const&);
 };

+ 11 - 0
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)
     {

+ 44 - 0
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<std::string> &incs)
     }
 }
 
+//----------------------------------------------------------------------------
+void cmTarget::FinalizeSystemIncludeDirectories()
+{
+  for (std::vector<cmValueWithOrigin>::const_iterator
+      it = this->Internal->LinkInterfacePropertyEntries.begin(),
+      end = this->Internal->LinkInterfacePropertyEntries.end();
+      it != end; ++it)
+    {
+    {
+    cmListFileBacktrace lfbt;
+    cmGeneratorExpression ge(lfbt);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> 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 = "$<TARGET_PROPERTY:" +
+                        it->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 = "$<$<BOOL:" + it->Value + ">:" + includeGenex + ">";
+      }
+    this->SystemIncludeDirectories.insert(includeGenex);
+    }
+}
+
 //----------------------------------------------------------------------------
 void
 cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )

+ 3 - 0
Source/cmTarget.h

@@ -538,6 +538,9 @@ public:
   void AddSystemIncludeDirectories(const std::vector<std::string> &incs);
   std::set<cmStdString> const & GetSystemIncludeDirectories() const
     { return this->SystemIncludeDirectories; }
+
+  void FinalizeSystemIncludeDirectories();
+
 private:
   // The set of include directories that are marked as system include
   // directories.

+ 14 - 3
Source/cmTargetIncludeDirectoriesCommand.cxx

@@ -84,10 +84,21 @@ void cmTargetIncludeDirectoriesCommand
                          const std::vector<std::string> &content,
                          bool prepend, bool system)
 {
+  cmTargetPropCommandBase::HandleInterfaceContent(tgt, content,
+                                                  prepend, system);
+
   if (system)
     {
-    // Error.
+    std::string joined;
+    std::string sep;
+    for(std::vector<std::string>::const_iterator it = content.begin();
+      it != content.end(); ++it)
+      {
+      joined += sep;
+      sep = ";";
+      joined += *it;
+      }
+    tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
+                        joined.c_str());
     }
-  cmTargetPropCommandBase::HandleInterfaceContent(tgt, content,
-                                                  prepend, system);
 }

+ 8 - 0
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 <target> 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 \"$<...>\".  "

+ 17 - 0
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
 ")

+ 19 - 0
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
+  $<TARGET_PROPERTY:systemlib,INTERFACE_INCLUDE_DIRECTORIES>
+)
+
+add_library(consumer consumer.cpp)
+target_link_libraries(consumer upstream)
+target_compile_options(consumer PRIVATE -Werror=unused-variable)

+ 7 - 0
Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp

@@ -0,0 +1,7 @@
+
+#include "upstream.h"
+
+int consumer()
+{
+  return upstream();
+}

+ 4 - 0
Tests/IncludeDirectories/SystemIncludeDirectories/systemlib.cpp

@@ -0,0 +1,4 @@
+
+#include "systemlib.h"
+
+int systemlib() { return 0; }

+ 19 - 0
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

+ 4 - 0
Tests/IncludeDirectories/SystemIncludeDirectories/upstream.cpp

@@ -0,0 +1,4 @@
+
+#include "upstream.h"
+
+int upstream() { return systemlib(); }

+ 12 - 0
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