1
0
Эх сурвалжийг харах

Merge topic 'target-sources-refactor'

5de63265 Genex: Only evaluate TARGET_OBJECTS to determine target sources.
aa0a3562 cmGeneratorTarget: Compute target objects on demand
042c1c83 cmTarget: Compute languages from object libraries on demand.
fdcefe3c cmGeneratorTarget: Compute consumed object libraries on demand.
c355d108 cmComputeTargetDepends: Track object library depends.
e5da9e51 cmTarget: Allow any generator expression in SOURCES property.
5702e106 cmTarget: Include TARGET_OBJECTS genex in target SOURCES property.
857d30b5 cmGlobalGenerator: Add interface to call ForceLinkerLanguages
28e1d2f8 cmStringCommand: Add GENEX_STRIP subcommand.
bf98cc25 Genex: Evaluate TARGET_OBJECTS as a normal expression.
8cd113ad cmTarget: Store strings instead of cmSourceFile* to represent SOURCES.
4959f341 cmSourceFileLocation: Collapse full path for directory comparisons.
fcc92878 cmSourceFileLocation: Remove unused Update method.
59e8740a cmTarget: Remove AddSourceFile method
26d494ba cmTarget: Use string API to add sources to cmTarget objects.
d38423ec cmTarget: Add a method to obtain list of filenames for sources.
...
Brad King 11 жил өмнө
parent
commit
93054aa84f
64 өөрчлөгдсөн 778 нэмэгдсэн , 271 устгасан
  1. 5 2
      Help/command/add_executable.rst
  2. 4 2
      Help/command/add_library.rst
  3. 5 0
      Help/command/string.rst
  4. 5 0
      Help/manual/cmake-generator-expressions.7.rst
  5. 1 0
      Help/manual/cmake-policies.7.rst
  6. 24 0
      Help/policy/CMP0051.rst
  7. 6 0
      Help/release/dev/string-GENEX_STRIP.rst
  8. 12 0
      Help/release/dev/target-SOURCES-genex.rst
  9. 29 0
      Source/cmComputeTargetDepends.cxx
  10. 1 1
      Source/cmFLTKWrapUICommand.cxx
  11. 3 1
      Source/cmGeneratorExpression.cxx
  12. 6 0
      Source/cmGeneratorExpression.h
  13. 74 0
      Source/cmGeneratorExpressionEvaluator.cxx
  14. 1 0
      Source/cmGeneratorExpressionEvaluator.h
  15. 56 72
      Source/cmGeneratorTarget.cxx
  16. 3 5
      Source/cmGeneratorTarget.h
  17. 8 48
      Source/cmGlobalGenerator.cxx
  18. 2 2
      Source/cmGlobalGenerator.h
  19. 2 1
      Source/cmGlobalVisualStudio8Generator.cxx
  20. 11 7
      Source/cmGlobalXCodeGenerator.cxx
  21. 2 2
      Source/cmLocalGenerator.cxx
  22. 13 3
      Source/cmLocalVisualStudio6Generator.cxx
  23. 6 2
      Source/cmLocalVisualStudio7Generator.cxx
  24. 2 2
      Source/cmMakefile.cxx
  25. 0 3
      Source/cmMakefileTargetGenerator.cxx
  26. 0 11
      Source/cmNinjaTargetGenerator.cxx
  27. 5 0
      Source/cmPolicies.cxx
  28. 1 0
      Source/cmPolicies.h
  29. 7 10
      Source/cmQtAutoGenerators.cxx
  30. 12 0
      Source/cmSourceFile.cxx
  31. 4 0
      Source/cmSourceFile.h
  32. 46 24
      Source/cmSourceFileLocation.cxx
  33. 3 2
      Source/cmSourceFileLocation.h
  34. 25 0
      Source/cmStringCommand.cxx
  35. 1 0
      Source/cmStringCommand.h
  36. 251 62
      Source/cmTarget.cxx
  37. 2 7
      Source/cmTarget.h
  38. 13 0
      Source/cmVisualStudio10TargetGenerator.cxx
  39. 1 1
      Tests/GeneratorExpression/CMakeLists.txt
  40. 2 0
      Tests/Properties/CMakeLists.txt
  41. 5 0
      Tests/Properties/SubDir2/CMakeLists.txt
  42. 9 0
      Tests/Properties/subdirtest.cxx
  43. 1 0
      Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt
  44. 1 0
      Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt
  45. 10 0
      Tests/RunCMake/CMP0051/CMP0051-NEW.cmake
  46. 1 0
      Tests/RunCMake/CMP0051/CMP0051-OLD-result.txt
  47. 1 0
      Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt
  48. 10 0
      Tests/RunCMake/CMP0051/CMP0051-OLD.cmake
  49. 1 0
      Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt
  50. 15 0
      Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt
  51. 8 0
      Tests/RunCMake/CMP0051/CMP0051-WARN.cmake
  52. 3 0
      Tests/RunCMake/CMP0051/CMakeLists.txt
  53. 5 0
      Tests/RunCMake/CMP0051/RunCMakeTest.cmake
  54. 7 0
      Tests/RunCMake/CMP0051/empty.cpp
  55. 2 0
      Tests/RunCMake/CMakeLists.txt
  56. 3 1
      Tests/RunCMake/ObjectLibrary/BadSourceExpression1-stderr.txt
  57. 4 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression2-stderr.txt
  58. 4 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
  59. 1 0
      Tests/RunCMake/TargetObjects/BadContext-result.txt
  60. 17 0
      Tests/RunCMake/TargetObjects/BadContext-stderr.txt
  61. 4 0
      Tests/RunCMake/TargetObjects/BadContext.cmake
  62. 3 0
      Tests/RunCMake/TargetObjects/CMakeLists.txt
  63. 3 0
      Tests/RunCMake/TargetObjects/RunCMakeTest.cmake
  64. 6 0
      Tests/StringFileTest/CMakeLists.txt

+ 5 - 2
Help/command/add_executable.rst

@@ -35,8 +35,11 @@ If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
 the created target.  See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
 target property for details.
 
-See the :manual:`cmake-buildsystem(7)` manual for more on defining
-buildsystem properties.
+Source arguments to ``add_executable`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
 
 --------------------------------------------------------------------------
 

+ 4 - 2
Help/command/add_library.rst

@@ -39,8 +39,10 @@ If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
 the created target.  See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
 target property for details.
 
-See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem
-properties.
+Source arguments to ``add_library`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
 
 --------------------------------------------------------------------------
 

+ 5 - 0
Help/command/string.rst

@@ -35,6 +35,7 @@ String operations.
   string(FIND <string> <substring> <output variable> [REVERSE])
   string(TIMESTAMP <output variable> [<format string>] [UTC])
   string(MAKE_C_IDENTIFIER <input string> <output variable>)
+  string(GENEX_STRIP <input string> <output variable>)
 
 REGEX MATCH will match the regular expression once and store the match
 in the output variable.
@@ -154,3 +155,7 @@ If no explicit <format string> is given it will default to:
 
 MAKE_C_IDENTIFIER will write a string which can be used as an
 identifier in C.
+
+``GENEX_STRIP`` will strip any
+:manual:`generator expressions <cmake-generator-expressions(7)>` from the
+``input string`` and store the result in the ``output variable``.

+ 5 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -188,3 +188,8 @@ property is non-empty::
   Content of ``...`` converted to upper case.
 ``$<MAKE_C_IDENTIFIER:...>``
   Content of ``...`` converted to a C identifier.
+``$<TARGET_OBJECTS:objLib>``
+  List of objects resulting from build of ``objLib``. ``objLib`` must be an
+  object of type ``OBJECT_LIBRARY``.  This expression may only be used in
+  the sources of :command:`add_library` and :command:`add_executable`
+  commands.

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

@@ -102,3 +102,4 @@ All Policies
    /policy/CMP0048
    /policy/CMP0049
    /policy/CMP0050
+   /policy/CMP0051

+ 24 - 0
Help/policy/CMP0051.rst

@@ -0,0 +1,24 @@
+CMP0051
+-------
+
+List TARGET_OBJECTS in SOURCES target property.
+
+CMake 3.0 and lower did not include the ``TARGET_OBJECTS``
+:manual:`generator expression <cmake-generator-expressions(7)>` when
+returning the :prop_tgt:`SOURCES` target property.
+
+Configure-time CMake code is not able to handle generator expressions.  If
+using the :prop_tgt:`SOURCES` target property at configure time, it may be
+necessary to first remove generator expressions using the
+:command:`string(STRIP_GENEX)` command.  Generate-time CMake code such as
+:command:`file(GENERATE)` can handle the content without stripping.
+
+The ``OLD`` behavior for this policy is to omit ``TARGET_OBJECTS``
+expressions from the :prop_tgt:`SOURCES` target property.  The ``NEW``
+behavior for this policy is to include ``TARGET_OBJECTS`` expressions
+in the output.
+
+This policy was introduced in CMake version 3.1.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior.  Use the :command:`cmake_policy` command to set it
+to ``OLD`` or ``NEW`` explicitly.

+ 6 - 0
Help/release/dev/string-GENEX_STRIP.rst

@@ -0,0 +1,6 @@
+string-GENEX_STRIP
+------------------
+
+* The :command:`string` command learned a new ``GENEX_STRIP`` subcommand
+  which removes
+  :manual:`generator expression <cmake-generator-expressions(7)>`.

+ 12 - 0
Help/release/dev/target-SOURCES-genex.rst

@@ -0,0 +1,12 @@
+target-SOURCES-genex
+--------------------
+
+* The :prop_tgt:`SOURCES` target property now contains
+  :manual:`generator expression <cmake-generator-expressions(7)>`
+  such as ``TARGET_OBJECTS`` when read at configure time, if
+  policy :policy:`CMP0051` is ``NEW``.
+
+* The :prop_tgt:`SOURCES` target property now generally supports
+  :manual:`generator expression <cmake-generator-expressions(7)>`.  The
+  generator expressions may be used in the :command:`add_library` and
+  :command:`add_executable` commands.

+ 29 - 0
Source/cmComputeTargetDepends.cxx

@@ -16,6 +16,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
+#include "cmSourceFile.h"
 #include "cmTarget.h"
 #include "cmake.h"
 
@@ -213,6 +214,34 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
   {
   std::set<std::string> emitted;
   {
+  cmGeneratorTarget* gt = depender->GetMakefile()->GetLocalGenerator()
+                                  ->GetGlobalGenerator()
+                                  ->GetGeneratorTarget(depender);
+  std::vector<cmSourceFile const*> objectFiles;
+  gt->GetExternalObjects(objectFiles);
+  for(std::vector<cmSourceFile const*>::const_iterator
+      it = objectFiles.begin(); it != objectFiles.end(); ++it)
+    {
+    std::string objLib = (*it)->GetObjectLibrary();
+    if (!objLib.empty() && emitted.insert(objLib).second)
+      {
+      if(depender->GetType() != cmTarget::EXECUTABLE &&
+          depender->GetType() != cmTarget::STATIC_LIBRARY &&
+          depender->GetType() != cmTarget::SHARED_LIBRARY &&
+          depender->GetType() != cmTarget::MODULE_LIBRARY)
+        {
+        this->GlobalGenerator->GetCMakeInstance()
+          ->IssueMessage(cmake::FATAL_ERROR,
+                          "Only executables and non-OBJECT libraries may "
+                          "reference target objects.",
+                          depender->GetBacktrace());
+        return;
+        }
+      const_cast<cmTarget*>(depender)->AddUtility(objLib);
+      }
+    }
+  }
+  {
   std::vector<std::string> tlibs;
   depender->GetDirectLinkLibraries("", tlibs, depender);
   // A target should not depend on itself.

+ 1 - 1
Source/cmFLTKWrapUICommand.cxx

@@ -168,7 +168,7 @@ void cmFLTKWrapUICommand::FinalPass()
     for(size_t classNum = 0; classNum < lastHeadersClass; classNum++)
       {
       this->Makefile->GetTargets()[this->Target]
-        .AddSourceFile(this->GeneratedSourcesClasses[classNum]);
+        .AddSource(this->GeneratedSourcesClasses[classNum]->GetFullPath());
       }
     }
 }

+ 3 - 1
Source/cmGeneratorExpression.cxx

@@ -90,6 +90,7 @@ const char *cmCompiledGeneratorExpression::Evaluate(
   context.HadError = false;
   context.HadContextSensitiveCondition = false;
   context.HeadTarget = headTarget;
+  context.EvaluateForBuildsystem = this->EvaluateForBuildsystem;
   context.CurrentTarget = currentTarget ? currentTarget : headTarget;
   context.Backtrace = this->Backtrace;
 
@@ -124,7 +125,8 @@ cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
               cmListFileBacktrace const& backtrace,
               const std::string& input)
   : Backtrace(backtrace), Input(input),
-    HadContextSensitiveCondition(false)
+    HadContextSensitiveCondition(false),
+    EvaluateForBuildsystem(false)
 {
   cmGeneratorExpressionLexer l;
   std::vector<cmGeneratorExpressionToken> tokens =

+ 6 - 0
Source/cmGeneratorExpression.h

@@ -112,6 +112,11 @@ public:
     return this->HadContextSensitiveCondition;
   }
 
+  void SetEvaluateForBuildsystem(bool eval)
+  {
+    this->EvaluateForBuildsystem = eval;
+  }
+
 private:
   cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
               const std::string& input);
@@ -131,6 +136,7 @@ private:
   mutable std::set<std::string> SeenTargetProperties;
   mutable std::string Output;
   mutable bool HadContextSensitiveCondition;
+  bool EvaluateForBuildsystem;
 };
 
 #endif

+ 74 - 0
Source/cmGeneratorExpressionEvaluator.cxx

@@ -15,6 +15,8 @@
 #include "cmGeneratorExpressionParser.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmSourceFile.h"
 
 #include <cmsys/String.h>
 
@@ -1239,6 +1241,77 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
 
 } targetNameNode;
 
+//----------------------------------------------------------------------------
+static const struct TargetObjectsNode : public cmGeneratorExpressionNode
+{
+  TargetObjectsNode() {}
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    if (!context->EvaluateForBuildsystem)
+      {
+      cmOStringStream e;
+      e << "The evaluation of the TARGET_OBJECTS generator expression "
+        "is only suitable for consumption by CMake.  It is not suitable "
+        "for writing out elsewhere.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+      }
+
+    std::string tgtName = parameters.front();
+    cmGeneratorTarget* gt =
+                context->Makefile->FindGeneratorTargetToUse(tgtName.c_str());
+    if (!gt)
+      {
+      cmOStringStream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but no such target exists.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+      }
+    if (gt->GetType() != cmTarget::OBJECT_LIBRARY)
+      {
+      cmOStringStream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but is not an OBJECT library.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+      }
+
+    std::vector<cmSourceFile const*> objectSources;
+    gt->GetObjectSources(objectSources);
+    std::map<cmSourceFile const*, std::string> mapping;
+
+    for(std::vector<cmSourceFile const*>::const_iterator it
+        = objectSources.begin(); it != objectSources.end(); ++it)
+      {
+      mapping[*it];
+      }
+
+    gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
+
+    std::string obj_dir = gt->ObjectDirectory;
+    std::string result;
+    const char* sep = "";
+    for(std::map<cmSourceFile const*, std::string>::const_iterator it
+        = mapping.begin(); it != mapping.end(); ++it)
+      {
+      assert(!it->second.empty());
+      result += sep;
+      std::string objFile = obj_dir + it->second;
+      cmSourceFile* sf = context->Makefile->GetOrCreateSource(objFile, true);
+      sf->SetObjectLibrary(tgtName);
+      sf->SetProperty("EXTERNAL_OBJECT", "1");
+      result += objFile;
+      sep = ";";
+      }
+    return result;
+  }
+} targetObjectsNode;
+
 //----------------------------------------------------------------------------
 static const char* targetPolicyWhitelist[] = {
   0
@@ -1593,6 +1666,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     nodeMap["SEMICOLON"] = &semicolonNode;
     nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
     nodeMap["TARGET_NAME"] = &targetNameNode;
+    nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
     nodeMap["TARGET_POLICY"] = &targetPolicyNode;
     nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
     nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;

+ 1 - 0
Source/cmGeneratorExpressionEvaluator.h

@@ -34,6 +34,7 @@ struct cmGeneratorExpressionContext
   bool Quiet;
   bool HadError;
   bool HadContextSensitiveCondition;
+  bool EvaluateForBuildsystem;
 };
 
 struct cmGeneratorExpressionDAGChecker;

+ 56 - 72
Source/cmGeneratorTarget.cxx

@@ -311,18 +311,36 @@ cmGeneratorTarget
 ::GetObjectSources(std::vector<cmSourceFile const*> &data) const
 {
   IMPLEMENT_VISIT(ObjectSources);
+
+  if (!this->Objects.empty())
+    {
+    return;
+    }
+
+  for(std::vector<cmSourceFile const*>::const_iterator it = data.begin();
+      it != data.end(); ++it)
+    {
+    this->Objects[*it];
+    }
+
+  this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
 }
 
-//----------------------------------------------------------------------------
-const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
+void cmGeneratorTarget::ComputeObjectMapping()
 {
-  return this->Objects[file];
+  if(!this->Objects.empty())
+    {
+    return;
+    }
+  std::vector<cmSourceFile const*> sourceFiles;
+  this->GetObjectSources(sourceFiles);
 }
 
-void cmGeneratorTarget::AddObject(cmSourceFile const* sf,
-                                  std::string const&name)
+//----------------------------------------------------------------------------
+const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
 {
-    this->Objects[sf] = name;
+  this->ComputeObjectMapping();
+  return this->Objects[file];
 }
 
 //----------------------------------------------------------------------------
@@ -334,6 +352,7 @@ void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
 //----------------------------------------------------------------------------
 bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
 {
+  const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
   std::set<cmSourceFile const*>::const_iterator it
                                         = this->ExplicitObjectName.find(file);
   return it != this->ExplicitObjectName.end();
@@ -503,58 +522,6 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const
   this->Target->GetSourceFiles(files);
 }
 
-//----------------------------------------------------------------------------
-void cmGeneratorTarget::LookupObjectLibraries()
-{
-  std::vector<std::string> const& objLibs =
-    this->Target->GetObjectLibraries();
-  for(std::vector<std::string>::const_iterator oli = objLibs.begin();
-      oli != objLibs.end(); ++oli)
-    {
-    std::string const& objLibName = *oli;
-    if(cmTarget* objLib = this->Makefile->FindTargetToUse(objLibName))
-      {
-      if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
-        {
-        if(this->Target->GetType() != cmTarget::EXECUTABLE &&
-           this->Target->GetType() != cmTarget::STATIC_LIBRARY &&
-           this->Target->GetType() != cmTarget::SHARED_LIBRARY &&
-           this->Target->GetType() != cmTarget::MODULE_LIBRARY)
-          {
-          this->GlobalGenerator->GetCMakeInstance()
-            ->IssueMessage(cmake::FATAL_ERROR,
-                           "Only executables and non-OBJECT libraries may "
-                           "reference target objects.",
-                           this->Target->GetBacktrace());
-          return;
-          }
-        this->Target->AddUtility(objLib->GetName());
-        this->ObjectLibraries.push_back(objLib);
-        }
-      else
-        {
-        cmOStringStream e;
-        e << "Objects of target \"" << objLibName
-          << "\" referenced but is not an OBJECT library.";
-        this->GlobalGenerator->GetCMakeInstance()
-          ->IssueMessage(cmake::FATAL_ERROR, e.str(),
-                         this->Target->GetBacktrace());
-        return;
-        }
-      }
-    else
-      {
-      cmOStringStream e;
-      e << "Objects of target \"" << objLibName
-        << "\" referenced but no such target exists.";
-      this->GlobalGenerator->GetCMakeInstance()
-        ->IssueMessage(cmake::FATAL_ERROR, e.str(),
-                       this->Target->GetBacktrace());
-      return;
-      }
-    }
-}
-
 //----------------------------------------------------------------------------
 std::string cmGeneratorTarget::GetModuleDefinitionFile() const
 {
@@ -567,9 +534,26 @@ std::string cmGeneratorTarget::GetModuleDefinitionFile() const
 void
 cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs) const
 {
+  std::vector<cmSourceFile const*> objectFiles;
+  this->GetExternalObjects(objectFiles);
+  std::vector<cmTarget*> objectLibraries;
+  std::set<cmTarget*> emitted;
+  for(std::vector<cmSourceFile const*>::const_iterator
+      it = objectFiles.begin(); it != objectFiles.end(); ++it)
+    {
+    std::string objLib = (*it)->GetObjectLibrary();
+    if (cmTarget* tgt = this->Makefile->FindTargetToUse(objLib))
+      {
+      if (emitted.insert(tgt).second)
+        {
+        objectLibraries.push_back(tgt);
+        }
+      }
+    }
+
   for(std::vector<cmTarget*>::const_iterator
-        ti = this->ObjectLibraries.begin();
-      ti != this->ObjectLibraries.end(); ++ti)
+        ti = objectLibraries.begin();
+      ti != objectLibraries.end(); ++ti)
     {
     cmTarget* objLib = *ti;
     cmGeneratorTarget* ogt =
@@ -600,12 +584,12 @@ private:
   cmGlobalGenerator const* GlobalGenerator;
   typedef cmGeneratorTarget::SourceEntry SourceEntry;
   SourceEntry* CurrentEntry;
-  std::queue<cmSourceFile*> SourceQueue;
-  std::set<cmSourceFile*> SourcesQueued;
+  std::queue<std::string> SourceQueue;
+  std::set<std::string> SourcesQueued;
   typedef std::map<std::string, cmSourceFile*> NameMapType;
   NameMapType NameMap;
 
-  void QueueSource(cmSourceFile* sf);
+  void QueueSource(std::string const& name);
   void FollowName(std::string const& name);
   void FollowNames(std::vector<std::string> const& names);
   bool IsUtility(std::string const& dep);
@@ -628,11 +612,11 @@ cmTargetTraceDependencies
   this->CurrentEntry = 0;
 
   // Queue all the source files already specified for the target.
-  std::vector<cmSourceFile*> sources;
   if (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
     {
+    std::vector<std::string> sources;
     this->Target->GetSourceFiles(sources);
-    for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+    for(std::vector<std::string>::const_iterator si = sources.begin();
         si != sources.end(); ++si)
       {
       this->QueueSource(*si);
@@ -652,7 +636,8 @@ void cmTargetTraceDependencies::Trace()
   while(!this->SourceQueue.empty())
     {
     // Get the next source from the queue.
-    cmSourceFile* sf = this->SourceQueue.front();
+    std::string src = this->SourceQueue.front();
+    cmSourceFile* sf = this->Makefile->GetSource(src);
     this->SourceQueue.pop();
     this->CurrentEntry = &this->GeneratorTarget->SourceEntries[sf];
 
@@ -680,14 +665,14 @@ void cmTargetTraceDependencies::Trace()
 }
 
 //----------------------------------------------------------------------------
-void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
+void cmTargetTraceDependencies::QueueSource(std::string const& name)
 {
-  if(this->SourcesQueued.insert(sf).second)
+  if(this->SourcesQueued.insert(name).second)
     {
-    this->SourceQueue.push(sf);
+    this->SourceQueue.push(name);
 
     // Make sure this file is in the target.
-    this->Target->AddSourceFile(sf);
+    this->Target->AddSource(name);
     }
 }
 
@@ -709,8 +694,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
       {
       this->CurrentEntry->Depends.push_back(sf);
       }
-
-    this->QueueSource(sf);
+    this->QueueSource(sf->GetFullPath());
     }
 }
 

+ 3 - 5
Source/cmGeneratorTarget.h

@@ -35,7 +35,6 @@ public:
   void GetObjectSources(std::vector<cmSourceFile const*> &) const;
   const std::string& GetObjectName(cmSourceFile const* file);
 
-  void AddObject(cmSourceFile const* sf, std::string const&name);
   bool HasExplicitObjectName(cmSourceFile const* file) const;
   void AddExplicitObjectName(cmSourceFile const* sf);
 
@@ -47,6 +46,8 @@ public:
   void GetCustomCommands(std::vector<cmSourceFile const*>&) const;
   void GetExpectedResxHeaders(std::set<std::string>&) const;
 
+  void ComputeObjectMapping();
+
   cmTarget* Target;
   cmMakefile* Makefile;
   cmLocalGenerator* LocalGenerator;
@@ -84,8 +85,6 @@ public:
    */
   void TraceDependencies();
 
-  void LookupObjectLibraries();
-
   /** Get sources that must be built before the given source.  */
   std::vector<cmSourceFile*> const*
   GetSourceDepends(cmSourceFile const* sf) const;
@@ -125,9 +124,8 @@ private:
   typedef std::map<cmSourceFile const*, SourceEntry> SourceEntriesType;
   SourceEntriesType SourceEntries;
 
-  std::map<cmSourceFile const*, std::string> Objects;
+  mutable std::map<cmSourceFile const*, std::string> Objects;
   std::set<cmSourceFile const*> ExplicitObjectName;
-  std::vector<cmTarget*> ObjectLibraries;
   mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache;
 
   void ConstructSourceFileFlags() const;

+ 8 - 48
Source/cmGlobalGenerator.cxx

@@ -216,6 +216,11 @@ bool cmGlobalGenerator::GenerateImportFile(const std::string &file)
   return false;
 }
 
+void cmGlobalGenerator::ForceLinkerLanguages()
+{
+
+}
+
 bool
 cmGlobalGenerator::IsExportedTargetsFile(const std::string &filename) const
 {
@@ -1196,6 +1201,8 @@ void cmGlobalGenerator::Generate()
   // Create per-target generator information.
   this->CreateGeneratorTargets();
 
+  this->ForceLinkerLanguages();
+
 #ifdef CMAKE_BUILD_WITH_CMAKE
   for (AutogensType::iterator it = autogens.begin(); it != autogens.end();
        ++it)
@@ -1217,8 +1224,6 @@ void cmGlobalGenerator::Generate()
     this->LocalGenerators[i]->GenerateTargetManifest();
     }
 
-  this->ComputeGeneratorTargetObjects();
-
   this->ProcessEvaluationFiles();
 
   // Compute the inter-target dependencies.
@@ -1409,6 +1414,7 @@ void cmGlobalGenerator::CreateGeneratorTargets(cmMakefile *mf)
     {
     cmTarget* t = &ti->second;
     cmGeneratorTarget* gt = new cmGeneratorTarget(t);
+    this->ComputeTargetObjectDirectory(gt);
     this->GeneratorTargets[t] = gt;
     generatorTargets[t] = gt;
     }
@@ -1434,29 +1440,6 @@ void cmGlobalGenerator::CreateGeneratorTargets()
     }
 }
 
-//----------------------------------------------------------------------------
-void cmGlobalGenerator::ComputeGeneratorTargetObjects()
-{
-  // Construct per-target generator information.
-  for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
-    {
-    cmMakefile *mf = this->LocalGenerators[i]->GetMakefile();
-    cmGeneratorTargetsType targets = mf->GetGeneratorTargets();
-    for(cmGeneratorTargetsType::iterator ti = targets.begin();
-        ti != targets.end(); ++ti)
-      {
-      if (ti->second->Target->IsImported()
-          || ti->second->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
-        {
-        continue;
-        }
-      cmGeneratorTarget* gt = ti->second;
-      this->ComputeTargetObjectDirectory(gt);
-      gt->LookupObjectLibraries();
-      this->ComputeTargetObjects(gt);
-      }
-    }
-}
 
 //----------------------------------------------------------------------------
 void cmGlobalGenerator::ClearGeneratorMembers()
@@ -1517,29 +1500,6 @@ cmGlobalGenerator::GetGeneratorTarget(cmTarget const* t) const
   return ti->second;
 }
 
-//----------------------------------------------------------------------------
-void cmGlobalGenerator::ComputeTargetObjects(cmGeneratorTarget* gt) const
-{
-  std::vector<cmSourceFile const*> objectSources;
-  gt->GetObjectSources(objectSources);
-
-  std::map<cmSourceFile const*, std::string> mapping;
-  for(std::vector<cmSourceFile const*>::const_iterator it
-      = objectSources.begin(); it != objectSources.end(); ++it)
-    {
-    mapping[*it];
-    }
-
-  gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
-
-  for(std::map<cmSourceFile const*, std::string>::const_iterator it
-      = mapping.begin(); it != mapping.end(); ++it)
-    {
-    assert(!it->second.empty());
-    gt->AddObject(it->first, it->second);
-    }
-}
-
 //----------------------------------------------------------------------------
 void cmGlobalGenerator::ComputeTargetObjectDirectory(cmGeneratorTarget*) const
 {

+ 2 - 2
Source/cmGlobalGenerator.h

@@ -423,6 +423,8 @@ private:
   void WriteSummary(cmTarget* target);
   void FinalizeTargetCompileInfo();
 
+  virtual void ForceLinkerLanguages();
+
   virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
                                    const char* envVar) const;
   void CheckCompilerIdCompatibility(cmMakefile* mf,
@@ -442,8 +444,6 @@ private:
   friend class cmake;
   void CreateGeneratorTargets(cmMakefile* mf);
   void CreateGeneratorTargets();
-  void ComputeGeneratorTargetObjects();
-  void ComputeTargetObjects(cmGeneratorTarget* gt) const;
 
   void ClearGeneratorMembers();
 

+ 2 - 1
Source/cmGlobalVisualStudio8Generator.cxx

@@ -16,6 +16,7 @@
 #include "cmVisualStudioWCEPlatformParser.h"
 #include "cmake.h"
 #include "cmGeneratedFileStream.h"
+#include "cmSourceFile.h"
 
 static const char vs8generatorName[] = "Visual Studio 8 2005";
 
@@ -323,7 +324,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
        no_main_dependency, commandLines, "Checking Build System",
        no_working_directory, true))
     {
-    tgt->AddSourceFile(file);
+    tgt->AddSource(file->GetFullPath());
     }
   else
     {

+ 11 - 7
Source/cmGlobalXCodeGenerator.cxx

@@ -343,7 +343,6 @@ void cmGlobalXCodeGenerator::Generate()
     // add ALL_BUILD, INSTALL, etc
     this->AddExtraTargets(root, it->second);
     }
-  this->ForceLinkerLanguages();
   this->cmGlobalGenerator::Generate();
   if(cmSystemTools::GetErrorOccuredFlag())
     {
@@ -412,7 +411,7 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
   std::string listfile = mf->GetStartDirectory();
   listfile += "/";
   listfile += "CMakeLists.txt";
-  allbuild->AddSource(listfile.c_str());
+  allbuild->AddSourceCMP0049(listfile.c_str());
 
   // Add XCODE depend helper
   std::string dir = mf->GetCurrentOutputDirectory();
@@ -495,7 +494,7 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
       listfile = lg->GetMakefile()->GetStartDirectory();
       listfile += "/";
       listfile += "CMakeLists.txt";
-      target.AddSource(listfile.c_str());
+      target.AddSourceCMP0049(listfile.c_str());
       }
     }
 }
@@ -988,6 +987,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
     cmtarget.GetSourceFiles(classes);
     std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare());
 
+    gtgt->ComputeObjectMapping();
+
     std::vector<cmXCodeObject*> externalObjFiles;
     std::vector<cmXCodeObject*> headerFiles;
     std::vector<cmXCodeObject*> resourceFiles;
@@ -1008,7 +1009,10 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
       if(filetype &&
          filetype->GetString() == "compiled.mach-o.objfile")
         {
-        externalObjFiles.push_back(xsf);
+        if ((*i)->GetObjectLibrary().empty())
+          {
+          externalObjFiles.push_back(xsf);
+          }
         }
       else if(this->IsHeaderFile(*i) ||
         (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) ||
@@ -1260,7 +1264,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
   if(cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str()))
     {
     sf->SetProperty("LANGUAGE", llang.c_str());
-    cmtarget.AddSourceFile(sf);
+    cmtarget.AddSource(fname);
     }
 }
 
@@ -2934,8 +2938,8 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
       if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
         {
         std::string plist = this->ComputeInfoPListLocation(cmtarget);
-        cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
-        cmtarget.AddSourceFile(sf);
+        mf->GetOrCreateSource(plist, true);
+        cmtarget.AddSource(plist);
         }
 
       std::vector<cmSourceFile*> classes;

+ 2 - 2
Source/cmLocalGenerator.cxx

@@ -751,8 +751,8 @@ void cmLocalGenerator::AddBuildTargetRule(const std::string& llang,
     comment.c_str(),
     this->Makefile->GetStartOutputDirectory()
     );
-  target.Target->AddSourceFile
-    (this->Makefile->GetSource(targetFullPath));
+  this->Makefile->GetSource(targetFullPath);
+  target.Target->AddSource(targetFullPath);
 }
 
 

+ 13 - 3
Source/cmLocalVisualStudio6Generator.cxx

@@ -253,9 +253,9 @@ void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmTarget& tgt)
                                            makefileIn.c_str(), commandLines,
                                            comment.c_str(),
                                            no_working_directory, true);
-  if(cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str()))
+  if(this->Makefile->GetSource(makefileIn.c_str()))
     {
-    tgt.AddSourceFile(file);
+    tgt.AddSource(makefileIn);
     }
   else
     {
@@ -324,6 +324,11 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
   for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
       i != classes.end(); i++)
     {
+    if (!(*i)->GetObjectLibrary().empty())
+      {
+      continue;
+      }
+
     // Add the file to the list of sources.
     std::string source = (*i)->GetFullPath();
     cmSourceGroup* sourceGroup =
@@ -398,6 +403,11 @@ void cmLocalVisualStudio6Generator
   for(std::vector<const cmSourceFile *>::const_iterator sf =
         sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
     {
+    if (!(*sf)->GetObjectLibrary().empty())
+      {
+      continue;
+      }
+
     std::string source = (*sf)->GetFullPath();
     const cmCustomCommand *command =
       (*sf)->GetCustomCommand();
@@ -591,7 +601,7 @@ cmLocalVisualStudio6Generator
        origCommand.GetCommandLines(), comment,
        origCommand.GetWorkingDirectory().c_str()))
     {
-    target.AddSourceFile(outsf);
+    target.AddSource(outsf->GetFullPath());
     }
 
   // Replace the dependencies with the output of this rule so that the

+ 6 - 2
Source/cmLocalVisualStudio7Generator.cxx

@@ -117,7 +117,7 @@ void cmLocalVisualStudio7Generator::AddCMakeListsRules()
         {
         if(l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET)
           {
-          l->second.AddSourceFile(sf);
+          l->second.AddSource(sf->GetFullPath());
           }
         }
       }
@@ -153,7 +153,7 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets()
            force.c_str(), no_depends, no_main_dependency,
            force_commands, " ", 0, true))
         {
-        tgt.AddSourceFile(file);
+        tgt.AddSource(file->GetFullPath());
         }
       }
     }
@@ -1401,6 +1401,10 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
   for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
       i != classes.end(); i++)
     {
+    if (!(*i)->GetObjectLibrary().empty())
+      {
+      continue;
+      }
     // Add the file to the list of sources.
     std::string source = (*i)->GetFullPath();
     if(cmSystemTools::UpperCase((*i)->GetExtension()) == "DEF")

+ 2 - 2
Source/cmMakefile.cxx

@@ -1182,7 +1182,7 @@ cmMakefile::AddCustomCommandOldStyle(const std::string& target,
       {
       if (this->Targets.find(target) != this->Targets.end())
         {
-        this->Targets[target].AddSourceFile(sf);
+        this->Targets[target].AddSource(sf->GetFullPath());
         }
       else
         {
@@ -1266,7 +1266,7 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName,
                                  commandLines, comment,
                                  workingDirectory, no_replace,
                                  escapeOldStyle);
-  cmSourceFile* sf = target->AddSource(force);
+  cmSourceFile* sf = target->AddSourceCMP0049(force);
 
   // The output is not actually created so mark it symbolic.
   if(sf)

+ 0 - 3
Source/cmMakefileTargetGenerator.cxx

@@ -202,9 +202,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
     // Generate this object file's rule file.
     this->WriteObjectRuleFiles(**si);
     }
-
-  // Add object library contents as external objects.
-  this->GeneratorTarget->UseObjectLibraries(this->ExternalObjects);
 }
 
 //----------------------------------------------------------------------------

+ 0 - 11
Source/cmNinjaTargetGenerator.cxx

@@ -525,17 +525,6 @@ cmNinjaTargetGenerator
     this->ModuleDefinitionFile = this->ConvertToNinjaPath(def.c_str());
     }
 
-  {
-  // Add object library contents as external objects.
-  std::vector<std::string> objs;
-  this->GeneratorTarget->UseObjectLibraries(objs);
-  for(std::vector<std::string>::iterator oi = objs.begin();
-      oi != objs.end(); ++oi)
-    {
-    this->Objects.push_back(ConvertToNinjaPath(oi->c_str()));
-    }
-  }
-
   this->GetBuildFileStream() << "\n";
 }
 

+ 5 - 0
Source/cmPolicies.cxx

@@ -343,6 +343,11 @@ cmPolicies::cmPolicies()
     CMP0050, "CMP0050",
     "Disallow add_custom_command SOURCE signatures.",
     3,0,0, cmPolicies::WARN);
+
+  this->DefinePolicy(
+    CMP0051, "CMP0051",
+    "List TARGET_OBJECTS in SOURCES target property.",
+    3,1,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()

+ 1 - 0
Source/cmPolicies.h

@@ -104,6 +104,7 @@ public:
     CMP0048, ///< project() command manages VERSION variables
     CMP0049, ///< Do not expand variables in target source entries
     CMP0050, ///< Disallow add_custom_command SOURCE signatures
+    CMP0051, ///< List TARGET_OBJECTS in SOURCES target property
 
     /** \brief Always the last entry.
      *

+ 7 - 10
Source/cmQtAutoGenerators.cxx

@@ -187,13 +187,11 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target)
     mocCppFile += "/";
     mocCppFile += automocTargetName;
     mocCppFile += ".cpp";
-    cmSourceFile* mocCppSource = makefile->GetOrCreateSource(
-                                                          mocCppFile,
-                                                          true);
+    makefile->GetOrCreateSource(mocCppFile, true);
     makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
                             mocCppFile.c_str(), false);
 
-    target->AddSourceFile(mocCppSource);
+    target->AddSource(mocCppFile);
     }
   // create a custom target for running generators at buildtime:
   std::string autogenTargetName = getAutogenTargetName(target);
@@ -479,7 +477,7 @@ void cmQtAutoGenerators::SetupSourceFiles(cmTarget const* target)
   const char *skipMocSep = "";
   const char *skipUicSep = "";
 
-  std::vector<cmSourceFile*> newRccFiles;
+  std::vector<std::string> newRccFiles;
 
   for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
       fileIt != srcFiles.end();
@@ -512,9 +510,8 @@ void cmQtAutoGenerators::SetupSourceFiles(cmTarget const* target)
         rcc_output_file += "/qrc_" + basename + ".cpp";
         makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
                                 rcc_output_file.c_str(), false);
-        cmSourceFile* rccCppSource
-                = makefile->GetOrCreateSource(rcc_output_file, true);
-        newRccFiles.push_back(rccCppSource);
+        makefile->GetOrCreateSource(rcc_output_file, true);
+        newRccFiles.push_back(rcc_output_file);
         }
       }
 
@@ -546,11 +543,11 @@ void cmQtAutoGenerators::SetupSourceFiles(cmTarget const* target)
       }
     }
 
-  for(std::vector<cmSourceFile*>::const_iterator fileIt = newRccFiles.begin();
+  for(std::vector<std::string>::const_iterator fileIt = newRccFiles.begin();
       fileIt != newRccFiles.end();
       ++fileIt)
     {
-    const_cast<cmTarget*>(target)->AddSourceFile(*fileIt);
+    const_cast<cmTarget*>(target)->AddSource(*fileIt);
     }
 }
 

+ 12 - 0
Source/cmSourceFile.cxx

@@ -38,6 +38,18 @@ std::string const& cmSourceFile::GetExtension() const
   return this->Extension;
 }
 
+//----------------------------------------------------------------------------
+void cmSourceFile::SetObjectLibrary(std::string const& objlib)
+{
+  this->ObjectLibrary = objlib;
+}
+
+//----------------------------------------------------------------------------
+std::string cmSourceFile::GetObjectLibrary() const
+{
+  return this->ObjectLibrary;
+}
+
 //----------------------------------------------------------------------------
 std::string cmSourceFile::GetLanguage()
 {

+ 4 - 0
Source/cmSourceFile.h

@@ -97,6 +97,9 @@ public:
    */
   bool Matches(cmSourceFileLocation const&);
 
+  void SetObjectLibrary(std::string const& objlib);
+  std::string GetObjectLibrary() const;
+
 private:
   cmSourceFileLocation Location;
   cmPropertyMap Properties;
@@ -105,6 +108,7 @@ private:
   std::string Language;
   std::string FullPath;
   bool FindFullPathFailed;
+  std::string ObjectLibrary;
 
   bool FindFullPath(std::string* error);
   bool TryFullPath(const std::string& path, const std::string& ext);

+ 46 - 24
Source/cmSourceFileLocation.cxx

@@ -16,29 +16,57 @@
 #include "cmGlobalGenerator.h"
 #include "cmSystemTools.h"
 
+#include "assert.h"
+
 //----------------------------------------------------------------------------
-cmSourceFileLocation
-::cmSourceFileLocation(cmMakefile const* mf, const std::string& name)
-  : Makefile(mf)
+cmSourceFileLocation::cmSourceFileLocation()
+  : Makefile(0), AmbiguousDirectory(true), AmbiguousExtension(true)
 {
-  this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str());
-  this->AmbiguousExtension = true;
-  this->Directory = cmSystemTools::GetFilenamePath(name);
-  this->Name = cmSystemTools::GetFilenameName(name);
-  this->UpdateExtension(name);
+
 }
 
 //----------------------------------------------------------------------------
-void cmSourceFileLocation::Update(const std::string& name)
+cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc)
+  : Makefile(loc.Makefile)
 {
-  if(this->AmbiguousDirectory)
+  this->AmbiguousDirectory = loc.AmbiguousDirectory;
+  this->AmbiguousExtension = loc.AmbiguousExtension;
+  this->Directory = loc.Directory;
+  this->Name = loc.Name;
+}
+
+//----------------------------------------------------------------------------
+cmSourceFileLocation&
+cmSourceFileLocation::operator=(const cmSourceFileLocation& loc)
+{
+  if(this == &loc)
     {
-    this->UpdateDirectory(name);
+    return *this;
     }
-  if(this->AmbiguousExtension)
+  this->Makefile = loc.Makefile;
+  this->AmbiguousDirectory = loc.AmbiguousDirectory;
+  this->AmbiguousExtension = loc.AmbiguousExtension;
+  this->Directory = loc.Directory;
+  this->Name = loc.Name;
+  this->UpdateExtension(this->Name);
+  return *this;
+}
+
+//----------------------------------------------------------------------------
+cmSourceFileLocation
+::cmSourceFileLocation(cmMakefile const* mf, const std::string& name)
+  : Makefile(mf)
+{
+  this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str());
+  this->AmbiguousExtension = true;
+  this->Directory = cmSystemTools::GetFilenamePath(name);
+  if (cmSystemTools::FileIsFullPath(this->Directory.c_str()))
     {
-    this->UpdateExtension(name);
+    this->Directory
+                  = cmSystemTools::CollapseFullPath(this->Directory.c_str());
     }
+  this->Name = cmSystemTools::GetFilenameName(name);
+  this->UpdateExtension(name);
 }
 
 //----------------------------------------------------------------------------
@@ -59,6 +87,7 @@ void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
 //----------------------------------------------------------------------------
 void cmSourceFileLocation::DirectoryUseSource()
 {
+  assert(this->Makefile);
   if(this->AmbiguousDirectory)
     {
     this->Directory =
@@ -71,6 +100,7 @@ void cmSourceFileLocation::DirectoryUseSource()
 //----------------------------------------------------------------------------
 void cmSourceFileLocation::DirectoryUseBinary()
 {
+  assert(this->Makefile);
   if(this->AmbiguousDirectory)
     {
     this->Directory =
@@ -83,6 +113,7 @@ void cmSourceFileLocation::DirectoryUseBinary()
 //----------------------------------------------------------------------------
 void cmSourceFileLocation::UpdateExtension(const std::string& name)
 {
+  assert(this->Makefile);
   // Check the extension.
   std::string ext = cmSystemTools::GetFilenameLastExtension(name);
   if(!ext.empty()) { ext = ext.substr(1); }
@@ -136,22 +167,12 @@ void cmSourceFileLocation::UpdateExtension(const std::string& name)
     }
 }
 
-//----------------------------------------------------------------------------
-void cmSourceFileLocation::UpdateDirectory(const std::string& name)
-{
-  // If a full path was given we know the directory.
-  if(cmSystemTools::FileIsFullPath(name.c_str()))
-    {
-    this->Directory = cmSystemTools::GetFilenamePath(name);
-    this->AmbiguousDirectory = false;
-    }
-}
-
 //----------------------------------------------------------------------------
 bool
 cmSourceFileLocation
 ::MatchesAmbiguousExtension(cmSourceFileLocation const& loc) const
 {
+  assert(this->Makefile);
   // This location's extension is not ambiguous but loc's extension
   // is.  See if the names match as-is.
   if(this->Name == loc.Name)
@@ -188,6 +209,7 @@ cmSourceFileLocation
 //----------------------------------------------------------------------------
 bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
 {
+  assert(this->Makefile);
   if(this->AmbiguousExtension && loc.AmbiguousExtension)
     {
     // Both extensions are ambiguous.  Since only the old fixed set of

+ 3 - 2
Source/cmSourceFileLocation.h

@@ -34,6 +34,9 @@ public:
    * instance with an initial name.
    */
   cmSourceFileLocation(cmMakefile const* mf, const std::string& name);
+  cmSourceFileLocation();
+  cmSourceFileLocation(const cmSourceFileLocation& loc);
+  cmSourceFileLocation& operator=(const cmSourceFileLocation& loc);
 
   /**
    * Return whether the givne source file location could refers to the
@@ -93,9 +96,7 @@ private:
 
   // Update the location with additional knowledge.
   void Update(cmSourceFileLocation const& loc);
-  void Update(const std::string& name);
   void UpdateExtension(const std::string& name);
-  void UpdateDirectory(const std::string& name);
 };
 
 #endif

+ 25 - 0
Source/cmStringCommand.cxx

@@ -101,6 +101,10 @@ bool cmStringCommand
     {
     return this->HandleMakeCIdentifierCommand(args);
     }
+  else if(subCommand == "GENEX_STRIP")
+    {
+    return this->HandleGenexStripCommand(args);
+    }
 
   std::string e = "does not recognize sub-command "+subCommand;
   this->SetError(e);
@@ -809,6 +813,27 @@ bool cmStringCommand
   return true;
 }
 
+//----------------------------------------------------------------------------
+bool cmStringCommand
+::HandleGenexStripCommand(std::vector<std::string> const& args)
+{
+  if(args.size() != 3)
+    {
+    this->SetError("sub-command GENEX_STRIP requires two arguments.");
+    return false;
+    }
+
+  const std::string& input = args[1];
+
+  std::string result = cmGeneratorExpression::Preprocess(input,
+                        cmGeneratorExpression::StripAllGeneratorExpressions);
+
+  const std::string& variableName = args[2];
+
+  this->Makefile->AddDefinition(variableName, result.c_str());
+  return true;
+}
+
 //----------------------------------------------------------------------------
 bool cmStringCommand::HandleStripCommand(
   std::vector<std::string> const& args)

+ 1 - 0
Source/cmStringCommand.h

@@ -75,6 +75,7 @@ protected:
   bool HandleFindCommand(std::vector<std::string> const& args);
   bool HandleTimestampCommand(std::vector<std::string> const& args);
   bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args);
+  bool HandleGenexStripCommand(std::vector<std::string> const& args);
 
   class RegexReplacement
   {

+ 251 - 62
Source/cmTarget.cxx

@@ -150,6 +150,7 @@ public:
   std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
   std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
+  std::vector<TargetPropertyEntry*> SourceEntries;
   std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
 
   mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
@@ -542,35 +543,58 @@ bool cmTarget::IsBundleOnApple() const
 }
 
 //----------------------------------------------------------------------------
-void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const
+void cmTarget::GetSourceFiles(std::vector<std::string> &files) const
 {
   assert(this->GetType() != INTERFACE_LIBRARY);
-  for(std::vector<cmSourceFile*>::const_iterator
-      si = this->SourceFiles.begin();
-      si != this->SourceFiles.end(); ++si)
+  for(std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
+      si = this->Internal->SourceEntries.begin();
+      si != this->Internal->SourceEntries.end(); ++si)
     {
-    std::string e;
-    if((*si)->GetFullPath(&e).empty())
+    std::vector<std::string> srcs;
+    cmSystemTools::ExpandListArgument((*si)->ge->Evaluate(this->Makefile,
+                                        "",
+                                        false,
+                                        this),
+                                      srcs);
+
+    for(std::vector<std::string>::const_iterator i = srcs.begin();
+        i != srcs.end(); ++i)
       {
-      if(!e.empty())
+      std::string src = *i;
+      cmSourceFile* sf = this->Makefile->GetOrCreateSource(src);
+      std::string e;
+      src = sf->GetFullPath(&e);
+      if(src.empty())
         {
-        cmake* cm = this->Makefile->GetCMakeInstance();
-        cm->IssueMessage(cmake::FATAL_ERROR, e,
-                         this->GetBacktrace());
+        if(!e.empty())
+          {
+          cmake* cm = this->Makefile->GetCMakeInstance();
+          cm->IssueMessage(cmake::FATAL_ERROR, e,
+                          this->GetBacktrace());
+          }
+        return;
         }
-      return;
+      files.push_back(src);
       }
     }
-  files = this->SourceFiles;
 }
 
 //----------------------------------------------------------------------------
-void cmTarget::AddSourceFile(cmSourceFile* sf)
+void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const
 {
-  if (std::find(this->SourceFiles.begin(), this->SourceFiles.end(), sf)
-                                            == this->SourceFiles.end())
+  std::vector<std::string> srcs;
+  this->GetSourceFiles(srcs);
+
+  std::set<cmSourceFile*> emitted;
+
+  for(std::vector<std::string>::const_iterator i = srcs.begin();
+      i != srcs.end(); ++i)
     {
-    this->SourceFiles.push_back(sf);
+    cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
+    if (emitted.insert(sf).second)
+      {
+      files.push_back(sf);
+      }
     }
 }
 
@@ -583,17 +607,17 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
     const char* src = i->c_str();
     if(src[0] == '$' && src[1] == '<')
       {
-      this->ProcessSourceExpression(*i);
+      this->AddSource(src);
       }
     else
       {
-      this->AddSource(src);
+      this->AddSourceCMP0049(src);
       }
     }
 }
 
 //----------------------------------------------------------------------------
-cmSourceFile* cmTarget::AddSource(const std::string& s)
+cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
 {
   std::string src = s;
 
@@ -632,28 +656,91 @@ cmSourceFile* cmTarget::AddSource(const std::string& s)
         }
       }
     }
-
-  cmSourceFile* sf = this->Makefile->GetOrCreateSource(src);
-  this->AddSourceFile(sf);
-  return sf;
+  return this->AddSource(src);
 }
 
 //----------------------------------------------------------------------------
-void cmTarget::ProcessSourceExpression(std::string const& expr)
+struct CreateLocation
+{
+  cmMakefile const* Makefile;
+
+  CreateLocation(cmMakefile const* mf)
+    : Makefile(mf)
+  {
+
+  }
+
+  cmSourceFileLocation operator()(const std::string& filename)
+  {
+    return cmSourceFileLocation(this->Makefile, filename);
+  }
+};
+
+//----------------------------------------------------------------------------
+struct LocationMatcher
 {
-  if(cmHasLiteralPrefix(expr.c_str(), "$<TARGET_OBJECTS:") &&
-     expr[expr.size()-1] == '>')
+  const cmSourceFileLocation& Needle;
+
+  LocationMatcher(const cmSourceFileLocation& needle)
+    : Needle(needle)
+  {
+
+  }
+
+  bool operator()(cmSourceFileLocation &loc)
+  {
+    return loc.Matches(this->Needle);
+  }
+};
+
+
+//----------------------------------------------------------------------------
+struct TargetPropertyEntryFinder
+{
+private:
+  const cmSourceFileLocation& Needle;
+public:
+  TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
+    : Needle(needle)
+  {
+
+  }
+
+  bool operator()(cmTargetInternals::TargetPropertyEntry* entry)
+  {
+    std::vector<std::string> files;
+    cmSystemTools::ExpandListArgument(entry->ge->GetInput(), files);
+    std::vector<cmSourceFileLocation> locations(files.size());
+    std::transform(files.begin(), files.end(), locations.begin(),
+                   CreateLocation(this->Needle.GetMakefile()));
+
+    return std::find_if(locations.begin(), locations.end(),
+        LocationMatcher(this->Needle)) != locations.end();
+  }
+};
+
+//----------------------------------------------------------------------------
+cmSourceFile* cmTarget::AddSource(const std::string& src)
+{
+  cmSourceFileLocation sfl(this->Makefile, src);
+  if (std::find_if(this->Internal->SourceEntries.begin(),
+                   this->Internal->SourceEntries.end(),
+                   TargetPropertyEntryFinder(sfl))
+                                      == this->Internal->SourceEntries.end())
     {
-    std::string objLibName = expr.substr(17, expr.size()-18);
-    this->ObjectLibraries.push_back(objLibName);
+    cmListFileBacktrace lfbt;
+    this->Makefile->GetBacktrace(lfbt);
+    cmGeneratorExpression ge(lfbt);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
+    cge->SetEvaluateForBuildsystem(true);
+    this->Internal->SourceEntries.push_back(
+                          new cmTargetInternals::TargetPropertyEntry(cge));
     }
-  else
+  if (cmGeneratorExpression::Find(src) != std::string::npos)
     {
-    cmOStringStream e;
-    e << "Unrecognized generator expression:\n"
-      << "  " << expr;
-    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+    return 0;
     }
+  return this->Makefile->GetOrCreateSource(src);
 }
 
 //----------------------------------------------------------------------------
@@ -2766,25 +2853,90 @@ const char *cmTarget::GetProperty(const std::string& prop,
     {
     cmOStringStream ss;
     const char* sep = "";
-    for(std::vector<cmSourceFile*>::const_iterator
-          i = this->SourceFiles.begin();
-        i != this->SourceFiles.end(); ++i)
+    typedef cmTargetInternals::TargetPropertyEntry
+                                TargetPropertyEntry;
+    for(std::vector<TargetPropertyEntry*>::const_iterator
+          i = this->Internal->SourceEntries.begin();
+        i != this->Internal->SourceEntries.end(); ++i)
       {
-      // Separate from the previous list entries.
-      ss << sep;
-      sep = ";";
+      std::string entry = (*i)->ge->GetInput();
 
-      // Construct what is known about this source file location.
-      cmSourceFileLocation const& location = (*i)->GetLocation();
-      std::string sname = location.GetDirectory();
-      if(!sname.empty())
+      std::vector<std::string> files;
+      cmSystemTools::ExpandListArgument(entry, files);
+      for (std::vector<std::string>::const_iterator
+          li = files.begin(); li != files.end(); ++li)
         {
-        sname += "/";
-        }
-      sname += location.GetName();
+        if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+            (*li)[li->size() - 1] == '>')
+          {
+          std::string objLibName = li->substr(17, li->size()-18);
+
+          if (cmGeneratorExpression::Find(objLibName) != std::string::npos)
+            {
+            ss << sep;
+            sep = ";";
+            ss << *li;
+            continue;
+            }
+
+          bool addContent = false;
+          bool noMessage = true;
+          cmOStringStream e;
+          cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+          switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0051))
+            {
+            case cmPolicies::WARN:
+              e << (this->Makefile->GetPolicies()
+                    ->GetPolicyWarning(cmPolicies::CMP0051)) << "\n";
+              noMessage = false;
+            case cmPolicies::OLD:
+              break;
+            case cmPolicies::REQUIRED_ALWAYS:
+            case cmPolicies::REQUIRED_IF_USED:
+            case cmPolicies::NEW:
+              addContent = true;
+            }
+          if (!noMessage)
+            {
+            e << "Target \"" << this->Name << "\" contains $<TARGET_OBJECTS> "
+            "generator expression in its sources list.  This content was not "
+            "previously part of the SOURCES property when that property was "
+            "read at configure time.  Code reading that property needs to be "
+            "adapted to ignore the generator expression using the "
+            "string(GENEX_STRIP) command.";
+            this->Makefile->IssueMessage(messageType, e.str());
+            }
+          if (addContent)
+            {
+            ss << sep;
+            sep = ";";
+            ss << *li;
+            }
+          }
+        else if (cmGeneratorExpression::Find(*li) == std::string::npos)
+          {
+          ss << sep;
+          sep = ";";
+          ss << *li;
+          }
+        else
+          {
+          cmSourceFile *sf = this->Makefile->GetOrCreateSource(*li);
+          // Construct what is known about this source file location.
+          cmSourceFileLocation const& location = sf->GetLocation();
+          std::string sname = location.GetDirectory();
+          if(!sname.empty())
+            {
+            sname += "/";
+            }
+          sname += location.GetName();
 
-      // Append this list entry.
-      ss << sname;
+          ss << sep;
+          sep = ";";
+          // Append this list entry.
+          ss << sname;
+          }
+        }
       }
     this->Properties.SetProperty("SOURCES", ss.str().c_str(),
                                  cmProperty::TARGET);
@@ -4844,8 +4996,10 @@ bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p,
 //----------------------------------------------------------------------------
 void cmTarget::GetLanguages(std::set<std::string>& languages) const
 {
+  std::vector<cmSourceFile*> sourceFiles;
+  this->GetSourceFiles(sourceFiles);
   for(std::vector<cmSourceFile*>::const_iterator
-        i = this->SourceFiles.begin(); i != this->SourceFiles.end(); ++i)
+        i = sourceFiles.begin(); i != sourceFiles.end(); ++i)
     {
     const std::string& lang = (*i)->GetLanguage();
     if(!lang.empty())
@@ -4853,6 +5007,53 @@ void cmTarget::GetLanguages(std::set<std::string>& languages) const
       languages.insert(lang);
       }
     }
+
+  std::vector<cmTarget*> objectLibraries;
+  std::vector<cmSourceFile const*> externalObjects;
+  if (this->Makefile->GetGeneratorTargets().empty())
+    {
+    // At configure-time, this method can be called as part of getting the
+    // LOCATION property or to export() a file to be include()d.  However
+    // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+    // for TARGET_OBJECTS instead for backwards compatibility with OLD
+    // behavior of CMP0024 and CMP0026 only.
+    std::vector<std::string> srcs;
+    cmSystemTools::ExpandListArgument(this->GetProperty("SOURCES"), srcs);
+    for(std::vector<std::string>::const_iterator it = srcs.begin();
+        it != srcs.end(); ++it)
+      {
+      if (cmHasLiteralPrefix(*it, "$<TARGET_OBJECTS:")
+          && cmHasLiteralSuffix(*it, ">"))
+        {
+        std::string objLibName = it->substr(17, it->size()-18);
+        if (cmTarget* tgt = this->Makefile->FindTargetToUse(objLibName))
+          {
+          objectLibraries.push_back(tgt);
+          }
+        }
+      }
+    }
+  else
+    {
+    cmGeneratorTarget* gt = this->Makefile->GetLocalGenerator()
+                                ->GetGlobalGenerator()
+                                ->GetGeneratorTarget(this);
+    gt->GetExternalObjects(externalObjects);
+    for(std::vector<cmSourceFile const*>::const_iterator
+          i = externalObjects.begin(); i != externalObjects.end(); ++i)
+      {
+      std::string objLib = (*i)->GetObjectLibrary();
+      if (cmTarget* tgt = this->Makefile->FindTargetToUse(objLib))
+        {
+        objectLibraries.push_back(tgt);
+        }
+      }
+    }
+  for(std::vector<cmTarget*>::const_iterator
+      i = objectLibraries.begin(); i != objectLibraries.end(); ++i)
+    {
+    (*i)->GetLanguages(languages);
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -5917,19 +6118,6 @@ cmTarget::ComputeLinkImplementationLanguages(LinkImplementation& impl) const
   std::set<std::string> languages;
   // Get languages used in our source files.
   this->GetLanguages(languages);
-  // Get languages used in object library sources.
-  for(std::vector<std::string>::const_iterator
-      i = this->ObjectLibraries.begin();
-      i != this->ObjectLibraries.end(); ++i)
-    {
-    if(cmTarget* objLib = this->Makefile->FindTargetToUse(*i))
-      {
-      if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
-        {
-        objLib->GetLanguages(languages);
-        }
-      }
-    }
   // Copy the set of langauges to the link implementation.
   for(std::set<std::string>::iterator li = languages.begin();
       li != languages.end(); ++li)
@@ -6395,6 +6583,7 @@ cmTargetInternalPointer::~cmTargetInternalPointer()
   deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
   deleteAndClear(this->Pointer->CompileOptionsEntries);
   deleteAndClear(this->Pointer->CompileDefinitionsEntries);
+  deleteAndClear(this->Pointer->SourceEntries);
   delete this->Pointer;
 }
 

+ 2 - 7
Source/cmTarget.h

@@ -135,17 +135,14 @@ public:
   /**
    * Get the list of the source files used by this target
    */
+  void GetSourceFiles(std::vector<std::string> &files) const;
   void GetSourceFiles(std::vector<cmSourceFile*> &files) const;
-  void AddSourceFile(cmSourceFile* sf);
-  std::vector<std::string> const& GetObjectLibraries() const
-    {
-    return this->ObjectLibraries;
-    }
 
   /**
    * Add sources to the target.
    */
   void AddSources(std::vector<std::string> const& srcs);
+  cmSourceFile* AddSourceCMP0049(const std::string& src);
   cmSourceFile* AddSource(const std::string& src);
 
   enum LinkLibraryType {GENERAL, DEBUG, OPTIMIZED};
@@ -685,8 +682,6 @@ private:
   std::vector<cmCustomCommand> PreLinkCommands;
   std::vector<cmCustomCommand> PostBuildCommands;
   TargetType TargetTypeValue;
-  std::vector<cmSourceFile*> SourceFiles;
-  std::vector<std::string> ObjectLibraries;
   LinkLibraryVectorType LinkLibraries;
   LinkLibraryVectorType PrevLinkedLibraries;
   bool LinkLibrariesAnalyzed;

+ 13 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -1054,6 +1054,19 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
 
   std::vector<cmSourceFile const*> externalObjects;
   this->GeneratorTarget->GetExternalObjects(externalObjects);
+  for(std::vector<cmSourceFile const*>::iterator
+        si = externalObjects.begin();
+      si != externalObjects.end(); )
+    {
+    if (!(*si)->GetObjectLibrary().empty())
+      {
+      si = externalObjects.erase(si);
+      }
+    else
+      {
+      ++si;
+      }
+    }
   if(this->LocalGenerator->GetVersion() > cmLocalVisualStudioGenerator::VS10)
     {
     // For VS >= 11 we use LinkObjects to avoid linking custom command

+ 1 - 1
Tests/GeneratorExpression/CMakeLists.txt

@@ -166,7 +166,7 @@ add_library(imported4 SHARED IMPORTED)
 set_property(TARGET imported4 APPEND PROPERTY
   INCLUDE_DIRECTORIES $<TARGET_PROPERTY:imported3,INTERFACE_INCLUDE_DIRECTORIES>)
 
-add_executable(someexe empty.cpp)
+add_executable(someexe $<1:empty.cpp> $<0:does_not_exist>)
 add_executable(Alias::SomeExe ALIAS someexe)
 
 add_library(Alias::SomeLib ALIAS empty1)

+ 2 - 0
Tests/Properties/CMakeLists.txt

@@ -143,3 +143,5 @@ set_property(CACHE SOME_ENTRY PROPERTY VALUE "${expect_VALUE}")
 set_property(CACHE SOME_ENTRY PROPERTY ADVANCED "${expect_ADVANCED}")
 set_property(CACHE SOME_ENTRY PROPERTY STRINGS "${expect_STRINGS}")
 check_cache_props()
+
+add_subdirectory(SubDir2)

+ 5 - 0
Tests/Properties/SubDir2/CMakeLists.txt

@@ -0,0 +1,5 @@
+
+set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx"
+  PROPERTIES COMPILE_DEFINITIONS SUBDIR_TEST)
+
+add_executable(subdirtest "${CMAKE_CURRENT_SOURCE_DIR}/../subdirtest.cxx")

+ 9 - 0
Tests/Properties/subdirtest.cxx

@@ -0,0 +1,9 @@
+
+#ifndef SUBDIR_TEST
+#error Expected SUBDIR_TEST
+#endif
+
+int main(int, char**)
+{
+  return 0;
+}

+ 1 - 0
Tests/RunCMake/CMP0051/CMP0051-NEW-result.txt

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

+ 1 - 0
Tests/RunCMake/CMP0051/CMP0051-NEW-stderr.txt

@@ -0,0 +1 @@
+^Sources: "empty.cpp;\$<TARGET_OBJECTS:objects>"$

+ 10 - 0
Tests/RunCMake/CMP0051/CMP0051-NEW.cmake

@@ -0,0 +1,10 @@
+
+cmake_policy(SET CMP0051 NEW)
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")

+ 1 - 0
Tests/RunCMake/CMP0051/CMP0051-OLD-result.txt

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

+ 1 - 0
Tests/RunCMake/CMP0051/CMP0051-OLD-stderr.txt

@@ -0,0 +1 @@
+^Sources: "empty.cpp"$

+ 10 - 0
Tests/RunCMake/CMP0051/CMP0051-OLD.cmake

@@ -0,0 +1,10 @@
+
+cmake_policy(SET CMP0051 OLD)
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")

+ 1 - 0
Tests/RunCMake/CMP0051/CMP0051-WARN-result.txt

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

+ 15 - 0
Tests/RunCMake/CMP0051/CMP0051-WARN-stderr.txt

@@ -0,0 +1,15 @@
+CMake Warning \(dev\) at CMP0051-WARN.cmake:6 \(get_target_property\):
+  Policy CMP0051 is not set: List TARGET_OBJECTS in SOURCES target property.
+  Run "cmake --help-policy CMP0051" for policy details.  Use the cmake_policy
+  command to set the policy and suppress this warning.
+
+  Target "empty" contains \$<TARGET_OBJECTS> generator expression in its
+  sources list.  This content was not previously part of the SOURCES property
+  when that property was read at configure time.  Code reading that property
+  needs to be adapted to ignore the generator expression using the
+  string\(GENEX_STRIP\) command.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+Sources: "empty.cpp"$

+ 8 - 0
Tests/RunCMake/CMP0051/CMP0051-WARN.cmake

@@ -0,0 +1,8 @@
+
+add_library(objects OBJECT empty.cpp)
+
+add_library(empty empty.cpp $<TARGET_OBJECTS:objects>)
+
+get_target_property(srcs empty SOURCES)
+
+message("Sources: \"${srcs}\"")

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

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

+ 5 - 0
Tests/RunCMake/CMP0051/RunCMakeTest.cmake

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0051-OLD)
+run_cmake(CMP0051-NEW)
+run_cmake(CMP0051-WARN)

+ 7 - 0
Tests/RunCMake/CMP0051/empty.cpp

@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int empty()
+{
+  return 0;
+}

+ 2 - 0
Tests/RunCMake/CMakeLists.txt

@@ -34,6 +34,7 @@ add_RunCMake_test(CMP0045)
 add_RunCMake_test(CMP0046)
 add_RunCMake_test(CMP0049)
 add_RunCMake_test(CMP0050)
+add_RunCMake_test(CMP0051)
 add_RunCMake_test(CTest)
 if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
   add_RunCMake_test(CompilerChange)
@@ -49,6 +50,7 @@ add_RunCMake_test(GeneratorToolset)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(ObjectLibrary)
+add_RunCMake_test(TargetObjects)
 add_RunCMake_test(find_dependency)
 if(NOT WIN32)
   add_RunCMake_test(PositionIndependentCode)

+ 3 - 1
Tests/RunCMake/ObjectLibrary/BadSourceExpression1-stderr.txt

@@ -1,6 +1,8 @@
 CMake Error at BadSourceExpression1.cmake:1 \(add_library\):
-  Unrecognized generator expression:
+  Error evaluating generator expression:
 
     \$<BAD_EXPRESSION>
+
+  Expression did not evaluate to a known generator expression
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression2-stderr.txt

@@ -1,4 +1,8 @@
 CMake Error at BadSourceExpression2.cmake:1 \(add_library\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:DoesNotExist>
+
   Objects of target "DoesNotExist" referenced but no such target exists.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt

@@ -1,4 +1,8 @@
 CMake Error at BadSourceExpression3.cmake:2 \(add_library\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:NotObjLib>
+
   Objects of target "NotObjLib" referenced but is not an OBJECT library.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 1 - 0
Tests/RunCMake/TargetObjects/BadContext-result.txt

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

+ 17 - 0
Tests/RunCMake/TargetObjects/BadContext-stderr.txt

@@ -0,0 +1,17 @@
+CMake Error at BadContext.cmake:2 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:NoTarget>
+
+  The evaluation of the TARGET_OBJECTS generator expression is only suitable
+  for consumption by CMake.  It is not suitable for writing out elsewhere.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:NoTarget>
+
+  The evaluation of the TARGET_OBJECTS generator expression is only suitable
+  for consumption by CMake.  It is not suitable for writing out elsewhere.

+ 4 - 0
Tests/RunCMake/TargetObjects/BadContext.cmake

@@ -0,0 +1,4 @@
+
+file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:NoTarget>)
+
+install(FILES $<TARGET_OBJECTS:NoTarget> DESTINATION objects)

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

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

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

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

+ 6 - 0
Tests/StringFileTest/CMakeLists.txt

@@ -286,3 +286,9 @@ string(MAKE_C_IDENTIFIER "1one-two$" MCI_1)
 if(NOT MCI_1 STREQUAL _1one_two_)
   message(SEND_ERROR "MAKE_C_IDENTIFIER did not create expected result.")
 endif()
+
+string(GENEX_STRIP "one;$<1:two;three>;four;$<TARGET_OBJECTS:some_target>" strip_result)
+
+if (NOT strip_result STREQUAL "one;four")
+  message(SEND_ERROR "GENEX_STRIP did not create expected result: ${strip_result}")
+endif()