Commit 9cf3547e authored by Stephen Kelly's avatar Stephen Kelly Committed by Brad King
Browse files

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.
parent 1925cffa
...@@ -126,6 +126,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) ...@@ -126,6 +126,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateIncludeDirectoriesInterface(te, this->PopulateIncludeDirectoriesInterface(te,
cmGeneratorExpression::InstallInterface, cmGeneratorExpression::InstallInterface,
properties, missingTargets); properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
te,
cmGeneratorExpression::InstallInterface,
properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",
te, te,
cmGeneratorExpression::InstallInterface, cmGeneratorExpression::InstallInterface,
......
...@@ -171,6 +171,14 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const ...@@ -171,6 +171,14 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const
|| strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 ); || 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 bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const
{ {
......
...@@ -18,11 +18,13 @@ ...@@ -18,11 +18,13 @@
#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \ #define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \
F(EvaluatingIncludeDirectories) \ F(EvaluatingIncludeDirectories) \
F(EvaluatingSystemIncludeDirectories) \
F(EvaluatingCompileDefinitions) \ F(EvaluatingCompileDefinitions) \
F(EvaluatingCompileOptions) F(EvaluatingCompileOptions)
#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \ #define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \
F(INTERFACE_INCLUDE_DIRECTORIES) \ F(INTERFACE_INCLUDE_DIRECTORIES) \
F(INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) \
F(INTERFACE_COMPILE_DEFINITIONS) \ F(INTERFACE_COMPILE_DEFINITIONS) \
F(INTERFACE_COMPILE_OPTIONS) F(INTERFACE_COMPILE_OPTIONS)
......
...@@ -879,6 +879,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode ...@@ -879,6 +879,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{ {
interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES"; interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES";
} }
else if (propertyName == "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")
{
interfacePropertyName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES";
}
else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS" else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS"
|| propertyName == "COMPILE_DEFINITIONS" || propertyName == "COMPILE_DEFINITIONS"
|| strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0) || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0)
......
...@@ -51,21 +51,43 @@ const char *cmGeneratorTarget::GetProperty(const char *prop) ...@@ -51,21 +51,43 @@ const char *cmGeneratorTarget::GetProperty(const char *prop)
bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
const char *config) const char *config)
{ {
for (std::set<cmStdString>::const_iterator std::string config_upper;
it = this->Target->GetSystemIncludeDirectories().begin(); if(config && *config)
it != this->Target->GetSystemIncludeDirectories().end(); ++it)
{ {
cmListFileBacktrace lfbt; config_upper = cmSystemTools::UpperCase(config);
cmGeneratorExpression ge(lfbt); }
typedef std::map<std::string, std::vector<std::string> > IncludeCacheType;
IncludeCacheType::iterator iter =
this->SystemIncludesCache.find(config_upper);
std::vector<std::string> incs; if (iter == this->SystemIncludesCache.end())
cmSystemTools::ExpandListArgument(ge.Parse(*it) {
->Evaluate(this->Makefile, std::vector<std::string> result;
config, false), incs); for (std::set<cmStdString>::const_iterator
if (std::find(incs.begin(), incs.end(), dir) != incs.end()) 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; return false;
} }
......
...@@ -78,6 +78,8 @@ private: ...@@ -78,6 +78,8 @@ private:
void ClassifySources(); void ClassifySources();
void LookupObjectLibraries(); void LookupObjectLibraries();
std::map<std::string, std::vector<std::string> > SystemIncludesCache;
cmGeneratorTarget(cmGeneratorTarget const&); cmGeneratorTarget(cmGeneratorTarget const&);
void operator=(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&);
}; };
......
...@@ -1001,6 +1001,17 @@ void cmGlobalGenerator::Generate() ...@@ -1001,6 +1001,17 @@ void cmGlobalGenerator::Generate()
// it builds by default. // it builds by default.
this->FillLocalGeneratorToTargetMap(); 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 // Generate project files
for (i = 0; i < this->LocalGenerators.size(); ++i) for (i = 0; i < this->LocalGenerators.size(); ++i)
{ {
......
...@@ -842,6 +842,17 @@ void cmTarget::DefineProperties(cmake *cm) ...@@ -842,6 +842,17 @@ void cmTarget::DefineProperties(cmake *cm)
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_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 cm->DefineProperty
("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET,
"List of public compile definitions for a library.", "List of public compile definitions for a library.",
...@@ -2555,6 +2566,39 @@ cmTarget::AddSystemIncludeDirectories(const std::vector<std::string> &incs) ...@@ -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 void
cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
......
...@@ -538,6 +538,9 @@ public: ...@@ -538,6 +538,9 @@ public:
void AddSystemIncludeDirectories(const std::vector<std::string> &incs); void AddSystemIncludeDirectories(const std::vector<std::string> &incs);
std::set<cmStdString> const & GetSystemIncludeDirectories() const std::set<cmStdString> const & GetSystemIncludeDirectories() const
{ return this->SystemIncludeDirectories; } { return this->SystemIncludeDirectories; }
void FinalizeSystemIncludeDirectories();
private: private:
// The set of include directories that are marked as system include // The set of include directories that are marked as system include
// directories. // directories.
......
...@@ -84,10 +84,21 @@ void cmTargetIncludeDirectoriesCommand ...@@ -84,10 +84,21 @@ void cmTargetIncludeDirectoriesCommand
const std::vector<std::string> &content, const std::vector<std::string> &content,
bool prepend, bool system) bool prepend, bool system)
{ {
cmTargetPropCommandBase::HandleInterfaceContent(tgt, content,
prepend, system);
if (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);
} }
...@@ -71,6 +71,14 @@ public: ...@@ -71,6 +71,14 @@ public:
"The following arguments specify include directories. Specified " "The following arguments specify include directories. Specified "
"include directories may be absolute paths or relative paths. " "include directories may be absolute paths or relative paths. "
"Repeated calls for the same <target> append items in the order called." "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" "\n"
"Arguments to target_include_directories may use \"generator " "Arguments to target_include_directories may use \"generator "
"expressions\" with the syntax \"$<...>\". " "expressions\" with the syntax \"$<...>\". "
......
cmake_minimum_required (VERSION 2.6) cmake_minimum_required (VERSION 2.6)
project(IncludeDirectories) 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 file(WRITE ${CMAKE_BINARY_DIR}/Flags/Flags.h
"//Flags.h "//Flags.h
") ")
......
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)
#include "upstream.h"
int consumer()
{
return upstream();
}
#include "systemlib.h"
int systemlib() { return 0; }
#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
#include "upstream.h"
int upstream() { return systemlib(); }
#ifndef UPSTREAM_H
#define UPSTREAM_H
#include "systemlib.h"
#ifdef _WIN32
__declspec(dllexport)
#endif
int upstream();
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment