Просмотр исходного кода

sourceFile properties: add property INCLUDE_DIRECTORIES

Marc Chevrier 8 лет назад
Родитель
Сommit
0448311179
38 измененных файлов с 350 добавлено и 23 удалено
  1. 1 0
      Help/manual/cmake-properties.7.rst
  2. 2 1
      Help/prop_sf/COMPILE_OPTIONS.rst
  3. 18 0
      Help/prop_sf/INCLUDE_DIRECTORIES.rst
  4. 0 4
      Help/release/dev/sourceFile-new-properties.rst
  5. 10 0
      Help/release/dev/src-new-properties-COMPILE_OPTIONS-and-INCLUDE_DIRECTORIES.rst
  6. 32 10
      Source/cmExtraSublimeTextGenerator.cxx
  7. 3 0
      Source/cmExtraSublimeTextGenerator.h
  8. 10 0
      Source/cmGlobalXCodeGenerator.cxx
  9. 48 0
      Source/cmLocalGenerator.cxx
  10. 17 0
      Source/cmLocalGenerator.h
  11. 12 1
      Source/cmLocalVisualStudio7Generator.cxx
  12. 20 2
      Source/cmMakefileTargetGenerator.cxx
  13. 25 1
      Source/cmNinjaTargetGenerator.cxx
  14. 3 0
      Source/cmNinjaTargetGenerator.h
  15. 18 1
      Source/cmServerProtocol.cxx
  16. 18 1
      Source/cmVisualStudio10TargetGenerator.cxx
  17. 3 0
      Tests/CMakeLists.txt
  18. 18 2
      Tests/GeneratorExpression/CMakeLists.txt
  19. 12 0
      Tests/GeneratorExpression/srcgenex_includes.c.in
  20. 7 0
      Tests/GeneratorExpression/srcgenex_includes.h.in
  21. 1 0
      Tests/RunCMake/CMakeLists.txt
  22. 3 0
      Tests/RunCMake/SourceProperties/CMakeLists.txt
  23. 1 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir-result.txt
  24. 4 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir-stderr.txt
  25. 4 0
      Tests/RunCMake/SourceProperties/RelativeIncludeDir.cmake
  26. 3 0
      Tests/RunCMake/SourceProperties/RunCMakeTest.cmake
  27. 5 0
      Tests/RunCMake/SourceProperties/empty.c
  28. 1 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-result.txt
  29. 8 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt
  30. 3 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs.cmake
  31. 1 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-result.txt
  32. 8 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt
  33. 3 0
      Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions.cmake
  34. 2 0
      Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
  35. 15 0
      Tests/SourceFileIncludeDirProperty/CMakeLists.txt
  36. 7 0
      Tests/SourceFileIncludeDirProperty/main.c
  37. 2 0
      Tests/SourceFileIncludeDirProperty/source/header.h
  38. 2 0
      Tests/SourceFileIncludeDirProperty/target/header.h

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -375,6 +375,7 @@ Properties on Source Files
    /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

+ 2 - 1
Help/prop_sf/COMPILE_OPTIONS.rst

@@ -6,7 +6,8 @@ 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.
+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

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

+ 0 - 4
Help/release/dev/sourceFile-new-properties.rst

@@ -1,4 +0,0 @@
-sourceFile-new-properties
--------------------------
-
-* The source files learn new property :prop_sf:`COMPILE_OPTIONS`.

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

+ 32 - 10
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,15 +354,6 @@ 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);
@@ -417,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;
 

+ 10 - 0
Source/cmGlobalXCodeGenerator.cxx

@@ -764,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);
 

+ 48 - 0
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__)
@@ -1959,6 +1961,52 @@ void cmLocalGenerator::AppendCompileOptions(
   }
 }
 
+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
 {

+ 17 - 0
Source/cmLocalGenerator.h

@@ -152,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.

+ 12 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -1396,6 +1396,7 @@ struct cmLVS7GFileConfig
   std::string CompileDefs;
   std::string CompileDefsConfig;
   std::string AdditionalDeps;
+  std::string IncludeDirs;
   bool ExcludedFromBuild;
 };
 
@@ -1484,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;
@@ -1661,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;
@@ -1673,6 +1680,10 @@ 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",

+ 20 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -455,10 +455,25 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
                           << "\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 =
@@ -575,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

+ 25 - 1
Source/cmNinjaTargetGenerator.cxx

@@ -211,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.
@@ -825,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);

+ 18 - 1
Source/cmServerProtocol.cxx

@@ -715,7 +715,24 @@ static Json::Value DumpSourceFilesList(
       }
       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;

+ 18 - 1
Source/cmVisualStudio10TargetGenerator.cxx

@@ -2024,6 +2024,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   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;
@@ -2039,6 +2041,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       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);
@@ -2091,7 +2098,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
     // if we have flags or defines for this config then
     // use them
     if (!flags.empty() || !options.empty() || !configDefines.empty() ||
-        compileAs || noWinRT) {
+        !includes.empty() || compileAs || noWinRT) {
       (*this->BuildFileStream) << firstString;
       firstString = ""; // only do firstString once
       hasFlags = true;
@@ -2150,6 +2157,16 @@ 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, "      ");

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

+ 18 - 2
Tests/GeneratorExpression/CMakeLists.txt

@@ -283,10 +283,26 @@ set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_options_COMPILE_LANGUA
 
 add_executable(srcgenex_defs "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c")
 set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/srcgenex_defs.c"
-             PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>)
+             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>>)
+               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.

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