summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2018-01-25 13:33:23 (GMT)
committerKitware Robot <kwrobot@kitware.com>2018-01-25 13:33:35 (GMT)
commit76f5a87cf1b653e254d26aff0f7fcf2115fb5e24 (patch)
treef00f75101a108b3b5394670b66435aef46f0b13a
parent03050c5689f5b6bd91b378316a919018629133fc (diff)
parent044831117955dfa33ed4e0c7799ea3f37258b149 (diff)
downloadCMake-76f5a87cf1b653e254d26aff0f7fcf2115fb5e24.zip
CMake-76f5a87cf1b653e254d26aff0f7fcf2115fb5e24.tar.gz
CMake-76f5a87cf1b653e254d26aff0f7fcf2115fb5e24.tar.bz2
Merge topic 'sourceFile-new-properties'
04483111 sourceFile properties: add property INCLUDE_DIRECTORIES 3073bd1f VisualStudio generators: refactoring 78b1c2e0 sourceFile properties: add property COMPILE_OPTIONS 3f935e69 LocalGenerator: refactoring Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !1596
-rw-r--r--Help/manual/cmake-properties.7.rst2
-rw-r--r--Help/prop_sf/COMPILE_OPTIONS.rst17
-rw-r--r--Help/prop_sf/INCLUDE_DIRECTORIES.rst18
-rw-r--r--Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst10
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx53
-rw-r--r--Source/cmExtraSublimeTextGenerator.h3
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx17
-rw-r--r--Source/cmGlobalXCodeGenerator.h2
-rw-r--r--Source/cmIDEOptions.cxx42
-rw-r--r--Source/cmIDEOptions.h12
-rw-r--r--Source/cmLocalGenerator.cxx107
-rw-r--r--Source/cmLocalGenerator.h40
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx6
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h5
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx102
-rw-r--r--Source/cmLocalXCodeGenerator.cxx6
-rw-r--r--Source/cmLocalXCodeGenerator.h2
-rw-r--r--Source/cmMakefileTargetGenerator.cxx32
-rw-r--r--Source/cmNinjaTargetGenerator.cxx41
-rw-r--r--Source/cmNinjaTargetGenerator.h3
-rw-r--r--Source/cmServerProtocol.cxx24
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx131
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h5
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx83
-rw-r--r--Source/cmVisualStudioGeneratorOptions.h4
-rw-r--r--Tests/CMakeLists.txt3
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt54
-rw-r--r--Tests/GeneratorExpression/srcgenex.c.in (renamed from Tests/GeneratorExpression/srcgenex_defs.c)2
-rw-r--r--Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c12
-rw-r--r--Tests/GeneratorExpression/srcgenex_flags.c12
-rw-r--r--Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c12
-rw-r--r--Tests/GeneratorExpression/srcgenex_includes.c.in12
-rw-r--r--Tests/GeneratorExpression/srcgenex_includes.h.in7
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/SourceProperties/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt1
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt4
-rw-r--r--Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake4
-rw-r--r--Tests/RunCMake/SourceProperties/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/SourceProperties/empty.c5
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt8
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt8
-rw-r--r--Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake3
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake2
-rw-r--r--Tests/SourceFileIncludeDirProperty/CMakeLists.txt15
-rw-r--r--Tests/SourceFileIncludeDirProperty/main.c7
-rw-r--r--Tests/SourceFileIncludeDirProperty/source/header.h2
-rw-r--r--Tests/SourceFileIncludeDirProperty/target/header.h2
51 files changed, 722 insertions, 232 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 88b39d4..00a932f 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -370,10 +370,12 @@ Properties on Source Files
/prop_sf/AUTORCC_OPTIONS
/prop_sf/COMPILE_DEFINITIONS
/prop_sf/COMPILE_FLAGS
+ /prop_sf/COMPILE_OPTIONS
/prop_sf/EXTERNAL_OBJECT
/prop_sf/Fortran_FORMAT
/prop_sf/GENERATED
/prop_sf/HEADER_FILE_ONLY
+ /prop_sf/INCLUDE_DIRECTORIES
/prop_sf/KEEP_EXTENSION
/prop_sf/LABELS
/prop_sf/LANGUAGE
diff --git a/Help/prop_sf/COMPILE_OPTIONS.rst b/Help/prop_sf/COMPILE_OPTIONS.rst
new file mode 100644
index 0000000..157c0b0
--- /dev/null
+++ b/Help/prop_sf/COMPILE_OPTIONS.rst
@@ -0,0 +1,17 @@
+COMPILE_OPTIONS
+---------------
+
+List of additional options to pass to the compiler.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of options
+and will be added to the list of compile flags when this
+source file builds. Use :prop_sf:`COMPILE_DEFINITIONS` to pass
+additional preprocessor definitions and :prop_sf:`INCLUDE_DIRECTORIES` to pass
+additional include directories.
+
+Contents of ``COMPILE_OPTIONS`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. However, :generator:`Xcode`
+does not support per-config per-source settings, so expressions
+that depend on the build configuration are not allowed with that
+generator.
diff --git a/Help/prop_sf/INCLUDE_DIRECTORIES.rst b/Help/prop_sf/INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..55780e5
--- /dev/null
+++ b/Help/prop_sf/INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,18 @@
+INCLUDE_DIRECTORIES
+-------------------
+
+List of preprocessor include file search directories.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of paths
+and will be added to the list of include directories when this
+source file builds. These directories will take precedence over directories
+defined at target level except for :generator:`Xcode` generator due to technical
+limitations.
+
+Relative paths should not be added to this property directly.
+
+Contents of ``INCLUDE_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. However, :generator:`Xcode` does not support
+per-config per-source settings, so expressions that depend on the build
+configuration are not allowed with that generator.
diff --git a/Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst b/Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst
new file mode 100644
index 0000000..d06c109
--- /dev/null
+++ b/Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst
@@ -0,0 +1,10 @@
+src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES
+----------------------------------------------------------
+
+* Source file learns new properties:
+
+ * A :prop_sf:`COMPILE_OPTIONS` source file property was added to manage list
+ of options to pass to the compiler.
+
+ * An :prop_sf:`INCLUDE_DIRECTORIES` source file property was added to specify
+ list of preprocessor include file search directories.
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index c7197f2..a89c187 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -257,6 +257,8 @@ void cmExtraSublimeTextGenerator::AppendTarget(
std::string flagsString =
this->ComputeFlagsForObject(sourceFile, lg, target);
std::string definesString = this->ComputeDefines(sourceFile, lg, target);
+ std::string includesString =
+ this->ComputeIncludes(sourceFile, lg, target);
flags.clear();
cmsys::RegularExpression flagRegex;
// Regular expression to extract compiler flags from a string
@@ -264,7 +266,8 @@ void cmExtraSublimeTextGenerator::AppendTarget(
const char* regexString =
"(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
flagRegex.compile(regexString);
- std::string workString = flagsString + " " + definesString;
+ std::string workString =
+ flagsString + " " + definesString + " " + includesString;
while (flagRegex.find(workString)) {
std::string::size_type start = flagRegex.start();
if (workString[start] == ' ') {
@@ -351,23 +354,21 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
lg->GetTargetCompileFlags(gtgt, config, language, flags);
- // Add include directory flags.
- {
- std::vector<std::string> includes;
- lg->GetIncludeDirectories(includes, gtgt, language, config);
- std::string includeFlags = lg->GetIncludeFlags(includes, gtgt, language,
- true); // full include paths
- lg->AppendFlags(flags, includeFlags);
- }
-
// Add source file specific flags.
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config,
+ gtgt->GetName(), language);
+
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
- cmGeneratorExpressionInterpreter genexInterpreter(
- lg, gtgt, config, gtgt->GetName(), language);
lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ }
+
return flags;
}
@@ -410,6 +411,34 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
return definesString;
}
+std::string cmExtraSublimeTextGenerator::ComputeIncludes(
+ cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
+
+{
+ std::vector<std::string> includes;
+ cmMakefile* makefile = lg->GetMakefile();
+ const std::string& language = source->GetLanguage();
+ const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ lg, target, config, target->GetName(), language);
+
+ // Add include directories for this source file
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+ lg->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES),
+ *source);
+ }
+
+ // Add include directory flags.
+ lg->GetIncludeDirectories(includes, target, language, config);
+
+ std::string includesString =
+ lg->GetIncludeFlags(includes, target, language, true, false, config);
+
+ return includesString;
+}
+
bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
const std::string& projectName,
bool dryRun)
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
index 57ba1cf..bc158f6 100644
--- a/Source/cmExtraSublimeTextGenerator.h
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -65,6 +65,9 @@ private:
std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
cmGeneratorTarget* gtgt);
+ std::string ComputeIncludes(cmSourceFile* source, cmLocalGenerator* lg,
+ cmGeneratorTarget* gtgt);
+
bool Open(const std::string& bindir, const std::string& projectName,
bool dryRun) override;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index bd51f60..9db21d8 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -743,6 +743,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) {
lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = sf->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ }
// Add per-source definitions.
BuildObjectListOrString flagsBuild(this, false);
@@ -759,6 +764,16 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
flags += flagsBuild.GetString();
}
+ // Add per-source include directories.
+ std::vector<std::string> includes;
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) {
+ lg->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES),
+ *sf);
+ }
+ lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
+
cmXCodeObject* buildFile =
this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), gtgt, lang, sf);
@@ -3521,7 +3536,7 @@ void cmGlobalXCodeGenerator::AppendDefines(
}
void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
- std::string const& flag)
+ std::string const& flag) const
{
// Short-circuit for an empty flag.
if (flag.empty()) {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 2269b25..d173f7a 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -104,7 +104,7 @@ public:
bool ShouldStripResourcePath(cmMakefile*) const override;
bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
- void AppendFlag(std::string& flags, std::string const& flag);
+ void AppendFlag(std::string& flags, std::string const& flag) const;
protected:
void AddExtraIDETargets() override;
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
index 4b59f44..354b757 100644
--- a/Source/cmIDEOptions.cxx
+++ b/Source/cmIDEOptions.cxx
@@ -13,6 +13,7 @@ cmIDEOptions::cmIDEOptions()
{
this->DoingDefine = false;
this->AllowDefine = true;
+ this->DoingInclude = false;
this->AllowSlash = false;
this->DoingFollowing = 0;
for (int i = 0; i < FlagTableCount; ++i) {
@@ -33,6 +34,13 @@ void cmIDEOptions::HandleFlag(const char* flag)
return;
}
+ // If the last option was -I then this option is the include directory.
+ if (this->DoingInclude) {
+ this->DoingInclude = false;
+ this->Includes.push_back(flag);
+ return;
+ }
+
// If the last option expected a following value, this is it.
if (this->DoingFollowing) {
this->FlagMapUpdate(this->DoingFollowing, flag);
@@ -53,6 +61,17 @@ void cmIDEOptions::HandleFlag(const char* flag)
}
return;
}
+ // Look for include directory.
+ if (this->AllowInclude && flag[1] == 'I') {
+ if (flag[2] == '\0') {
+ // The next argument will have the include directory.
+ this->DoingInclude = true;
+ } else {
+ // Store this include directory.
+ this->Includes.push_back(flag + 2);
+ }
+ return;
+ }
// Look through the available flag tables.
bool flag_handled = false;
@@ -155,6 +174,29 @@ std::vector<std::string> const& cmIDEOptions::GetDefines() const
return this->Defines;
}
+void cmIDEOptions::AddInclude(const std::string& include)
+{
+ this->Includes.push_back(include);
+}
+
+void cmIDEOptions::AddIncludes(const char* includes)
+{
+ if (includes) {
+ // Expand the list of includes.
+ cmSystemTools::ExpandListArgument(includes, this->Includes);
+ }
+}
+void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes)
+{
+ this->Includes.insert(this->Includes.end(), includes.begin(),
+ includes.end());
+}
+
+std::vector<std::string> const& cmIDEOptions::GetIncludes() const
+{
+ return this->Includes;
+}
+
void cmIDEOptions::AddFlag(std::string const& flag, std::string const& value)
{
this->FlagMap[flag] = value;
diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h
index ded92ca..54cb524 100644
--- a/Source/cmIDEOptions.h
+++ b/Source/cmIDEOptions.h
@@ -20,12 +20,17 @@ public:
cmIDEOptions();
virtual ~cmIDEOptions();
- // Store definitions and flags.
+ // Store definitions, includes and flags.
void AddDefine(const std::string& define);
void AddDefines(const char* defines);
void AddDefines(const std::vector<std::string>& defines);
std::vector<std::string> const& GetDefines() const;
+ void AddInclude(const std::string& includes);
+ void AddIncludes(const char* includes);
+ void AddIncludes(const std::vector<std::string>& includes);
+ std::vector<std::string> const& GetIncludes() const;
+
void AddFlag(std::string const& flag, std::string const& value);
void AddFlag(std::string const& flag, std::vector<std::string> const& value);
void AppendFlag(std::string const& flag, std::string const& value);
@@ -76,8 +81,13 @@ protected:
// Preprocessor definitions.
std::vector<std::string> Defines;
+ // Include directories.
+ std::vector<std::string> Includes;
+
bool DoingDefine;
bool AllowDefine;
+ bool DoingInclude;
+ bool AllowInclude;
bool AllowSlash;
cmIDEFlagTable const* DoingFollowing;
enum
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index c8d94c0..86b16f8 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -16,6 +16,7 @@
#include "cmMakefile.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
@@ -37,6 +38,7 @@
#include <sstream>
#include <stdio.h>
#include <string.h>
+#include <unordered_set>
#include <utility>
#if defined(__HAIKU__)
@@ -792,19 +794,14 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags,
if (const char* langFlagRegexStr =
this->Makefile->GetDefinition(langFlagRegexVar)) {
// Filter flags acceptable to this language.
- cmsys::RegularExpression r(langFlagRegexStr);
std::vector<std::string> opts;
if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
}
target->GetCompileOptions(opts, config, lang);
- for (std::string const& opt : opts) {
- if (r.find(opt.c_str())) {
- // (Re-)Escape this flag. COMPILE_FLAGS were already parsed
- // as a command line above, and COMPILE_OPTIONS are escaped.
- this->AppendFlagEscape(flags, opt);
- }
- }
+ // (Re-)Escape these flags. COMPILE_FLAGS were already parsed
+ // as a command line above, and COMPILE_OPTIONS are escaped.
+ this->AppendCompileOptions(flags, opts, langFlagRegexStr);
} else {
// Use all flags.
if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
@@ -813,10 +810,8 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags,
}
std::vector<std::string> opts;
target->GetCompileOptions(opts, config, lang);
- for (std::string const& opt : opts) {
- // COMPILE_OPTIONS are escaped.
- this->AppendFlagEscape(flags, opt);
- }
+ // COMPILE_OPTIONS are escaped.
+ this->AppendCompileOptions(flags, opts);
}
for (auto const& it : target->GetMaxLanguageStandards()) {
@@ -1876,7 +1871,7 @@ void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
}
void cmLocalGenerator::AppendFlags(std::string& flags,
- const std::string& newFlags)
+ const std::string& newFlags) const
{
if (!newFlags.empty()) {
if (!flags.empty()) {
@@ -1886,7 +1881,8 @@ void cmLocalGenerator::AppendFlags(std::string& flags,
}
}
-void cmLocalGenerator::AppendFlags(std::string& flags, const char* newFlags)
+void cmLocalGenerator::AppendFlags(std::string& flags,
+ const char* newFlags) const
{
if (newFlags && *newFlags) {
this->AppendFlags(flags, std::string(newFlags));
@@ -1894,7 +1890,7 @@ void cmLocalGenerator::AppendFlags(std::string& flags, const char* newFlags)
}
void cmLocalGenerator::AppendFlagEscape(std::string& flags,
- const std::string& rawFlag)
+ const std::string& rawFlag) const
{
this->AppendFlags(flags, this->EscapeForShell(rawFlag));
}
@@ -1930,6 +1926,87 @@ void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
}
}
+void cmLocalGenerator::AppendCompileOptions(std::string& options,
+ const char* options_list,
+ const char* regex) const
+{
+ // Short-circuit if there are no options.
+ if (!options_list) {
+ return;
+ }
+
+ // Expand the list of options.
+ std::vector<std::string> options_vec;
+ cmSystemTools::ExpandListArgument(options_list, options_vec);
+ this->AppendCompileOptions(options, options_vec, regex);
+}
+
+void cmLocalGenerator::AppendCompileOptions(
+ std::string& options, const std::vector<std::string>& options_vec,
+ const char* regex) const
+{
+ if (regex != nullptr) {
+ // Filter flags upon specified reges.
+ cmsys::RegularExpression r(regex);
+
+ for (std::string const& opt : options_vec) {
+ if (r.find(opt.c_str())) {
+ this->AppendFlagEscape(options, opt);
+ }
+ }
+ } else {
+ for (std::string const& opt : options_vec) {
+ this->AppendFlagEscape(options, opt);
+ }
+ }
+}
+
+void cmLocalGenerator::AppendIncludeDirectories(
+ std::vector<std::string>& includes, const char* includes_list,
+ const cmSourceFile& sourceFile) const
+{
+ // Short-circuit if there are no includes.
+ if (!includes_list) {
+ return;
+ }
+
+ // Expand the list of includes.
+ std::vector<std::string> includes_vec;
+ cmSystemTools::ExpandListArgument(includes_list, includes_vec);
+ this->AppendIncludeDirectories(includes, includes_vec, sourceFile);
+}
+
+void cmLocalGenerator::AppendIncludeDirectories(
+ std::vector<std::string>& includes,
+ const std::vector<std::string>& includes_vec,
+ const cmSourceFile& sourceFile) const
+{
+ std::unordered_set<std::string> uniqueIncludes;
+
+ for (const std::string& include : includes_vec) {
+ if (!cmSystemTools::FileIsFullPath(include.c_str())) {
+ std::ostringstream e;
+ e << "Found relative path while evaluating include directories of "
+ "\""
+ << sourceFile.GetLocation().GetName() << "\":\n \"" << include
+ << "\"\n";
+
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+
+ std::string inc = include;
+
+ if (!cmSystemTools::IsOff(inc.c_str())) {
+ cmSystemTools::ConvertToUnixSlashes(inc);
+ }
+
+ if (uniqueIncludes.insert(inc).second) {
+ includes.push_back(inc);
+ }
+ }
+}
+
void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
const char* defines_list) const
{
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 4a7d2ca..a66fa6e 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -118,10 +118,11 @@ public:
cmGeneratorTarget const* target,
const std::string& lang);
///! Append flags to a string.
- virtual void AppendFlags(std::string& flags, const std::string& newFlags);
- virtual void AppendFlags(std::string& flags, const char* newFlags);
+ virtual void AppendFlags(std::string& flags,
+ const std::string& newFlags) const;
+ virtual void AppendFlags(std::string& flags, const char* newFlags) const;
virtual void AppendFlagEscape(std::string& flags,
- const std::string& rawFlag);
+ const std::string& rawFlag) const;
void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);
@@ -152,6 +153,23 @@ public:
cmGeneratorTarget* FindGeneratorTargetToUse(const std::string& name) const;
/**
+ * Process a list of include directories
+ */
+ void AppendIncludeDirectories(std::vector<std::string>& includes,
+ const char* includes_list,
+ const cmSourceFile& sourceFile) const;
+ void AppendIncludeDirectories(std::vector<std::string>& includes,
+ std::string const& includes_list,
+ const cmSourceFile& sourceFile) const
+ {
+ this->AppendIncludeDirectories(includes, includes_list.c_str(),
+ sourceFile);
+ }
+ void AppendIncludeDirectories(std::vector<std::string>& includes,
+ const std::vector<std::string>& includes_vec,
+ const cmSourceFile& sourceFile) const;
+
+ /**
* Encode a list of preprocessor definitions for the compiler
* command line.
*/
@@ -166,6 +184,22 @@ public:
const std::vector<std::string>& defines_vec) const;
/**
+ * Encode a list of compile options for the compiler
+ * command line.
+ */
+ void AppendCompileOptions(std::string& options, const char* options_list,
+ const char* regex = nullptr) const;
+ void AppendCompileOptions(std::string& options,
+ std::string const& options_list,
+ const char* regex = nullptr) const
+ {
+ this->AppendCompileOptions(options, options_list.c_str(), regex);
+ }
+ void AppendCompileOptions(std::string& options,
+ const std::vector<std::string>& options_vec,
+ const char* regex = nullptr) const;
+
+ /**
* Join a set of defines into a definesString with a space separator.
*/
void JoinDefines(const std::set<std::string>& defines,
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 28890f0..e2d5322 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -830,8 +830,8 @@ std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
return dir;
}
-void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags,
- const std::string& newFlags)
+void cmLocalUnixMakefileGenerator3::AppendFlags(
+ std::string& flags, const std::string& newFlags) const
{
if (this->IsWatcomWMake() && !newFlags.empty()) {
std::string newf = newFlags;
@@ -845,7 +845,7 @@ void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags,
}
void cmLocalUnixMakefileGenerator3::AppendFlags(std::string& flags,
- const char* newFlags)
+ const char* newFlags) const
{
this->cmLocalGenerator::AppendFlags(flags, newFlags);
}
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index b149524..86c5aab 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -88,8 +88,9 @@ public:
const std::string& tgt);
// append flags to a string
- void AppendFlags(std::string& flags, const std::string& newFlags) override;
- void AppendFlags(std::string& flags, const char* newFlags) override;
+ void AppendFlags(std::string& flags,
+ const std::string& newFlags) const override;
+ void AppendFlags(std::string& flags, const char* newFlags) const override;
// append an echo command
enum EchoColor
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index b55fa49..f38cd79 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -45,15 +45,6 @@ public:
extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
-static void cmConvertToWindowsSlash(std::string& s)
-{
- std::string::size_type pos = 0;
- while ((pos = s.find('/', pos)) != std::string::npos) {
- s[pos] = '\\';
- pos++;
- }
-}
-
cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator(
cmGlobalGenerator* gg, cmMakefile* mf)
: cmLocalVisualStudioGenerator(gg, mf)
@@ -704,11 +695,16 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
targetOptions.Parse(flags.c_str());
targetOptions.Parse(defineFlags.c_str());
targetOptions.ParseFinish();
- std::vector<std::string> targetDefines;
if (!langForClCompile.empty()) {
+ std::vector<std::string> targetDefines;
target->GetCompileDefinitions(targetDefines, configName, langForClCompile);
+ targetOptions.AddDefines(targetDefines);
+
+ std::vector<std::string> targetIncludes;
+ this->GetIncludeDirectories(targetIncludes, target, langForClCompile,
+ configName);
+ targetOptions.AddIncludes(targetIncludes);
}
- targetOptions.AddDefines(targetDefines);
targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@@ -795,27 +791,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
<< this->ConvertToXMLOutputPath(modDir.c_str())
<< "\\$(ConfigurationName)\"\n";
}
- fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
- std::vector<std::string> includes_cl;
- if (!langForClCompile.empty()) {
- this->GetIncludeDirectories(includes_cl, target, langForClCompile,
- configName);
- }
- std::vector<std::string>::iterator i = includes_cl.begin();
- for (; i != includes_cl.end(); ++i) {
- // output the include path
- std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
- fout << ipath << ";";
- // if this is fortran then output the include with
- // a ConfigurationName on the end of it.
- if (this->FortranProject) {
- ipath = i->c_str();
- ipath += "/$(ConfigurationName)";
- ipath = this->ConvertToXMLOutputPath(ipath.c_str());
- fout << ipath << ";";
- }
- }
- fout << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(
+ fout, "\t\t\t\t", "\n",
+ this->FortranProject ? "Fortran" : langForClCompile);
targetOptions.OutputFlagMap(fout, "\t\t\t\t");
targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n",
langForClCompile);
@@ -835,20 +813,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
fout <<
"\t\t\t<Tool\n"
"\t\t\t\tName=\"MASM\"\n"
- "\t\t\t\tIncludePaths=\""
;
- std::vector<std::string> includes_masm;
- this->GetIncludeDirectories(includes_masm, target, "ASM_MASM",
- configName);
/* clang-format on */
- const char* sep = "";
- for (i = includes_masm.begin(); i != includes_masm.end(); ++i) {
- std::string inc = *i;
- cmConvertToWindowsSlash(inc);
- fout << sep << this->EscapeForXML(inc);
- sep = ";";
- }
- fout << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(fout, "\t\t\t\t", "\n",
+ "ASM_MASM");
// Use same preprocessor definitions as VCCLCompilerTool.
targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n",
"ASM_MASM");
@@ -868,16 +836,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
if (this->FortranProject) {
tool = "VFResourceCompilerTool";
}
- fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"
- << "\t\t\t\tAdditionalIncludeDirectories=\"";
- std::vector<std::string> includes_rc;
- this->GetIncludeDirectories(includes_rc, target, "RC", configName);
- for (i = includes_rc.begin(); i != includes_rc.end(); ++i) {
- std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
- fout << ipath << ";";
- }
+ fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "",
+ "RC");
// add the -D flags to the RC tool
- fout << "\"";
targetOptions.OutputPreprocessorDefinitions(fout, "\n\t\t\t\t", "", "RC");
fout << "/>\n";
tool = "VCMIDLTool";
@@ -885,14 +847,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
tool = "VFMIDLTool";
}
fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n";
- fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
- std::vector<std::string> includes_midl;
- this->GetIncludeDirectories(includes_midl, target, "MIDL", configName);
- for (i = includes_midl.begin(); i != includes_midl.end(); ++i) {
- std::string ipath = this->ConvertToXMLOutputPath(i->c_str());
- fout << ipath << ";";
- }
- fout << "\"\n";
+ targetOptions.OutputAdditionalIncludeDirectories(fout, "\n\t\t\t\t", "",
+ "MIDL");
fout << "\t\t\t\tMkTypLibCompatible=\"false\"\n";
if (gg->GetPlatformName() == "x64") {
fout << "\t\t\t\tTargetEnvironment=\"3\"\n";
@@ -1440,6 +1396,7 @@ struct cmLVS7GFileConfig
std::string CompileDefs;
std::string CompileDefsConfig;
std::string AdditionalDeps;
+ std::string IncludeDirs;
bool ExcludedFromBuild;
};
@@ -1494,6 +1451,12 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
fc.CompileFlags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS);
needfc = true;
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = sf.GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ fc.CompileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ needfc = true;
+ }
if (lg->FortranProject) {
switch (cmOutputConverter::GetFortranFormat(
sf.GetProperty("Fortran_FORMAT"))) {
@@ -1522,6 +1485,12 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
needfc = true;
}
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) {
+ fc.IncludeDirs = genexInterpreter.Evaluate(cincs, INCLUDE_DIRECTORIES);
+ needfc = true;
+ }
+
// Check for extra object-file dependencies.
if (const char* deps = sf.GetProperty("OBJECT_DEPENDS")) {
std::vector<std::string> depends;
@@ -1652,7 +1621,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo);
} else if (!fcinfo.FileConfigMap.empty()) {
const char* aCompilerTool = "VCCLCompilerTool";
- const char* ppLang = "CXX";
+ std::string ppLang = "CXX";
if (this->FortranProject) {
aCompilerTool = "VFFortranCompilerTool";
}
@@ -1699,7 +1668,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
if (!fc.CompileFlags.empty() || !fc.CompileDefs.empty() ||
- !fc.CompileDefsConfig.empty()) {
+ !fc.CompileDefsConfig.empty() || !fc.IncludeDirs.empty()) {
Options::Tool tool = Options::Compiler;
cmVS7FlagTable const* table =
cmLocalVisualStudio7GeneratorFlagTable;
@@ -1711,7 +1680,14 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
fileOptions.Parse(fc.CompileFlags.c_str());
fileOptions.AddDefines(fc.CompileDefs.c_str());
fileOptions.AddDefines(fc.CompileDefsConfig.c_str());
+ // validate source level include directories
+ std::vector<std::string> includes;
+ this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf);
+ fileOptions.AddIncludes(includes);
fileOptions.OutputFlagMap(fout, "\t\t\t\t\t");
+ fileOptions.OutputAdditionalIncludeDirectories(
+ fout, "\t\t\t\t\t", "\n",
+ ppLang == "CXX" && this->FortranProject ? "Fortran" : ppLang);
fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", "\n",
ppLang);
}
diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx
index 457d1fd..92c958d 100644
--- a/Source/cmLocalXCodeGenerator.cxx
+++ b/Source/cmLocalXCodeGenerator.cxx
@@ -31,10 +31,10 @@ std::string cmLocalXCodeGenerator::GetTargetDirectory(
}
void cmLocalXCodeGenerator::AppendFlagEscape(std::string& flags,
- const std::string& rawFlag)
+ const std::string& rawFlag) const
{
- cmGlobalXCodeGenerator* gg =
- static_cast<cmGlobalXCodeGenerator*>(this->GlobalGenerator);
+ const cmGlobalXCodeGenerator* gg =
+ static_cast<const cmGlobalXCodeGenerator*>(this->GlobalGenerator);
gg->AppendFlag(flags, rawFlag);
}
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
index 8c9596f..5c22dcf 100644
--- a/Source/cmLocalXCodeGenerator.h
+++ b/Source/cmLocalXCodeGenerator.h
@@ -31,7 +31,7 @@ public:
std::string GetTargetDirectory(
cmGeneratorTarget const* target) const override;
void AppendFlagEscape(std::string& flags,
- const std::string& rawFlag) override;
+ const std::string& rawFlag) const override;
void Generate() override;
virtual void GenerateInstallRules();
void ComputeObjectFilenames(
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 002cc0f..1543536 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -445,10 +445,35 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
<< "\n";
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = source.GetProperty(COMPILE_OPTIONS)) {
+ const char* evaluatedOptions =
+ genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS);
+ this->LocalGenerator->AppendCompileOptions(flags, evaluatedOptions);
+ *this->FlagFileStream << "# Custom options: " << relativeObj
+ << "_OPTIONS = " << evaluatedOptions << "\n"
+ << "\n";
+ }
+
+ // Add include directories from source file properties.
+ std::vector<std::string> includes;
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) {
+ const char* evaluatedIncludes =
+ genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES);
+ this->LocalGenerator->AppendIncludeDirectories(includes, evaluatedIncludes,
+ source);
+ *this->FlagFileStream << "# Custom include directories: " << relativeObj
+ << "_INCLUDE_DIRECTORIES = " << evaluatedIncludes
+ << "\n"
+ << "\n";
+ }
+
// Add language-specific defines.
std::set<std::string> defines;
- // Add source-sepcific preprocessor definitions.
+ // Add source-specific preprocessor definitions.
const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
if (const char* compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) {
const char* evaluatedDefs =
@@ -565,7 +590,10 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
vars.Defines = definesString.c_str();
- std::string const includesString = "$(" + lang + "_INCLUDES)";
+ std::string includesString = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, lang, true, false, config);
+ this->LocalGenerator->AppendFlags(includesString,
+ "$(" + lang + "_INCLUDES)");
vars.Includes = includesString.c_str();
// At the moment, it is assumed that C, C++, Fortran, and CUDA have both
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index f967168..4f37882 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -135,16 +135,23 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
}
// Add source file specific flags.
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, this->GeneratorTarget,
+ this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(),
+ language);
+
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
- cmGeneratorExpressionInterpreter genexInterpreter(
- this->LocalGenerator, this->GeneratorTarget,
- this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(),
- language);
this->LocalGenerator->AppendFlags(
flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) {
+ this->LocalGenerator->AppendCompileOptions(
+ flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ }
+
return flags;
}
@@ -204,6 +211,30 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
return definesString;
}
+std::string cmNinjaTargetGenerator::ComputeIncludes(
+ cmSourceFile const* source, const std::string& language)
+{
+ std::vector<std::string> includes;
+ const std::string config = this->LocalGenerator->GetConfigName();
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ this->LocalGenerator, this->GeneratorTarget, config,
+ this->GeneratorTarget->GetName(), language);
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+ this->LocalGenerator->AppendIncludeDirectories(
+ includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES),
+ *source);
+ }
+
+ std::string includesString = this->LocalGenerator->GetIncludeFlags(
+ includes, this->GeneratorTarget, language, true, false, config);
+ this->LocalGenerator->AppendFlags(includesString,
+ this->GetIncludes(language));
+
+ return includesString;
+}
+
cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
{
// Static libraries never depend on other targets for linking.
@@ -818,7 +849,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
cmNinjaVars vars;
vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
vars["DEFINES"] = this->ComputeDefines(source, language);
- vars["INCLUDES"] = this->GetIncludes(language);
+ vars["INCLUDES"] = this->ComputeIncludes(source, language);
if (!this->NeedDepTypeMSVC(language)) {
vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
objectFileName + ".d", cmOutputConverter::SHELL);
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 770a99d..4660a3a 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -82,6 +82,9 @@ protected:
std::string ComputeDefines(cmSourceFile const* source,
const std::string& language);
+ std::string ComputeIncludes(cmSourceFile const* source,
+ const std::string& language);
+
std::string ConvertToNinjaPath(const std::string& path) const
{
return this->GetGlobalGenerator()->ConvertToNinjaPath(path);
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 4c0a354..c2dee8f 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -708,9 +708,31 @@ static Json::Value DumpSourceFilesList(
lg->AppendFlags(compileFlags,
genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
}
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ }
fileData.Flags = compileFlags;
- fileData.IncludePathList = ld.IncludePathList;
+ // Add include directories from source file properties.
+ std::vector<std::string> includes;
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) {
+ const char* evaluatedIncludes =
+ genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES);
+ lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
+
+ for (const auto& include : includes) {
+ fileData.IncludePathList.push_back(std::make_pair(
+ include, target->IsSystemIncludeDirectory(include, config)));
+ }
+ }
+
+ fileData.IncludePathList.insert(fileData.IncludePathList.end(),
+ ld.IncludePathList.begin(),
+ ld.IncludePathList.end());
const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
std::set<std::string> defines;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index ff2ed32..4555358 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -114,22 +114,6 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
{
- for (OptionsMap::iterator i = this->ClOptions.begin();
- i != this->ClOptions.end(); ++i) {
- delete i->second;
- }
- for (OptionsMap::iterator i = this->LinkOptions.begin();
- i != this->LinkOptions.end(); ++i) {
- delete i->second;
- }
- for (OptionsMap::iterator i = this->CudaOptions.begin();
- i != this->CudaOptions.end(); ++i) {
- delete i->second;
- }
- for (OptionsMap::iterator i = this->CudaLinkOptions.begin();
- i != this->CudaLinkOptions.end(); ++i) {
- delete i->second;
- }
if (!this->BuildFileStream) {
return;
}
@@ -2036,18 +2020,32 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
}
std::string flags;
bool configDependentFlags = false;
+ std::string options;
+ bool configDependentOptions = false;
std::string defines;
bool configDependentDefines = false;
+ std::string includes;
+ bool configDependentIncludes = false;
if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) {
configDependentFlags =
cmGeneratorExpression::Find(cflags) != std::string::npos;
flags += cflags;
}
+ if (const char* coptions = sf.GetProperty("COMPILE_OPTIONS")) {
+ configDependentOptions =
+ cmGeneratorExpression::Find(coptions) != std::string::npos;
+ options += coptions;
+ }
if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
configDependentDefines =
cmGeneratorExpression::Find(cdefs) != std::string::npos;
defines += cdefs;
}
+ if (const char* cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) {
+ configDependentIncludes =
+ cmGeneratorExpression::Find(cincludes) != std::string::npos;
+ includes += cincludes;
+ }
std::string lang =
this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
@@ -2099,7 +2097,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
}
// if we have flags or defines for this config then
// use them
- if (!flags.empty() || !configDefines.empty() || compileAs || noWinRT) {
+ if (!flags.empty() || !options.empty() || !configDefines.empty() ||
+ !includes.empty() || compileAs || noWinRT) {
(*this->BuildFileStream) << firstString;
firstString = ""; // only do firstString once
hasFlags = true;
@@ -2137,9 +2136,16 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
} else {
clOptions.Parse(flags.c_str());
}
- if (clOptions.HasFlag("AdditionalIncludeDirectories")) {
- clOptions.AppendFlag("AdditionalIncludeDirectories",
- "%(AdditionalIncludeDirectories)");
+ if (!options.empty()) {
+ std::string expandedOptions;
+ if (configDependentOptions) {
+ this->LocalGenerator->AppendCompileOptions(
+ expandedOptions,
+ genexInterpreter.Evaluate(options, "COMPILE_OPTIONS"));
+ } else {
+ this->LocalGenerator->AppendCompileOptions(expandedOptions, options);
+ }
+ clOptions.Parse(expandedOptions.c_str());
}
if (clOptions.HasFlag("DisableSpecificWarnings")) {
clOptions.AppendFlag("DisableSpecificWarnings",
@@ -2151,9 +2157,21 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
} else {
clOptions.AddDefines(configDefines.c_str());
}
+ std::vector<std::string> includeList;
+ if (configDependentIncludes) {
+ this->LocalGenerator->AppendIncludeDirectories(
+ includeList,
+ genexInterpreter.Evaluate(includes, "INCLUDE_DIRECTORIES"), *source);
+ } else {
+ this->LocalGenerator->AppendIncludeDirectories(includeList, includes,
+ *source);
+ }
+ clOptions.AddIncludes(includeList);
clOptions.SetConfiguration(config.c_str());
clOptions.PrependInheritedString("AdditionalOptions");
clOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ clOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream,
+ " ", "\n", lang);
clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n", lang);
}
@@ -2446,6 +2464,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
break;
}
clOptions.AddDefines(targetDefines);
+
+ // Get includes for this target
+ if (!this->LangForClCompile.empty()) {
+ clOptions.AddIncludes(
+ this->GetIncludes(configName, this->LangForClCompile));
+ }
+
if (this->MSTools) {
clOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@@ -2497,7 +2522,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
}
- this->ClOptions[configName] = pOptions.release();
+ this->ClOptions[configName] = std::move(pOptions);
return true;
}
@@ -2510,14 +2535,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
}
this->WriteString("<ClCompile>\n", 2);
clOptions.PrependInheritedString("AdditionalOptions");
- if (!this->LangForClCompile.empty()) {
- std::vector<std::string> const includes =
- this->GetIncludes(configName, this->LangForClCompile);
- clOptions.AppendFlag("AdditionalIncludeDirectories", includes);
- }
- clOptions.AppendFlag("AdditionalIncludeDirectories",
- "%(AdditionalIncludeDirectories)");
clOptions.OutputFlagMap(*this->BuildFileStream, " ");
+ clOptions.OutputAdditionalIncludeDirectories(
+ *this->BuildFileStream, " ", "\n", this->LangForClCompile);
clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n", this->LangForClCompile);
@@ -2595,7 +2615,10 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
Options& clOptions = *(this->ClOptions[configName]);
rcOptions.AddDefines(clOptions.GetDefines());
- this->RcOptions[configName] = pOptions.release();
+ // Get includes for this target
+ rcOptions.AddIncludes(this->GetIncludes(configName, "RC"));
+
+ this->RcOptions[configName] = std::move(pOptions);
return true;
}
@@ -2610,11 +2633,8 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions(
Options& rcOptions = *(this->RcOptions[configName]);
rcOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n", "RC");
- std::vector<std::string> const includes =
- this->GetIncludes(configName, "RC");
- rcOptions.AppendFlag("AdditionalIncludeDirectories", includes);
- rcOptions.AppendFlag("AdditionalIncludeDirectories",
- "%(AdditionalIncludeDirectories)");
+ rcOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream,
+ " ", "\n", "RC");
rcOptions.PrependInheritedString("AdditionalOptions");
rcOptions.OutputFlagMap(*this->BuildFileStream, " ");
@@ -2728,7 +2748,10 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
cudaOptions.AddDefine(exportMacro);
}
- this->CudaOptions[configName] = pOptions.release();
+ // Get includes for this target
+ cudaOptions.AddIncludes(this->GetIncludes(configName, "CUDA"));
+
+ this->CudaOptions[configName] = std::move(pOptions);
return true;
}
@@ -2741,10 +2764,8 @@ void cmVisualStudio10TargetGenerator::WriteCudaOptions(
this->WriteString("<CudaCompile>\n", 2);
Options& cudaOptions = *(this->CudaOptions[configName]);
- std::vector<std::string> const includes =
- this->GetIncludes(configName, "CUDA");
- cudaOptions.AppendFlag("Include", includes);
- cudaOptions.AppendFlag("Include", "%(Include)");
+ cudaOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream,
+ " ", "\n", "CUDA");
cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n", "CUDA");
cudaOptions.PrependInheritedString("AdditionalOptions");
@@ -2801,7 +2822,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
"-Wno-deprecated-gpu-targets");
}
- this->CudaLinkOptions[configName] = pOptions.release();
+ this->CudaLinkOptions[configName] = std::move(pOptions);
return true;
}
@@ -2852,7 +2873,11 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
std::string(this->Makefile->GetSafeDefinition(configFlagsVar));
masmOptions.Parse(flags.c_str());
- this->MasmOptions[configName] = pOptions.release();
+
+ // Get includes for this target
+ masmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MASM"));
+
+ this->MasmOptions[configName] = std::move(pOptions);
return true;
}
@@ -2870,10 +2895,8 @@ void cmVisualStudio10TargetGenerator::WriteMasmOptions(
"\n", "ASM_MASM");
Options& masmOptions = *(this->MasmOptions[configName]);
- std::vector<std::string> const includes =
- this->GetIncludes(configName, "ASM_MASM");
- masmOptions.AppendFlag("IncludePaths", includes);
- masmOptions.AppendFlag("IncludePaths", "%(IncludePaths)");
+ masmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream,
+ " ", "\n", "ASM_MASM");
masmOptions.PrependInheritedString("AdditionalOptions");
masmOptions.OutputFlagMap(*this->BuildFileStream, " ");
@@ -2911,7 +2934,11 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
std::string(" ") +
std::string(this->Makefile->GetSafeDefinition(configFlagsVar));
nasmOptions.Parse(flags.c_str());
- this->NasmOptions[configName] = pOptions.release();
+
+ // Get includes for this target
+ nasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_NASM"));
+
+ this->NasmOptions[configName] = std::move(pOptions);
return true;
}
@@ -2926,12 +2953,8 @@ void cmVisualStudio10TargetGenerator::WriteNasmOptions(
std::vector<std::string> includes =
this->GetIncludes(configName, "ASM_NASM");
Options& nasmOptions = *(this->NasmOptions[configName]);
- for (size_t i = 0; i < includes.size(); i++) {
- includes[i] += "\\";
- }
-
- nasmOptions.AppendFlag("IncludePaths", includes);
- nasmOptions.AppendFlag("IncludePaths", "%(IncludePaths)");
+ nasmOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream,
+ " ", "\n", "ASM_NASM");
nasmOptions.OutputFlagMap(*this->BuildFileStream, " ");
nasmOptions.PrependInheritedString("AdditionalOptions");
nasmOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
@@ -3357,7 +3380,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
}
}
- this->LinkOptions[config] = pOptions.release();
+ this->LinkOptions[config] = std::move(pOptions);
return true;
}
@@ -3523,7 +3546,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
if (this->ProjectType == csproj) {
return;
}
- for (std::string const& i : this->Configurations) {
+ for (const auto& i : this->Configurations) {
this->WritePlatformConfigTag("ItemDefinitionGroup", i, 1);
*this->BuildFileStream << "\n";
// output cl compile flags <ClCompile></ClCompile>
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index c346164..2bc5da9 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -7,6 +7,7 @@
#include <iosfwd>
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -24,6 +25,8 @@ class cmVisualStudioGeneratorOptions;
class cmVisualStudio10TargetGenerator
{
+ CM_DISABLE_COPY(cmVisualStudio10TargetGenerator)
+
public:
cmVisualStudio10TargetGenerator(cmGeneratorTarget* target,
cmGlobalVisualStudio10Generator* gg);
@@ -169,7 +172,7 @@ private:
private:
typedef cmVisualStudioGeneratorOptions Options;
- typedef std::map<std::string, Options*> OptionsMap;
+ typedef std::map<std::string, std::unique_ptr<Options>> OptionsMap;
OptionsMap ClOptions;
OptionsMap RcOptions;
OptionsMap CudaOptions;
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 106bdff..ccbff83 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -29,23 +29,8 @@ static std::string cmVisualStudioGeneratorOptionsEscapeForXML(std::string ret)
cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
cmLocalVisualStudioGenerator* lg, Tool tool,
cmVisualStudio10TargetGenerator* g)
- : cmIDEOptions()
- , LocalGenerator(lg)
- , Version(lg->GetVersion())
- , CurrentTool(tool)
- , TargetGenerator(g)
+ : cmVisualStudioGeneratorOptions(lg, tool, nullptr, nullptr, g)
{
- // Preprocessor definitions are not allowed for linker tools.
- this->AllowDefine = (tool != Linker);
-
- // Slash options are allowed for VS.
- this->AllowSlash = true;
-
- this->FortranRuntimeDebug = false;
- this->FortranRuntimeDLL = false;
- this->FortranRuntimeMT = false;
-
- this->UnknownFlagField = "AdditionalOptions";
}
cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
@@ -64,6 +49,9 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
// Preprocessor definitions are not allowed for linker tools.
this->AllowDefine = (tool != Linker);
+ // include directories are not allowed for linker tools.
+ this->AllowInclude = (tool != Linker);
+
// Slash options are allowed for VS.
this->AllowSlash = true;
@@ -511,6 +499,69 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
}
}
+void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories(
+ std::ostream& fout, const char* prefix, const char* suffix,
+ const std::string& lang)
+{
+ if (this->Includes.empty()) {
+ return;
+ }
+
+ const char* tag = "AdditionalIncludeDirectories";
+ if (lang == "CUDA") {
+ tag = "Include";
+ } else if (lang == "ASM_MASM" || lang == "ASM_NASM") {
+ tag = "IncludePaths";
+ }
+
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ // if there are configuration specific flags, then
+ // use the configuration specific tag for PreprocessorDefinitions
+ if (!this->Configuration.empty()) {
+ fout << prefix;
+ this->TargetGenerator->WritePlatformConfigTag(
+ tag, this->Configuration.c_str(), 0, 0, 0, &fout);
+ } else {
+ fout << prefix << "<" << tag << ">";
+ }
+ } else {
+ fout << prefix << tag << "=\"";
+ }
+
+ const char* sep = "";
+ for (std::string include : this->Includes) {
+ // first convert all of the slashes
+ std::string::size_type pos = 0;
+ while ((pos = include.find('/', pos)) != std::string::npos) {
+ include[pos] = '\\';
+ pos++;
+ }
+
+ if (lang == "ASM_NASM") {
+ include += "\\";
+ }
+
+ // Escape this include for the IDE.
+ fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10
+ ? cmVisualStudio10GeneratorOptionsEscapeForXML(include)
+ : cmVisualStudioGeneratorOptionsEscapeForXML(include));
+ sep = ";";
+
+ if (lang == "Fortran") {
+ include += "/$(ConfigurationName)";
+ fout << sep << (this->Version >= cmGlobalVisualStudioGenerator::VS10
+ ? cmVisualStudio10GeneratorOptionsEscapeForXML(include)
+ : cmVisualStudioGeneratorOptionsEscapeForXML(include));
+ }
+ }
+
+ if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
+ fout << sep << "%(" << tag << ")</" << tag << ">" << suffix;
+ } else {
+ fout << "\"" << suffix;
+ }
+}
+
void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout,
const char* indent)
{
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index 7c08a2c..2dffe9b 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -86,6 +86,10 @@ public:
void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix,
const char* suffix,
const std::string& lang);
+ void OutputAdditionalIncludeDirectories(std::ostream& fout,
+ const char* prefix,
+ const char* suffix,
+ const std::string& lang);
void OutputFlagMap(std::ostream& fout, const char* indent);
void SetConfiguration(const char* config);
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 506e995..cbfbd91 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -390,6 +390,9 @@ if(BUILD_TESTING)
endif()
ADD_TEST_MACRO(SourcesProperty SourcesProperty)
ADD_TEST_MACRO(SourceFileProperty SourceFileProperty)
+ if (NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ ADD_TEST_MACRO(SourceFileIncludeDirProperty SourceFileIncludeDirProperty)
+ endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU
AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
set(runCxxDialectTest 1)
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 4586357..19d12e5 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -260,17 +260,49 @@ add_custom_target(check-part4 ALL
#-----------------------------------------------------------------------------
# Cover source file properties with generator expressions.
-add_executable(srcgenex_flags srcgenex_flags.c)
-set_property(SOURCE srcgenex_flags.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
-
-add_executable(srcgenex_flags_COMPILE_LANGUAGE srcgenex_flags_COMPILE_LANGUAGE.c)
-set_property(SOURCE srcgenex_flags_COMPILE_LANGUAGE.c PROPERTY COMPILE_FLAGS "$<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>")
-
-add_executable(srcgenex_defs srcgenex_defs.c)
-set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>)
-
-add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c)
-set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
+## generate various source files
+foreach (item IN ITEMS flags flags_COMPILE_LANGUAGE
+ options options_COMPILE_LANGUAGE
+ defs defs_COMPILE_LANGUAGE)
+ set(TARGET_NAME srcgenex_${item})
+ configure_file(srcgenex.c.in ${TARGET_NAME}.c @ONLY)
+endforeach()
+add_executable(srcgenex_flags "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags.c"
+ PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>")
+add_executable(srcgenex_flags_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_flags_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_FLAGS "$<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>")
+
+add_executable(srcgenex_options "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options.c"
+ PROPERTY COMPILE_OPTIONS -DUNUSED -DNAME=$<TARGET_PROPERTY:NAME>)
+add_executable(srcgenex_options_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:C>:-DNAME=$<TARGET_PROPERTY:NAME>>)
+
+add_executable(srcgenex_defs "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c"
+ PROPERTY COMPILE_DEFINITIONS UNUSED NAME=$<TARGET_PROPERTY:NAME>)
+add_executable(srcgenex_defs_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs_COMPILE_LANGUAGE.c")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs_COMPILE_LANGUAGE.c"
+ PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>)
+
+foreach (item IN ITEMS basic COMPILE_LANGUAGE)
+ set(TARGET_NAME srcgenex_includes_${item})
+ configure_file(srcgenex_includes.h.in "sf_includes_${item}/${TARGET_NAME}.h" @ONLY)
+ configure_file(srcgenex_includes.c.in ${TARGET_NAME}.c @ONLY)
+endforeach()
+add_executable(srcgenex_includes_basic "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_basic.c")
+# first include directory is useless but ensure list aspect is tested
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_basic.c"
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/sf_includes_basic")
+if (CMAKE_GENERATOR MATCHES "Makefiles|Ninja|Watcom WMake")
+ add_executable(srcgenex_includes_COMPILE_LANGUAGE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_COMPILE_LANGUAGE.c")
+ # first include directory is useless but ensure list aspect is tested
+ set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_includes_COMPILE_LANGUAGE.c"
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_BINARY_DIR}/sf_includes_COMPILE_LANGUAGE>)
+endif()
#-----------------------------------------------------------------------------
# Cover test properties with generator expressions.
diff --git a/Tests/GeneratorExpression/srcgenex_defs.c b/Tests/GeneratorExpression/srcgenex.c.in
index 883e631..4a43bd1 100644
--- a/Tests/GeneratorExpression/srcgenex_defs.c
+++ b/Tests/GeneratorExpression/srcgenex.c.in
@@ -1,4 +1,4 @@
-int srcgenex_defs(void)
+int @TARGET_NAME@(void)
{
return 0;
}
diff --git a/Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c b/Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c
deleted file mode 100644
index 421b55b..0000000
--- a/Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c
+++ /dev/null
@@ -1,12 +0,0 @@
-int srcgenex_defs_COMPILE_LANGUAGE(void)
-{
- return 0;
-}
-
-int main(int argc, char* argv[])
-{
-#ifndef NAME
-#error NAME not defined
-#endif
- return NAME();
-}
diff --git a/Tests/GeneratorExpression/srcgenex_flags.c b/Tests/GeneratorExpression/srcgenex_flags.c
deleted file mode 100644
index 3de2b12..0000000
--- a/Tests/GeneratorExpression/srcgenex_flags.c
+++ /dev/null
@@ -1,12 +0,0 @@
-int srcgenex_flags(void)
-{
- return 0;
-}
-
-int main(int argc, char* argv[])
-{
-#ifndef NAME
-#error NAME not defined
-#endif
- return NAME();
-}
diff --git a/Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c b/Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c
deleted file mode 100644
index 4e80d6e..0000000
--- a/Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c
+++ /dev/null
@@ -1,12 +0,0 @@
-int srcgenex_flags_COMPILE_LANGUAGE(void)
-{
- return 0;
-}
-
-int main(int argc, char* argv[])
-{
-#ifndef NAME
-#error NAME not defined
-#endif
- return NAME();
-}
diff --git a/Tests/GeneratorExpression/srcgenex_includes.c.in b/Tests/GeneratorExpression/srcgenex_includes.c.in
new file mode 100644
index 0000000..b48d7df
--- /dev/null
+++ b/Tests/GeneratorExpression/srcgenex_includes.c.in
@@ -0,0 +1,12 @@
+
+#include "@TARGET_NAME@.h"
+
+int @TARGET_NAME@(void)
+{
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ return @TARGET_NAME@();
+}
diff --git a/Tests/GeneratorExpression/srcgenex_includes.h.in b/Tests/GeneratorExpression/srcgenex_includes.h.in
new file mode 100644
index 0000000..2259ca6
--- /dev/null
+++ b/Tests/GeneratorExpression/srcgenex_includes.h.in
@@ -0,0 +1,7 @@
+
+#if !defined @TARGET_NAME@_H
+#define @TARGET_NAME@_H
+
+int @TARGET_NAME@(void);
+
+#endif
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index e440b7f..d5bd297 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -176,6 +176,7 @@ add_RunCMake_test(CompileDefinitions)
add_RunCMake_test(CompileFeatures)
add_RunCMake_test(PolicyScope)
add_RunCMake_test(WriteCompilerDetectionHeader)
+add_RunCMake_test(SourceProperties)
if(NOT WIN32)
add_RunCMake_test(PositionIndependentCode)
endif()
diff --git a/Tests/RunCMake/SourceProperties/CMakeLists.txt b/Tests/RunCMake/SourceProperties/CMakeLists.txt
new file mode 100644
index 0000000..a17c8cd
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST} C)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt b/Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt b/Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt
new file mode 100644
index 0000000..cf146c2
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Found relative path while evaluating include directories of "empty.c":
+
+ "relative"
diff --git a/Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake b/Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake
new file mode 100644
index 0000000..08dffa8
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake
@@ -0,0 +1,4 @@
+
+set_property (SOURCE empty.c PROPERTY INCLUDE_DIRECTORIES "relative")
+
+add_library (somelib empty.c)
diff --git a/Tests/RunCMake/SourceProperties/RunCMakeTest.cmake b/Tests/RunCMake/SourceProperties/RunCMakeTest.cmake
new file mode 100644
index 0000000..0982153
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(RelativeIncludeDir)
diff --git a/Tests/RunCMake/SourceProperties/empty.c b/Tests/RunCMake/SourceProperties/empty.c
new file mode 100644
index 0000000..a9ec102
--- /dev/null
+++ b/Tests/RunCMake/SourceProperties/empty.c
@@ -0,0 +1,5 @@
+
+int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
new file mode 100644
index 0000000..f9b8ee7
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error in CMakeLists.txt:
+ Xcode does not support per-config per-source INCLUDE_DIRECTORIES:
+
+ \$<\$<CONFIG:Debug>:MYDEBUG>
+
+ specified for source:
+
+ .*/Tests/RunCMake/XcodeProject/main.c$
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake
new file mode 100644
index 0000000..4476c39
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(main main.c)
+set_property(SOURCE main.c PROPERTY INCLUDE_DIRECTORIES "$<$<CONFIG:Debug>:MYDEBUG>")
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
new file mode 100644
index 0000000..bfca020
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error in CMakeLists.txt:
+ Xcode does not support per-config per-source COMPILE_OPTIONS:
+
+ \$<\$<CONFIG:Debug>:-DMYDEBUG>
+
+ specified for source:
+
+ .*/Tests/RunCMake/XcodeProject/main.c$
diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake
new file mode 100644
index 0000000..f8e8030
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(main main.c)
+set_property(SOURCE main.c PROPERTY COMPILE_OPTIONS $<$<CONFIG:Debug>:-DMYDEBUG>)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 1313cb5..64a07f0 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -19,7 +19,9 @@ if (NOT XCODE_VERSION VERSION_LESS 6)
endif()
run_cmake(PerConfigPerSourceFlags)
+run_cmake(PerConfigPerSourceOptions)
run_cmake(PerConfigPerSourceDefinitions)
+run_cmake(PerConfigPerSourceIncludeDirs)
# Use a single build tree for a few tests without cleaning.
diff --git a/Tests/SourceFileIncludeDirProperty/CMakeLists.txt b/Tests/SourceFileIncludeDirProperty/CMakeLists.txt
new file mode 100644
index 0000000..786d5b6
--- /dev/null
+++ b/Tests/SourceFileIncludeDirProperty/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(SourceFileIncludeDirProperty C)
+
+#
+# Check that source level include directory take
+# precedence over target one
+
+add_executable(SourceFileIncludeDirProperty main.c)
+
+set_property (TARGET SourceFileIncludeDirProperty
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/target")
+
+set_property (SOURCE main.c
+ PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/source")
diff --git a/Tests/SourceFileIncludeDirProperty/main.c b/Tests/SourceFileIncludeDirProperty/main.c
new file mode 100644
index 0000000..36144ca
--- /dev/null
+++ b/Tests/SourceFileIncludeDirProperty/main.c
@@ -0,0 +1,7 @@
+
+#include "header.h"
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/SourceFileIncludeDirProperty/source/header.h b/Tests/SourceFileIncludeDirProperty/source/header.h
new file mode 100644
index 0000000..0c6f241
--- /dev/null
+++ b/Tests/SourceFileIncludeDirProperty/source/header.h
@@ -0,0 +1,2 @@
+
+/* used header file */
diff --git a/Tests/SourceFileIncludeDirProperty/target/header.h b/Tests/SourceFileIncludeDirProperty/target/header.h
new file mode 100644
index 0000000..71c1521
--- /dev/null
+++ b/Tests/SourceFileIncludeDirProperty/target/header.h
@@ -0,0 +1,2 @@
+
+#error "wrong header file"