Browse Source

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 <[email protected]>
Merge-request: !1596
Brad King 7 years ago
parent
commit
76f5a87cf1
51 changed files with 722 additions and 232 deletions
  1. 2 0
      Help/manual/cmake-properties.7.rst
  2. 17 0
      Help/prop_sf/COMPILE_OPTIONS.rst
  3. 18 0
      Help/prop_sf/INCLUDE_DIRECTORIES.rst
  4. 10 0
      Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst
  5. 41 12
      Source/cmExtraSublimeTextGenerator.cxx
  6. 3 0
      Source/cmExtraSublimeTextGenerator.h
  7. 16 1
      Source/cmGlobalXCodeGenerator.cxx
  8. 1 1
      Source/cmGlobalXCodeGenerator.h
  9. 42 0
      Source/cmIDEOptions.cxx
  10. 11 1
      Source/cmIDEOptions.h
  11. 92 15
      Source/cmLocalGenerator.cxx
  12. 37 3
      Source/cmLocalGenerator.h
  13. 3 3
      Source/cmLocalUnixMakefileGenerator3.cxx
  14. 3 2
      Source/cmLocalUnixMakefileGenerator3.h
  15. 39 63
      Source/cmLocalVisualStudio7Generator.cxx
  16. 3 3
      Source/cmLocalXCodeGenerator.cxx
  17. 1 1
      Source/cmLocalXCodeGenerator.h
  18. 30 2
      Source/cmMakefileTargetGenerator.cxx
  19. 36 5
      Source/cmNinjaTargetGenerator.cxx
  20. 3 0
      Source/cmNinjaTargetGenerator.h
  21. 23 1
      Source/cmServerProtocol.cxx
  22. 77 54
      Source/cmVisualStudio10TargetGenerator.cxx
  23. 4 1
      Source/cmVisualStudio10TargetGenerator.h
  24. 67 16
      Source/cmVisualStudioGeneratorOptions.cxx
  25. 4 0
      Source/cmVisualStudioGeneratorOptions.h
  26. 3 0
      Tests/CMakeLists.txt
  27. 43 11
      Tests/GeneratorExpression/CMakeLists.txt
  28. 1 1
      Tests/GeneratorExpression/srcgenex.c.in
  29. 0 12
      Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c
  30. 0 12
      Tests/GeneratorExpression/srcgenex_flags.c
  31. 0 12
      Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c
  32. 12 0
      Tests/GeneratorExpression/srcgenex_includes.c.in
  33. 7 0
      Tests/GeneratorExpression/srcgenex_includes.h.in
  34. 1 0
      Tests/RunCMake/CMakeLists.txt
  35. 3 0
      Tests/RunCMake/SourceProperties/CMakeLists.txt
  36. 1 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt
  37. 4 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt
  38. 4 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake
  39. 3 0
      Tests/RunCMake/SourceProperties/RunCMakeTest.cmake
  40. 5 0
      Tests/RunCMake/SourceProperties/empty.c
  41. 1 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt
  42. 8 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
  43. 3 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake
  44. 1 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt
  45. 8 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
  46. 3 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake
  47. 2 0
      Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
  48. 15 0
      Tests/SourceFileIncludeDirProperty/CMakeLists.txt
  49. 7 0
      Tests/SourceFileIncludeDirProperty/main.c
  50. 2 0
      Tests/SourceFileIncludeDirProperty/source/header.h
  51. 2 0
      Tests/SourceFileIncludeDirProperty/target/header.h

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

+ 17 - 0
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.

+ 18 - 0
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.

+ 10 - 0
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.

+ 41 - 12
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)

+ 3 - 0
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;
 

+ 16 - 1
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()) {

+ 1 - 1
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;

+ 42 - 0
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;

+ 11 - 1
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

+ 92 - 15
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
 {

+ 37 - 3
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);
@@ -151,6 +152,23 @@ public:
     const std::string& name) const;
   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.
@@ -165,6 +183,22 @@ public:
   void AppendDefines(std::set<std::string>& defines,
                      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.
    */

+ 3 - 3
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);
 }

+ 3 - 2
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

+ 39 - 63
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);
           }

+ 3 - 3
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);
 }
 

+ 1 - 1
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(

+ 30 - 2
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

+ 36 - 5
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);

+ 3 - 0
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);

+ 23 - 1
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;

+ 77 - 54
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>

+ 4 - 1
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;

+ 67 - 16
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)
 {

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

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

+ 43 - 11
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.

+ 1 - 1
Tests/GeneratorExpression/srcgenex_defs.c → Tests/GeneratorExpression/srcgenex.c.in

@@ -1,4 +1,4 @@
-int srcgenex_defs(void)
+int @TARGET_NAME@(void)
 {
   return 0;
 }

+ 0 - 12
Tests/GeneratorExpression/srcgenex_defs_COMPILE_LANGUAGE.c

@@ -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();
-}

+ 0 - 12
Tests/GeneratorExpression/srcgenex_flags.c

@@ -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();
-}

+ 0 - 12
Tests/GeneratorExpression/srcgenex_flags_COMPILE_LANGUAGE.c

@@ -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();
-}

+ 12 - 0
Tests/GeneratorExpression/srcgenex_includes.c.in

@@ -0,0 +1,12 @@
+
+#include "@[email protected]"
+
+int @TARGET_NAME@(void)
+{
+  return 0;
+}
+
+int main(int argc, char* argv[])
+{
+  return @TARGET_NAME@();
+}

+ 7 - 0
Tests/GeneratorExpression/srcgenex_includes.h.in

@@ -0,0 +1,7 @@
+
+#if !defined @TARGET_NAME@_H
+#define @TARGET_NAME@_H
+
+int @TARGET_NAME@(void);
+
+#endif

+ 1 - 0
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()

+ 3 - 0
Tests/RunCMake/SourceProperties/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST} C)
+include(${RunCMake_TEST}.cmake)

+ 1 - 0
Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt

@@ -0,0 +1 @@
+1

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

+ 4 - 0
Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake

@@ -0,0 +1,4 @@
+
+set_property (SOURCE empty.c PROPERTY INCLUDE_DIRECTORIES "relative")
+
+add_library (somelib empty.c)

+ 3 - 0
Tests/RunCMake/SourceProperties/RunCMakeTest.cmake

@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(RelativeIncludeDir)

+ 5 - 0
Tests/RunCMake/SourceProperties/empty.c

@@ -0,0 +1,5 @@
+
+int empty()
+{
+  return 0;
+}

+ 1 - 0
Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt

@@ -0,0 +1 @@
+1

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

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

+ 1 - 0
Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt

@@ -0,0 +1 @@
+1

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

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

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

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

+ 7 - 0
Tests/SourceFileIncludeDirProperty/main.c

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

+ 2 - 0
Tests/SourceFileIncludeDirProperty/source/header.h

@@ -0,0 +1,2 @@
+
+/* used header file */

+ 2 - 0
Tests/SourceFileIncludeDirProperty/target/header.h

@@ -0,0 +1,2 @@
+
+#error "wrong header file"