فهرست منبع

Merge topic 'object-library'

93d5509 Merge branch 'ninja-object-library' into object-library
821037c Merge branch 'xcode-object-library' into object-library
eb24c99 Merge branch 'object-library' into xcode-object-library
63d1be8 Xcode: Honor $<TARGET_OBJECTS:...> source expressions
020ba38 Merge branch 'object-library' into xcode-object-library
e8ea615 Build object library targets in Xcode
8045e17 Pre-compute object file names before Xcode generation
247a132 Allow txt files as ExtraSources in object library targets
b063599 Add a default source group for object files.
be01f3b Xcode: Re-factor some existing methods into "FromPath" variants
2693dbe Merge branch 'object-library' into ninja-object-library
51997cb Ninja: Honor $<TARGET_OBJECTS:...> source expressions
23ec258 Merge branch 'object-library' into ninja-object-library
61124de Build object library targets in Ninja
f5b06cd Pre-compute object file names before Ninja generation
a2514f1 Simplify cmNinjaTargetGenerator using cmGeneratorTarget
...
David Cole 13 سال پیش
والد
کامیت
31c0bc0219
100فایلهای تغییر یافته به همراه1633 افزوده شده و 477 حذف شده
  1. 2 0
      Source/CMakeLists.txt
  2. 14 0
      Source/cmAddLibraryCommand.cxx
  3. 20 0
      Source/cmAddLibraryCommand.h
  4. 13 0
      Source/cmComputeLinkDepends.cxx
  5. 8 0
      Source/cmExportCommand.cxx
  6. 172 0
      Source/cmGeneratorTarget.cxx
  7. 63 0
      Source/cmGeneratorTarget.h
  8. 56 1
      Source/cmGlobalGenerator.cxx
  9. 12 1
      Source/cmGlobalGenerator.h
  10. 30 0
      Source/cmGlobalNinjaGenerator.cxx
  11. 6 0
      Source/cmGlobalNinjaGenerator.h
  12. 38 0
      Source/cmGlobalUnixMakefileGenerator3.cxx
  13. 2 0
      Source/cmGlobalUnixMakefileGenerator3.h
  14. 1 1
      Source/cmGlobalVisualStudio10Generator.h
  15. 1 1
      Source/cmGlobalVisualStudio6Generator.h
  16. 1 1
      Source/cmGlobalVisualStudio7Generator.h
  17. 68 2
      Source/cmGlobalVisualStudioGenerator.cxx
  18. 2 0
      Source/cmGlobalVisualStudioGenerator.h
  19. 267 66
      Source/cmGlobalXCodeGenerator.cxx
  20. 14 1
      Source/cmGlobalXCodeGenerator.h
  21. 10 1
      Source/cmInstallCommand.cxx
  22. 1 0
      Source/cmInstallTargetGenerator.cxx
  23. 4 0
      Source/cmLocalGenerator.cxx
  24. 0 31
      Source/cmLocalNinjaGenerator.cxx
  25. 0 3
      Source/cmLocalNinjaGenerator.h
  26. 1 39
      Source/cmLocalUnixMakefileGenerator3.cxx
  27. 0 5
      Source/cmLocalUnixMakefileGenerator3.h
  28. 102 39
      Source/cmLocalVisualStudio6Generator.cxx
  29. 3 0
      Source/cmLocalVisualStudio6Generator.h
  30. 99 27
      Source/cmLocalVisualStudio7Generator.cxx
  31. 1 5
      Source/cmLocalVisualStudio7Generator.h
  32. 0 63
      Source/cmLocalVisualStudioGenerator.cxx
  33. 2 6
      Source/cmLocalVisualStudioGenerator.h
  34. 15 3
      Source/cmMakefile.cxx
  35. 26 0
      Source/cmMakefileLibraryTargetGenerator.cxx
  36. 1 0
      Source/cmMakefileLibraryTargetGenerator.h
  37. 66 71
      Source/cmMakefileTargetGenerator.cxx
  38. 5 3
      Source/cmMakefileTargetGenerator.h
  39. 34 6
      Source/cmNinjaNormalTargetGenerator.cxx
  40. 1 0
      Source/cmNinjaNormalTargetGenerator.h
  41. 54 42
      Source/cmNinjaTargetGenerator.cxx
  42. 2 3
      Source/cmNinjaTargetGenerator.h
  43. 0 6
      Source/cmSourceGroup.cxx
  44. 0 1
      Source/cmSourceGroup.h
  45. 43 1
      Source/cmTarget.cxx
  46. 9 1
      Source/cmTarget.h
  47. 10 0
      Source/cmTargetLinkLibrariesCommand.cxx
  48. 79 45
      Source/cmVisualStudio10TargetGenerator.cxx
  49. 2 2
      Source/cmVisualStudio10TargetGenerator.h
  50. 1 0
      Tests/CMakeLists.txt
  51. 17 0
      Tests/ObjectLibrary/A/CMakeLists.txt
  52. 6 0
      Tests/ObjectLibrary/A/a.h
  53. 2 0
      Tests/ObjectLibrary/A/a1.c.in
  54. 2 0
      Tests/ObjectLibrary/A/a2.c
  55. 5 0
      Tests/ObjectLibrary/AB.def
  56. 15 0
      Tests/ObjectLibrary/B/CMakeLists.txt
  57. 11 0
      Tests/ObjectLibrary/B/b.h
  58. 2 0
      Tests/ObjectLibrary/B/b1.c
  59. 1 0
      Tests/ObjectLibrary/B/b1_vs6.c
  60. 2 0
      Tests/ObjectLibrary/B/b2.c
  61. 1 0
      Tests/ObjectLibrary/B/b2_vs6.c
  62. 52 0
      Tests/ObjectLibrary/CMakeLists.txt
  63. 19 0
      Tests/ObjectLibrary/c.c
  64. 1 0
      Tests/ObjectLibrary/dummy.c
  65. BIN
      Tests/ObjectLibrary/dummy.obj
  66. 16 0
      Tests/ObjectLibrary/main.c
  67. 22 0
      Tests/ObjectLibrary/mainAB.c
  68. 2 0
      Tests/RunCMake/CMakeLists.txt
  69. 1 0
      Tests/RunCMake/ObjectLibrary/BadObjSource1-result.txt
  70. 8 0
      Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt
  71. 1 0
      Tests/RunCMake/ObjectLibrary/BadObjSource1.cmake
  72. 1 0
      Tests/RunCMake/ObjectLibrary/BadObjSource2-result.txt
  73. 8 0
      Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt
  74. 1 0
      Tests/RunCMake/ObjectLibrary/BadObjSource2.cmake
  75. 1 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression1-result.txt
  76. 6 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression1-stderr.txt
  77. 1 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression1.cmake
  78. 1 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression2-result.txt
  79. 4 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression2-stderr.txt
  80. 1 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression2.cmake
  81. 1 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression3-result.txt
  82. 4 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
  83. 2 0
      Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake
  84. 3 0
      Tests/RunCMake/ObjectLibrary/CMakeLists.txt
  85. 1 0
      Tests/RunCMake/ObjectLibrary/Export-result.txt
  86. 4 0
      Tests/RunCMake/ObjectLibrary/Export-stderr.txt
  87. 2 0
      Tests/RunCMake/ObjectLibrary/Export.cmake
  88. 15 0
      Tests/RunCMake/ObjectLibrary/ExportLanguages.cmake
  89. 1 0
      Tests/RunCMake/ObjectLibrary/Import-result.txt
  90. 4 0
      Tests/RunCMake/ObjectLibrary/Import-stderr.txt
  91. 1 0
      Tests/RunCMake/ObjectLibrary/Import.cmake
  92. 1 0
      Tests/RunCMake/ObjectLibrary/Install-result.txt
  93. 4 0
      Tests/RunCMake/ObjectLibrary/Install-stderr.txt
  94. 2 0
      Tests/RunCMake/ObjectLibrary/Install.cmake
  95. 1 0
      Tests/RunCMake/ObjectLibrary/LinkObjLHS-result.txt
  96. 4 0
      Tests/RunCMake/ObjectLibrary/LinkObjLHS-stderr.txt
  97. 2 0
      Tests/RunCMake/ObjectLibrary/LinkObjLHS.cmake
  98. 1 0
      Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt
  99. 6 0
      Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt
  100. 3 0
      Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake

+ 2 - 0
Source/CMakeLists.txt

@@ -185,6 +185,8 @@ SET(SRCS
   cmGeneratedFileStream.cxx
   cmGeneratorExpression.cxx
   cmGeneratorExpression.h
+  cmGeneratorTarget.cxx
+  cmGeneratorTarget.h
   cmGlobalGenerator.cxx
   cmGlobalGenerator.h
   cmGlobalUnixMakefileGenerator3.cxx

+ 14 - 0
Source/cmAddLibraryCommand.cxx

@@ -64,6 +64,12 @@ bool cmAddLibraryCommand
       type = cmTarget::MODULE_LIBRARY;
       haveSpecifiedType = true;
       }
+    else if(libType == "OBJECT")
+      {
+      ++s;
+      type = cmTarget::OBJECT_LIBRARY;
+      haveSpecifiedType = true;
+      }
     else if(libType == "UNKNOWN")
       {
       ++s;
@@ -118,6 +124,14 @@ bool cmAddLibraryCommand
       this->SetError("called with IMPORTED argument but no library type.");
       return false;
       }
+    if(type == cmTarget::OBJECT_LIBRARY)
+      {
+      this->Makefile->IssueMessage(
+        cmake::FATAL_ERROR,
+        "The OBJECT library type may not be used for IMPORTED libraries."
+        );
+      return true;
+      }
 
     // Make sure the target does not already exist.
     if(this->Makefile->FindTargetToUse(libName.c_str()))

+ 20 - 0
Source/cmAddLibraryCommand.h

@@ -112,6 +112,26 @@ public:
       "(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) "
       "which specifies the location of the main library file on disk.  "
       "See documentation of the IMPORTED_* properties for more information."
+      "\n"
+      "The signature\n"
+      "  add_library(<name> OBJECT <src>...)\n"
+      "creates a special \"object library\" target.  "
+      "An object library compiles source files but does not archive or link "
+      "their object files into a library.  "
+      "Instead other targets created by add_library or add_executable may "
+      "reference the objects using an expression of the form "
+      "$<TARGET_OBJECTS:objlib> as a source, where \"objlib\" is the "
+      "object library name.  "
+      "For example:\n"
+      "  add_library(... $<TARGET_OBJECTS:objlib> ...)\n"
+      "  add_executable(... $<TARGET_OBJECTS:objlib> ...)\n"
+      "will include objlib's object files in a library and an executable "
+      "along with those compiled from their own sources.  "
+      "Object libraries may contain only sources (and headers) that compile "
+      "to object files.  "
+      "They may contain custom commands generating such sources, but not "
+      "PRE_BUILD, PRE_LINK, or POST_BUILD commands.  "
+      "Object libraries cannot be imported, exported, installed, or linked."
       ;
     }
   

+ 13 - 0
Source/cmComputeLinkDepends.cxx

@@ -633,6 +633,19 @@ cmTarget* cmComputeLinkDepends::FindTargetToLink(int depender_index,
     tgt = 0;
     }
 
+  if(tgt && tgt->GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    cmOStringStream e;
+    e << "Target \"" << this->Target->GetName() << "\" links to "
+      "OBJECT library \"" << tgt->GetName() << "\" but this is not "
+      "allowed.  "
+      "One may link only to STATIC or SHARED libraries, or to executables "
+      "with the ENABLE_EXPORTS property set.";
+    this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
+                                      this->Target->GetBacktrace());
+    tgt = 0;
+    }
+
   // Return the target found, if any.
   return tgt;
 }

+ 8 - 0
Source/cmExportCommand.cxx

@@ -124,6 +124,14 @@ bool cmExportCommand
         {
         targets.push_back(target);
         }
+      else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
+        {
+        cmOStringStream e;
+        e << "given OBJECT library \"" << *currentTarget
+          << "\" which may not be exported.";
+        this->SetError(e.str().c_str());
+        return false;
+        }
       else
         {
         cmOStringStream e;

+ 172 - 0
Source/cmGeneratorTarget.cxx

@@ -0,0 +1,172 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmGeneratorTarget.h"
+
+#include "cmTarget.h"
+#include "cmMakefile.h"
+#include "cmLocalGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmSourceFile.h"
+
+//----------------------------------------------------------------------------
+cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
+{
+  this->Makefile = this->Target->GetMakefile();
+  this->LocalGenerator = this->Makefile->GetLocalGenerator();
+  this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+  this->ClassifySources();
+  this->LookupObjectLibraries();
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::ClassifySources()
+{
+  bool isObjLib = this->Target->GetType() == cmTarget::OBJECT_LIBRARY;
+  std::vector<cmSourceFile*> badObjLib;
+  std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
+  for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+      si != sources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    cmTarget::SourceFileFlags tsFlags =
+      this->Target->GetTargetSourceFileFlags(sf);
+    if(sf->GetCustomCommand())
+      {
+      this->CustomCommands.push_back(sf);
+      }
+    else if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
+      {
+      this->OSXContent.push_back(sf);
+      if(isObjLib) { badObjLib.push_back(sf); }
+      }
+    else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY"))
+      {
+      this->HeaderSources.push_back(sf);
+      }
+    else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
+      {
+      this->ExternalObjects.push_back(sf);
+      if(isObjLib) { badObjLib.push_back(sf); }
+      }
+    else if(cmSystemTools::LowerCase(sf->GetExtension()) == "def")
+      {
+      this->ModuleDefinitionFile = sf->GetFullPath();
+      if(isObjLib) { badObjLib.push_back(sf); }
+      }
+    else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str()))
+      {
+      // We only get here if a source file is not an external object
+      // and has an extension that is listed as an ignored file type.
+      // No message or diagnosis should be given.
+      }
+    else if(sf->GetLanguage())
+      {
+      this->ObjectSources.push_back(sf);
+      }
+    else
+      {
+      this->ExtraSources.push_back(sf);
+      if(isObjLib && cmSystemTools::LowerCase(sf->GetExtension()) != "txt")
+        {
+        badObjLib.push_back(sf);
+        }
+      }
+    }
+
+  if(!badObjLib.empty())
+    {
+    cmOStringStream e;
+    e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n";
+    for(std::vector<cmSourceFile*>::iterator i = badObjLib.begin();
+        i != badObjLib.end(); ++i)
+      {
+      e << "  " << (*i)->GetLocation().GetName() << "\n";
+      }
+    e << "but may contain only headers and sources that compile.";
+    this->GlobalGenerator->GetCMakeInstance()
+      ->IssueMessage(cmake::FATAL_ERROR, e.str(),
+                     this->Target->GetBacktrace());
+    }
+}
+
+//----------------------------------------------------------------------------
+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.c_str()))
+      {
+      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;
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs)
+{
+  for(std::vector<cmTarget*>::const_iterator
+        ti = this->ObjectLibraries.begin();
+      ti != this->ObjectLibraries.end(); ++ti)
+    {
+    cmTarget* objLib = *ti;
+    cmGeneratorTarget* ogt =
+      this->GlobalGenerator->GetGeneratorTarget(objLib);
+    for(std::vector<cmSourceFile*>::const_iterator
+          si = ogt->ObjectSources.begin();
+        si != ogt->ObjectSources.end(); ++si)
+      {
+      std::string obj = ogt->ObjectDirectory;
+      obj += ogt->Objects[*si];
+      objs.push_back(obj);
+      }
+    }
+}

+ 63 - 0
Source/cmGeneratorTarget.h

@@ -0,0 +1,63 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorTarget_h
+#define cmGeneratorTarget_h
+
+#include "cmStandardIncludes.h"
+
+class cmCustomCommand;
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmTarget;
+
+class cmGeneratorTarget
+{
+public:
+  cmGeneratorTarget(cmTarget*);
+
+  cmTarget* Target;
+  cmMakefile* Makefile;
+  cmLocalGenerator* LocalGenerator;
+  cmGlobalGenerator* GlobalGenerator;
+
+  /** Sources classified by purpose.  */
+  std::vector<cmSourceFile*> CustomCommands;
+  std::vector<cmSourceFile*> ExtraSources;
+  std::vector<cmSourceFile*> HeaderSources;
+  std::vector<cmSourceFile*> ObjectSources;
+  std::vector<cmSourceFile*> ExternalObjects;
+  std::vector<cmSourceFile*> OSXContent;
+  std::string ModuleDefinitionFile;
+
+  std::map<cmSourceFile const*, std::string> Objects;
+  std::set<cmSourceFile const*> ExplicitObjectName;
+
+  /** Full path with trailing slash to the top-level directory
+      holding object files for this target.  Includes the build
+      time config name placeholder if needed for the generator.  */
+  std::string ObjectDirectory;
+
+  std::vector<cmTarget*> ObjectLibraries;
+
+  void UseObjectLibraries(std::vector<std::string>& objs);
+
+private:
+  void ClassifySources();
+  void LookupObjectLibraries();
+
+  cmGeneratorTarget(cmGeneratorTarget const&);
+  void operator=(cmGeneratorTarget const&);
+};
+
+#endif

+ 56 - 1
Source/cmGlobalGenerator.cxx

@@ -24,6 +24,7 @@
 #include "cmExportInstallFileGenerator.h"
 #include "cmComputeTargetDepends.h"
 #include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
 
 #include <cmsys/Directory.hxx>
 
@@ -74,6 +75,7 @@ cmGlobalGenerator::~cmGlobalGenerator()
     delete this->ExtraGenerator;
     }
 
+  this->ClearGeneratorTargets();
   this->ClearExportSets();
 }
 
@@ -807,6 +809,7 @@ bool cmGlobalGenerator::IsDependedOn(const char* project,
 void cmGlobalGenerator::Configure()
 {
   this->FirstTimeProgress = 0.0f;
+  this->ClearGeneratorTargets();
   this->ClearExportSets();
   // Delete any existing cmLocalGenerators
   unsigned int i;
@@ -947,6 +950,9 @@ void cmGlobalGenerator::Generate()
     this->LocalGenerators[i]->GenerateTargetManifest();
     }
 
+  // Create per-target generator information.
+  this->CreateGeneratorTargets();
+
   // Compute the inter-target dependencies.
   if(!this->ComputeTargetDepends())
     {
@@ -1056,6 +1062,55 @@ void cmGlobalGenerator::CreateAutomocTargets()
 #endif
 }
 
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::CreateGeneratorTargets()
+{
+  // Construct per-target generator information.
+  for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
+    {
+    cmTargets& targets =
+      this->LocalGenerators[i]->GetMakefile()->GetTargets();
+    for(cmTargets::iterator ti = targets.begin();
+        ti != targets.end(); ++ti)
+      {
+      cmTarget* t = &ti->second;
+      cmGeneratorTarget* gt = new cmGeneratorTarget(t);
+      this->GeneratorTargets[t] = gt;
+      this->ComputeTargetObjects(gt);
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::ClearGeneratorTargets()
+{
+  for(GeneratorTargetsType::iterator i = this->GeneratorTargets.begin();
+      i != this->GeneratorTargets.end(); ++i)
+    {
+    delete i->second;
+    }
+  this->GeneratorTargets.clear();
+}
+
+//----------------------------------------------------------------------------
+cmGeneratorTarget* cmGlobalGenerator::GetGeneratorTarget(cmTarget* t) const
+{
+  GeneratorTargetsType::const_iterator ti = this->GeneratorTargets.find(t);
+  if(ti == this->GeneratorTargets.end())
+    {
+    this->CMakeInstance->IssueMessage(
+      cmake::INTERNAL_ERROR, "Missing cmGeneratorTarget instance!",
+      cmListFileBacktrace());
+    return 0;
+    }
+  return ti->second;
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::ComputeTargetObjects(cmGeneratorTarget*) const
+{
+  // Implemented in generator subclasses that need this.
+}
 
 void cmGlobalGenerator::CheckLocalGenerators()
 {
@@ -1714,7 +1769,7 @@ void cmGlobalGenerator::SetCMakeInstance(cmake* cm)
 void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
 {
   cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
-  const char* cmakeCfgIntDir = this->GetCMakeCFGInitDirectory();
+  const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
   const char* cmakeCommand = mf->GetRequiredDefinition("CMAKE_COMMAND");
 
   // CPack

+ 12 - 1
Source/cmGlobalGenerator.h

@@ -19,6 +19,7 @@
 #include "cmTargetDepend.h" // For cmTargetDependSet
 #include "cmSystemTools.h" // for cmSystemTools::OutputOption
 class cmake;
+class cmGeneratorTarget;
 class cmMakefile;
 class cmLocalGenerator;
 class cmExternalMakefileProjectGenerator;
@@ -183,7 +184,7 @@ public:
   const char* GetLanguageOutputExtension(cmSourceFile const&);
 
   ///! What is the configurations directory variable called?
-  virtual const char* GetCMakeCFGInitDirectory()  { return "."; }
+  virtual const char* GetCMakeCFGIntDir() const { return "."; }
 
   /** Get whether the generator should use a script for link commands.  */
   bool GetUseLinkScript() const { return this->UseLinkScript; }
@@ -251,6 +252,9 @@ public:
   // via a target_link_libraries or add_dependencies
   TargetDependSet const& GetTargetDirectDepends(cmTarget & target);
 
+  /** Get per-target generator information.  */
+  cmGeneratorTarget* GetGeneratorTarget(cmTarget*) const;
+
   const std::map<cmStdString, std::vector<cmLocalGenerator*> >& GetProjectMap()
                                                const {return this->ProjectMap;}
 
@@ -370,6 +374,13 @@ private:
   typedef std::map<cmTarget *, TargetDependSet> TargetDependMap;
   TargetDependMap TargetDependencies;
 
+  // Per-target generator information.
+  typedef std::map<cmTarget*, cmGeneratorTarget*> GeneratorTargetsType;
+  GeneratorTargetsType GeneratorTargets;
+  void CreateGeneratorTargets();
+  void ClearGeneratorTargets();
+  virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
+
   // Cache directory content and target files to be built.
   struct DirectoryContent: public std::set<cmStdString>
   {

+ 30 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -14,6 +14,7 @@
 #include "cmLocalNinjaGenerator.h"
 #include "cmMakefile.h"
 #include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
 #include "cmVersion.h"
 
 const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
@@ -499,6 +500,34 @@ bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
   return (rule != this->Rules.end());
 }
 
+//----------------------------------------------------------------------------
+// Private virtual overrides
+
+// TODO: Refactor to combine with cmGlobalUnixMakefileGenerator3 impl.
+void cmGlobalNinjaGenerator::ComputeTargetObjects(cmGeneratorTarget* gt) const
+{
+  cmTarget* target = gt->Target;
+
+  // Compute full path to object file directory for this target.
+  std::string dir_max;
+  dir_max += gt->Makefile->GetCurrentOutputDirectory();
+  dir_max += "/";
+  dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
+  dir_max += "/";
+  gt->ObjectDirectory = dir_max;
+
+  // Compute the name of each object file.
+  for(std::vector<cmSourceFile*>::iterator
+        si = gt->ObjectSources.begin();
+      si != gt->ObjectSources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    std::string objectName = gt->LocalGenerator
+      ->GetObjectFileNameWithoutTarget(*sf, dir_max);
+    gt->Objects[sf] = objectName;
+    }
+}
+
 //----------------------------------------------------------------------------
 // Private methods
 
@@ -635,6 +664,7 @@ cmGlobalNinjaGenerator
       target->GetFullPath(configName).c_str()));
     break;
 
+  case cmTarget::OBJECT_LIBRARY:
   case cmTarget::UTILITY: {
     std::string path = ng->ConvertToNinjaPath(
       target->GetMakefile()->GetStartOutputDirectory());

+ 6 - 0
Source/cmGlobalNinjaGenerator.h

@@ -18,6 +18,7 @@
 
 class cmLocalGenerator;
 class cmGeneratedFileStream;
+class cmGeneratorTarget;
 
 /**
  * \class cmGlobalNinjaGenerator
@@ -235,6 +236,11 @@ protected:
   /// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
   virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
 
+private:
+
+  /// @see cmGlobalGenerator::ComputeTargetObjects
+  virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
+
 private:
   // In order to access the AddDependencyToAll() functions and co.
   friend class cmLocalNinjaGenerator;

+ 38 - 0
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -17,6 +17,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmSourceFile.h"
 #include "cmTarget.h"
+#include "cmGeneratorTarget.h"
 
 cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
 {
@@ -70,6 +71,38 @@ void cmGlobalUnixMakefileGenerator3
     "default make target.  A \"make install\" target is also provided.";
 }
 
+//----------------------------------------------------------------------------
+void
+cmGlobalUnixMakefileGenerator3
+::ComputeTargetObjects(cmGeneratorTarget* gt) const
+{
+  cmTarget* target = gt->Target;
+  cmLocalUnixMakefileGenerator3* lg =
+    static_cast<cmLocalUnixMakefileGenerator3*>(gt->LocalGenerator);
+
+  // Compute full path to object file directory for this target.
+  std::string dir_max;
+  dir_max += gt->Makefile->GetCurrentOutputDirectory();
+  dir_max += "/";
+  dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
+  dir_max += "/";
+  gt->ObjectDirectory = dir_max;
+
+  // Compute the name of each object file.
+  for(std::vector<cmSourceFile*>::iterator
+        si = gt->ObjectSources.begin();
+      si != gt->ObjectSources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    bool hasSourceExtension = true;
+    std::string objectName = gt->LocalGenerator
+      ->GetObjectFileNameWithoutTarget(*sf, dir_max,
+                                       &hasSourceExtension);
+    gt->Objects[sf] = objectName;
+    lg->AddLocalObjectFile(target, sf, objectName, hasSourceExtension);
+    }
+}
+
 //----------------------------------------------------------------------------
 std::string EscapeJSON(const std::string& s) {
   std::string result;
@@ -378,6 +411,7 @@ void cmGlobalUnixMakefileGenerator3
          (l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
          (l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
          (l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+         (l->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
          (l->second.GetType() == cmTarget::UTILITY))
         {
         std::string tname = lg->GetRelativeTargetDirectory(l->second);
@@ -413,6 +447,7 @@ cmGlobalUnixMakefileGenerator3
        (l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
        (l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
        (l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+       (l->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
        (l->second.GetType() == cmTarget::UTILITY))
       {
       // Add this to the list of depends rules in this directory.
@@ -587,6 +622,7 @@ cmGlobalUnixMakefileGenerator3
           (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
           (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
           (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+          (t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
           (t->second.GetType() == cmTarget::UTILITY)))
         {
         // Add a rule to build the target by name.
@@ -673,6 +709,7 @@ cmGlobalUnixMakefileGenerator3
         || (t->second.GetType() == cmTarget::STATIC_LIBRARY)
         || (t->second.GetType() == cmTarget::SHARED_LIBRARY)
         || (t->second.GetType() == cmTarget::MODULE_LIBRARY)
+        || (t->second.GetType() == cmTarget::OBJECT_LIBRARY)
         || (t->second.GetType() == cmTarget::UTILITY)))
       {
       std::string makefileName;
@@ -982,6 +1019,7 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule
            (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
            (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
            (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+           (t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
            (t->second.GetType() == cmTarget::GLOBAL_TARGET) ||
            (t->second.GetType() == cmTarget::UTILITY))
           {

+ 2 - 0
Source/cmGlobalUnixMakefileGenerator3.h

@@ -182,6 +182,8 @@ protected:
   size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
 
   cmGeneratedFileStream *CommandDatabase;
+private:
+  virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
 };
 
 #endif

+ 1 - 1
Source/cmGlobalVisualStudio10Generator.h

@@ -72,7 +72,7 @@ public:
    * Studio?
    */
   virtual std::string GetUserMacrosRegKeyBase();
-  virtual const char* GetCMakeCFGInitDirectory() 
+  virtual const char* GetCMakeCFGIntDir() const
     { return "$(Configuration)";}
   bool Find64BitTools(cmMakefile* mf);
 protected:

+ 1 - 1
Source/cmGlobalVisualStudio6Generator.h

@@ -82,7 +82,7 @@ public:
                                         std::string& dir);
 
   ///! What is the configurations directory variable called?
-  virtual const char* GetCMakeCFGInitDirectory()  { return "$(IntDir)"; }
+  virtual const char* GetCMakeCFGIntDir() const { return "$(IntDir)"; }
 
 protected:
   virtual const char* GetIDEVersion() { return "6.0"; }

+ 1 - 1
Source/cmGlobalVisualStudio7Generator.h

@@ -87,7 +87,7 @@ public:
                                         std::string& dir);
 
   ///! What is the configurations directory variable called?
-  virtual const char* GetCMakeCFGInitDirectory()  { return "$(OutDir)"; }
+  virtual const char* GetCMakeCFGIntDir() const { return "$(OutDir)"; }
 
   /** Return true if the target project file should have the option
       LinkLibraryDependencies and link to .sln dependencies. */

+ 68 - 2
Source/cmGlobalVisualStudioGenerator.cxx

@@ -12,8 +12,10 @@
 #include "cmGlobalVisualStudioGenerator.h"
 
 #include "cmCallVisualStudioMacro.h"
-#include "cmLocalGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalVisualStudioGenerator.h"
 #include "cmMakefile.h"
+#include "cmSourceFile.h"
 #include "cmTarget.h"
 
 //----------------------------------------------------------------------------
@@ -97,6 +99,64 @@ void cmGlobalVisualStudioGenerator::Generate()
   this->cmGlobalGenerator::Generate();
 }
 
+//----------------------------------------------------------------------------
+void
+cmGlobalVisualStudioGenerator
+::ComputeTargetObjects(cmGeneratorTarget* gt) const
+{
+  cmLocalVisualStudioGenerator* lg =
+    static_cast<cmLocalVisualStudioGenerator*>(gt->LocalGenerator);
+  std::string dir_max = lg->ComputeLongestObjectDirectory(*gt->Target);
+
+  // Count the number of object files with each name.  Note that
+  // windows file names are not case sensitive.
+  std::map<cmStdString, int> counts;
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = gt->ObjectSources.begin();
+      si != gt->ObjectSources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    std::string objectNameLower = cmSystemTools::LowerCase(
+      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
+    objectNameLower += ".obj";
+    counts[objectNameLower] += 1;
+    }
+
+  // For all source files producing duplicate names we need unique
+  // object name computation.
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = gt->ObjectSources.begin();
+      si != gt->ObjectSources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    std::string objectName =
+      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    objectName += ".obj";
+    if(counts[cmSystemTools::LowerCase(objectName)] > 1)
+      {
+      gt->ExplicitObjectName.insert(sf);
+      objectName = lg->GetObjectFileNameWithoutTarget(*sf, dir_max);
+      }
+    gt->Objects[sf] = objectName;
+    }
+
+  std::string dir = gt->Makefile->GetCurrentOutputDirectory();
+  dir += "/";
+  std::string tgtDir = lg->GetTargetDirectory(*gt->Target);
+  if(!tgtDir.empty())
+    {
+    dir += tgtDir;
+    dir += "/";
+    }
+  const char* cd = this->GetCMakeCFGIntDir();
+  if(cd && *cd)
+    {
+    dir += cd;
+    dir += "/";
+    }
+  gt->ObjectDirectory = dir;
+}
+
 //----------------------------------------------------------------------------
 bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
   const std::string& regKeyBase,
@@ -314,6 +374,12 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
   return true;
 }
 
+//----------------------------------------------------------------------------
+static bool VSLinkable(cmTarget* t)
+{
+  return t->IsLinkable() || t->GetType() == cmTarget::OBJECT_LIBRARY;
+}
+
 //----------------------------------------------------------------------------
 void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
 {
@@ -398,7 +464,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
       di != utilDepends.end(); ++di)
     {
     cmTarget* dep = *di;
-    if(allowLinkable || !dep->IsLinkable() || linked.count(dep))
+    if(allowLinkable || !VSLinkable(dep) || linked.count(dep))
       {
       // Direct dependency allowed.
       vsTargetDepend.insert(dep->GetName());

+ 2 - 0
Source/cmGlobalVisualStudioGenerator.h

@@ -97,6 +97,8 @@ protected:
   typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
   UtilityDependsMap UtilityDepends;
 private:
+  void ComputeTargetObjects(cmGeneratorTarget* gt) const;
+
   void FollowLinkDepends(cmTarget* target, std::set<cmTarget*>& linked);
 
   class TargetSetMap: public std::map<cmTarget*, TargetSet> {};

+ 267 - 66
Source/cmGlobalXCodeGenerator.cxx

@@ -19,6 +19,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmSourceFile.h"
 #include "cmCustomCommandGenerator.h"
+#include "cmGeneratorTarget.h"
 
 #include <cmsys/auto_ptr.hxx>
 
@@ -303,6 +304,10 @@ void cmGlobalXCodeGenerator::Generate()
     }
   this->ForceLinkerLanguages();
   this->cmGlobalGenerator::Generate();
+  if(cmSystemTools::GetErrorOccuredFlag())
+    {
+    return;
+    }
   for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
     {
     cmLocalGenerator* root = it->second[0];
@@ -417,6 +422,8 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
       // this will make sure that when the next target is built
       // things are up-to-date
       if((target.GetType() == cmTarget::EXECUTABLE ||
+// Nope - no post-build for OBJECT_LIRBRARY
+//          target.GetType() == cmTarget::OBJECT_LIBRARY ||
           target.GetType() == cmTarget::STATIC_LIBRARY ||
           target.GetType() == cmTarget::SHARED_LIBRARY ||
           target.GetType() == cmTarget::MODULE_LIBRARY))
@@ -570,14 +577,42 @@ cmXCodeObject* cmGlobalXCodeGenerator
 }
 
 //----------------------------------------------------------------------------
-cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
+cmStdString
+GetGroupMapKeyFromPath(cmTarget& cmtarget, const std::string& fullpath)
 {
   cmStdString key(cmtarget.GetName());
   key += "-";
-  key += sf->GetFullPath();
+  key += fullpath;
   return key;
 }
 
+//----------------------------------------------------------------------------
+cmStdString
+GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
+{
+  return GetGroupMapKeyFromPath(cmtarget, sf->GetFullPath());
+}
+
+//----------------------------------------------------------------------------
+cmXCodeObject*
+cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
+  const std::string &fullpath,
+  cmTarget& cmtarget,
+  const std::string &lang)
+{
+  // Using a map and the full path guarantees that we will always get the same
+  // fileRef object for any given full path.
+  //
+  cmXCodeObject* fileRef =
+    this->CreateXCodeFileReferenceFromPath(fullpath, cmtarget, lang);
+
+  cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+  buildFile->SetComment(fileRef->GetComment());
+  buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
+
+  return buildFile;
+}
+
 //----------------------------------------------------------------------------
 cmXCodeObject*
 cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
@@ -612,14 +647,16 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
     flags += flagsBuild.GetString();
     }
 
-  // Using a map and the full path guarantees that we will always get the same
-  // fileRef object for any given full path.
-  //
-  cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
+  const char* lang =
+    this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+  if (!lang)
+    {
+    lang = "";
+    }
 
-  cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
-  buildFile->SetComment(fileRef->GetComment());
-  buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
+  cmXCodeObject* buildFile =
+    this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), cmtarget, lang);
+  cmXCodeObject* fileRef = buildFile->GetObject("fileRef")->GetObject();
 
   cmXCodeObject* settings =
     this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
@@ -671,36 +708,12 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
 }
 
 //----------------------------------------------------------------------------
-cmXCodeObject*
-cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
-                                                 cmTarget& cmtarget)
+std::string
+GetSourcecodeValueFromFileExtension(const std::string& _ext,
+                                    const std::string& lang)
 {
-  std::string fname = sf->GetFullPath();
-  cmXCodeObject* fileRef = this->FileRefs[fname];
-  if(!fileRef)
-    {
-    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
-    std::string comment = fname;
-    //comment += " in ";
-    //std::string gname = group->GetObject("name")->GetString();
-    //comment += gname.substr(1, gname.size()-2);
-    fileRef->SetComment(fname.c_str());
-    this->FileRefs[fname] = fileRef;
-    }
-  cmStdString key = GetGroupMapKey(cmtarget, sf);
-  cmXCodeObject* group = this->GroupMap[key];
-  cmXCodeObject* children = group->GetObject("children");
-  if (!children->HasObject(fileRef))
-    {
-    children->AddObject(fileRef);
-    }
-  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
-
-  const char* lang =
-    this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+  std::string ext = cmSystemTools::LowerCase(_ext);
   std::string sourcecode = "sourcecode";
-  std::string ext = sf->GetExtension();
-  ext = cmSystemTools::LowerCase(ext);
 
   if(ext == "o")
     {
@@ -735,25 +748,25 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
     {
     sourcecode += ".cpp.h";
     }
-  else if(lang && strcmp(lang, "CXX") == 0)
+  else if(ext == "png" || ext == "gif" || ext == "jpg")
     {
-    sourcecode += ".cpp.cpp";
+    sourcecode = "image";
     }
-  else if(lang && strcmp(lang, "C") == 0)
+  else if(ext == "txt")
     {
-    sourcecode += ".c.c";
+    sourcecode += ".text";
     }
-  else if(lang && strcmp(lang, "Fortran") == 0)
+  else if(lang == "CXX")
     {
-    sourcecode += ".fortran.f90";
+    sourcecode += ".cpp.cpp";
     }
-  else if(ext == "png" || ext == "gif" || ext == "jpg")
+  else if(lang == "C")
     {
-    sourcecode = "image";
+    sourcecode += ".c.c";
     }
-  else if(ext == "txt")
+  else if(lang == "Fortran")
     {
-    sourcecode += ".text";
+    sourcecode += ".fortran.f90";
     }
   //else
   //  {
@@ -763,11 +776,51 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
   //  // valid lastKnownFileType value.
   //  }
 
+  return sourcecode;
+}
+
+//----------------------------------------------------------------------------
+cmXCodeObject*
+cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
+  const std::string &fullpath,
+  cmTarget& cmtarget,
+  const std::string &lang)
+{
+  std::string fname = fullpath;
+  cmXCodeObject* fileRef = this->FileRefs[fname];
+  if(!fileRef)
+    {
+    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+    std::string comment = fname;
+    fileRef->SetComment(fname.c_str());
+    this->FileRefs[fname] = fileRef;
+    }
+  cmStdString key = GetGroupMapKeyFromPath(cmtarget, fullpath);
+  cmXCodeObject* group = this->GroupMap[key];
+  cmXCodeObject* children = group->GetObject("children");
+  if (!children->HasObject(fileRef))
+    {
+    children->AddObject(fileRef);
+    }
+  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
+
+  // Compute the extension.
+  std::string ext;
+  std::string realExt =
+    cmSystemTools::GetFilenameLastExtension(fullpath);
+  if(!realExt.empty())
+    {
+    // Extension without the leading '.'.
+    ext = realExt.substr(1);
+    }
+
+  std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang);
+
   fileRef->AddAttribute("lastKnownFileType",
                         this->CreateString(sourcecode.c_str()));
 
   // Store the file path relative to the top of the source tree.
-  std::string path = this->RelativeToSource(sf->GetFullPath().c_str());
+  std::string path = this->RelativeToSource(fullpath.c_str());
   std::string name = cmSystemTools::GetFilenameName(path.c_str());
   const char* sourceTree = (cmSystemTools::FileIsFullPath(path.c_str())?
                             "<absolute>" : "SOURCE_ROOT");
@@ -781,6 +834,22 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
   return fileRef;
 }
 
+//----------------------------------------------------------------------------
+cmXCodeObject*
+cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
+                                                 cmTarget& cmtarget)
+{
+  const char* lang =
+    this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
+  if (!lang)
+    {
+    lang = "";
+    }
+
+  return this->CreateXCodeFileReferenceFromPath(
+    sf->GetFullPath(), cmtarget, lang);
+}
+
 //----------------------------------------------------------------------------
 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
 {
@@ -889,6 +958,20 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
         }
       }
 
+    // Add object library contents as external objects. (Equivalent to
+    // the externalObjFiles above, except each one is not a cmSourceFile
+    // within the target.)
+    std::vector<std::string> objs;
+    this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
+    for(std::vector<std::string>::const_iterator
+          oi = objs.begin(); oi != objs.end(); ++oi)
+      {
+      std::string obj = *oi;
+      cmXCodeObject* xsf =
+        this->CreateXCodeSourceFileFromPath(obj, cmtarget, "");
+      externalObjFiles.push_back(xsf);
+      }
+
     // some build phases only apply to bundles and/or frameworks
     bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
     bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
@@ -1494,7 +1577,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
   std::string defFlags;
   bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
                  (target.GetType() == cmTarget::MODULE_LIBRARY));
-  bool binary = ((target.GetType() == cmTarget::STATIC_LIBRARY) ||
+  bool binary = ((target.GetType() == cmTarget::OBJECT_LIBRARY) ||
+                 (target.GetType() == cmTarget::STATIC_LIBRARY) ||
                  (target.GetType() == cmTarget::EXECUTABLE) ||
                  shared);
 
@@ -1581,7 +1665,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
     }
 
   const char* linkFlagsProp = "LINK_FLAGS";
-  if(target.GetType() == cmTarget::STATIC_LIBRARY)
+  if(target.GetType() == cmTarget::OBJECT_LIBRARY ||
+     target.GetType() == cmTarget::STATIC_LIBRARY)
     {
     linkFlagsProp = "STATIC_LIBRARY_FLAGS";
     }
@@ -1635,11 +1720,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
   std::string pnprefix;
   std::string pnbase;
   std::string pnsuffix;
-  target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
 
-  // Store the product name for all target types.
-  buildSettings->AddAttribute("PRODUCT_NAME",
-                              this->CreateString(pnbase.c_str()));
+  target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
 
   // Set attributes to specify the proper name for the target.
   std::string pndir = this->CurrentMakefile->GetCurrentOutputDirectory();
@@ -1663,17 +1745,44 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
                                   this->CreateString(pndir.c_str()));
       pndir = target.GetDirectory(configName);
       }
+
     buildSettings->AddAttribute("EXECUTABLE_PREFIX",
                                 this->CreateString(pnprefix.c_str()));
     buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
                                 this->CreateString(pnsuffix.c_str()));
     }
+  else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    pnprefix = "lib";
+    pnbase = target.GetName();
+    pnsuffix = ".a";
+
+    if(this->XcodeVersion >= 21)
+      {
+      std::string pncdir = this->GetObjectsNormalDirectory(
+        this->CurrentProject, configName, &target);
+      buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
+                                  this->CreateString(pncdir.c_str()));
+      }
+    else
+      {
+      buildSettings->AddAttribute("OBJROOT",
+                                  this->CreateString(pndir.c_str()));
+      pndir = this->GetObjectsNormalDirectory(
+        this->CurrentProject, configName, &target);
+      }
+    }
+
+  // Store the product name for all target types.
+  buildSettings->AddAttribute("PRODUCT_NAME",
+                              this->CreateString(pnbase.c_str()));
   buildSettings->AddAttribute("SYMROOT",
                               this->CreateString(pndir.c_str()));
 
   // Handle settings for each target type.
   switch(target.GetType())
     {
+    case cmTarget::OBJECT_LIBRARY:
     case cmTarget::STATIC_LIBRARY:
     {
     buildSettings->AddAttribute("LIBRARY_STYLE",
@@ -2177,6 +2286,7 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
 {
   switch(cmtarget.GetType())
     {
+    case cmTarget::OBJECT_LIBRARY:
     case cmTarget::STATIC_LIBRARY:
       return "archive.ar";
     case cmTarget::MODULE_LIBRARY:
@@ -2200,6 +2310,7 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
 {
   switch(cmtarget.GetType())
     {
+    case cmTarget::OBJECT_LIBRARY:
     case cmTarget::STATIC_LIBRARY:
       return "com.apple.product-type.library.static";
     case cmTarget::MODULE_LIBRARY:
@@ -2257,7 +2368,17 @@ cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
     {
     fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
     }
-  std::string fullName = cmtarget.GetFullName(defConfig.c_str());
+  std::string fullName;
+  if(cmtarget.GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    fullName = "lib";
+    fullName += cmtarget.GetName();
+    fullName += ".a";
+    }
+  else
+    {
+    fullName = cmtarget.GetFullName(defConfig.c_str());
+    }
   fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
   fileRef->AddAttribute("refType", this->CreateString("0"));
   fileRef->AddAttribute("sourceTree",
@@ -2462,7 +2583,8 @@ void cmGlobalXCodeGenerator
     }
 
   // Skip link information for static libraries.
-  if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
+  if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY ||
+     cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
     {
     return;
     }
@@ -2610,6 +2732,7 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
 
       std::vector<cmSourceFile*>  classes = cmtarget.GetSourceFiles();
 
+      // Put cmSourceFile instances in proper groups:
       for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
           s != classes.end(); s++)
         {
@@ -2623,6 +2746,21 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
         cmStdString key = GetGroupMapKey(cmtarget, sf);
         this->GroupMap[key] = pbxgroup;
         }
+
+      // Put OBJECT_LIBRARY objects in proper groups:
+      std::vector<std::string> objs;
+      this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
+      for(std::vector<std::string>::const_iterator
+            oi = objs.begin(); oi != objs.end(); ++oi)
+        {
+        std::string const& source = *oi;
+        cmSourceGroup& sourceGroup =
+          mf->FindSourceGroup(source.c_str(), sourceGroups);
+        cmXCodeObject* pbxgroup =
+          this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
+        cmStdString key = GetGroupMapKeyFromPath(cmtarget, source);
+        this->GroupMap[key] = pbxgroup;
+        }
       }
     }
 }
@@ -3054,6 +3192,26 @@ void cmGlobalXCodeGenerator
   this->RootObject->AddAttribute("targets", allTargets);
 }
 
+//----------------------------------------------------------------------------
+std::string
+cmGlobalXCodeGenerator::GetObjectsNormalDirectory(
+  const std::string &projName,
+  const std::string &configName,
+  const cmTarget *t) const
+{
+  std::string dir =
+    t->GetMakefile()->GetCurrentOutputDirectory();
+  dir += "/";
+  dir += projName;
+  dir += ".build/";
+  dir += configName;
+  dir += "/";
+  dir += t->GetName();
+  dir += ".build/Objects-normal/";
+
+  return dir;
+}
+
 //----------------------------------------------------------------------------
 void
 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
@@ -3123,6 +3281,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
       cmTarget* t =target->GetTarget();
 
       if(t->GetType() == cmTarget::EXECUTABLE ||
+// Nope - no post-build for OBJECT_LIRBRARY
+//         t->GetType() == cmTarget::OBJECT_LIBRARY ||
          t->GetType() == cmTarget::STATIC_LIBRARY ||
          t->GetType() == cmTarget::SHARED_LIBRARY ||
          t->GetType() == cmTarget::MODULE_LIBRARY)
@@ -3178,15 +3338,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
         // then remove those exectuables as well
         if(this->Architectures.size() > 1)
           {
-          std::string universal =
-            t->GetMakefile()->GetCurrentOutputDirectory();
-          universal += "/";
-          universal += this->CurrentProject;
-          universal += ".build/";
-          universal += configName;
-          universal += "/";
-          universal += t->GetName();
-          universal += ".build/Objects-normal/";
+          std::string universal = this->GetObjectsNormalDirectory(
+            this->CurrentProject, configName, t);
           for( std::vector<std::string>::iterator arch =
                  this->Architectures.begin();
                arch != this->Architectures.end(); ++arch)
@@ -3292,7 +3445,7 @@ cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
 }
 
 //----------------------------------------------------------------------------
-const char* cmGlobalXCodeGenerator::GetCMakeCFGInitDirectory()
+const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
 {
   return this->XcodeVersion >= 21 ?
     "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" : ".";
@@ -3545,3 +3698,51 @@ bool cmGlobalXCodeGenerator::IsMultiConfig()
   // Newer Xcode versions are multi config:
   return true;
 }
+
+ //----------------------------------------------------------------------------
+void
+cmGlobalXCodeGenerator
+::ComputeTargetObjects(cmGeneratorTarget* gt) const
+{
+  // Count the number of object files with each name. Warn about duplicate
+  // names since Xcode names them uniquely automatically with a numeric suffix
+  // to avoid exact duplicate file names. Note that Mac file names are not
+  // typically case sensitive, hence the LowerCase.
+  std::map<cmStdString, int> counts;
+  for(std::vector<cmSourceFile*>::const_iterator
+      si = gt->ObjectSources.begin();
+      si != gt->ObjectSources.end(); ++si)
+    {
+    cmSourceFile* sf = *si;
+    std::string objectName =
+      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    objectName += ".o";
+
+    std::string objectNameLower = cmSystemTools::LowerCase(objectName);
+    counts[objectNameLower] += 1;
+    if (2 == counts[objectNameLower])
+      {
+      // TODO: emit warning about duplicate name?
+      }
+
+    gt->Objects[sf] = objectName;
+    }
+
+  const char* configName = this->GetCMakeCFGIntDir();
+  std::string dir = this->GetObjectsNormalDirectory(
+    this->CurrentProject, configName, gt->Target);
+  if(this->XcodeVersion >= 21)
+    {
+    dir += "$(CURRENT_ARCH)/";
+    }
+  else
+    {
+#ifdef __ppc__
+    dir += "ppc/";
+#endif
+#ifdef __i386
+    dir += "i386/";
+#endif
+    }
+  gt->ObjectDirectory = dir;
+}

+ 14 - 1
Source/cmGlobalXCodeGenerator.h

@@ -74,7 +74,7 @@ public:
                                         std::string& dir);
 
   ///! What is the configurations directory variable called?
-  virtual const char* GetCMakeCFGInitDirectory();
+  virtual const char* GetCMakeCFGIntDir() const;
 
   void SetCurrentLocalGenerator(cmLocalGenerator*);
 
@@ -153,6 +153,12 @@ private:
                           std::vector<cmLocalGenerator*>& generators);
   void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
                          std::vector<cmLocalGenerator*>& generators);
+  cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string &fullpath,
+                                                  cmTarget& cmtarget,
+                                                  const std::string &lang);
+  cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string &fullpath,
+                                               cmTarget& cmtarget,
+                                               const std::string &lang);
   cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
                                           cmTarget& cmtarget);
   cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, 
@@ -200,6 +206,13 @@ protected:
   std::vector<cmXCodeObject*> XCodeObjects;
   cmXCodeObject* RootObject;
 private:
+  void ComputeTargetObjects(cmGeneratorTarget* gt) const;
+
+  std::string GetObjectsNormalDirectory(
+    const std::string &projName,
+    const std::string &configName,
+    const cmTarget *t) const;
+
   void addObject(cmXCodeObject *obj);
   std::string PostBuildMakeTarget(std::string const& tName,
                                   std::string const& configName);

+ 10 - 1
Source/cmInstallCommand.cxx

@@ -357,7 +357,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
       if(target->GetType() != cmTarget::EXECUTABLE &&
          target->GetType() != cmTarget::STATIC_LIBRARY &&
          target->GetType() != cmTarget::SHARED_LIBRARY &&
-         target->GetType() != cmTarget::MODULE_LIBRARY)
+         target->GetType() != cmTarget::MODULE_LIBRARY &&
+         target->GetType() != cmTarget::OBJECT_LIBRARY)
         {
         cmOStringStream e;
         e << "TARGETS given target \"" << (*targetIt)
@@ -365,6 +366,14 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
         this->SetError(e.str().c_str());
         return false;
         }
+      else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
+        {
+        cmOStringStream e;
+        e << "TARGETS given OBJECT library \"" << (*targetIt)
+          << "\" which may not be installed.";
+        this->SetError(e.str().c_str());
+        return false;
+        }
       // Store the target in the list to be installed.
       targets.push_back(target);
       }

+ 1 - 0
Source/cmInstallTargetGenerator.cxx

@@ -90,6 +90,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
     case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break;
     case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break;
     case cmTarget::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break;
+    case cmTarget::OBJECT_LIBRARY:
     case cmTarget::UTILITY:
     case cmTarget::GLOBAL_TARGET:
     case cmTarget::UNKNOWN_LIBRARY:

+ 4 - 0
Source/cmLocalGenerator.cxx

@@ -1914,6 +1914,10 @@ bool cmLocalGenerator::GetRealDependency(const char* inName,
       case cmTarget::UNKNOWN_LIBRARY:
         dep = target->GetLocation(config);
         return true;
+      case cmTarget::OBJECT_LIBRARY:
+        // An object library has no single file on which to depend.
+        // This was listed to get the target-level dependency.
+        return false;
       case cmTarget::UTILITY:
       case cmTarget::GLOBAL_TARGET:
         // A utility target has no file on which to depend.  This was listed

+ 0 - 31
Source/cmLocalNinjaGenerator.cxx

@@ -117,37 +117,6 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
   return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
 }
 
-// TODO: Picked up from cmLocalUnixMakefileGenerator3.  Refactor it.
-std::string
-cmLocalNinjaGenerator
-::GetObjectFileName(const cmTarget& target,
-                    const cmSourceFile& source)
-{
-  // Make sure we never hit this old case.
-  if(source.GetProperty("MACOSX_PACKAGE_LOCATION"))
-    {
-    std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: ";
-    msg += source.GetFullPath();
-    this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
-                                      msg.c_str());
-    }
-
-  // Start with the target directory.
-  std::string obj = this->GetTargetDirectory(target);
-  obj += "/";
-
-  // Get the object file name without the target directory.
-  std::string dir_max;
-  dir_max += this->Makefile->GetCurrentOutputDirectory();
-  dir_max += "/";
-  dir_max += obj;
-  std::string objectName =
-    this->GetObjectFileNameWithoutTarget(source, dir_max, 0);
-  // Append the object name to the target directory.
-  obj += objectName;
-  return obj;
-}
-
 //----------------------------------------------------------------------------
 // Virtual protected methods.
 

+ 0 - 3
Source/cmLocalNinjaGenerator.h

@@ -59,9 +59,6 @@ public:
   const char* GetConfigName() const
   { return this->ConfigName.c_str(); }
 
-  std::string GetObjectFileName(const cmTarget& target,
-                                const cmSourceFile& source);
-
   /// @return whether we are processing the top CMakeLists.txt file.
   bool isRootMakefile() const;
 

+ 1 - 39
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -358,6 +358,7 @@ void cmLocalUnixMakefileGenerator3
        (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
        (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
        (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
+       (t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
        (t->second.GetType() == cmTarget::UTILITY))
       {
       emitted.insert(t->second.GetName());
@@ -2008,45 +2009,6 @@ void cmLocalUnixMakefileGenerator3
     }
 }
 
-//----------------------------------------------------------------------------
-std::string
-cmLocalUnixMakefileGenerator3
-::GetObjectFileName(cmTarget& target,
-                    const cmSourceFile& source,
-                    std::string* nameWithoutTargetDir,
-                    bool* hasSourceExtension)
-{
-  // Make sure we never hit this old case.
-  if(source.GetProperty("MACOSX_PACKAGE_LOCATION"))
-    {
-    std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: ";
-    msg += source.GetFullPath();
-    this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
-                                      msg.c_str());
-    }
-
-  // Start with the target directory.
-  std::string obj = this->GetTargetDirectory(target);
-  obj += "/";
-
-  // Get the object file name without the target directory.
-  std::string dir_max;
-  dir_max += this->Makefile->GetCurrentOutputDirectory();
-  dir_max += "/";
-  dir_max += obj;
-  std::string objectName =
-    this->GetObjectFileNameWithoutTarget(source, dir_max,
-                                         hasSourceExtension);
-  if(nameWithoutTargetDir)
-    {
-    *nameWithoutTargetDir = objectName;
-    }
-
-  // Append the object name to the target directory.
-  obj += objectName;
-  return obj;
-}
-
 //----------------------------------------------------------------------------
 void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
 {

+ 0 - 5
Source/cmLocalUnixMakefileGenerator3.h

@@ -284,11 +284,6 @@ protected:
                                cmTarget& target,
                                const std::vector<std::string>& objects);
 
-  std::string GetObjectFileName(cmTarget& target,
-                                const cmSourceFile& source,
-                                std::string* nameWithoutTargetDir = 0,
-                                bool* hasSourceExtension = 0);
-
   void AppendRuleDepend(std::vector<std::string>& depends,
                         const char* ruleFileName);
   void AppendRuleDepends(std::vector<std::string>& depends,

+ 102 - 39
Source/cmLocalVisualStudio6Generator.cxx

@@ -15,6 +15,7 @@
 #include "cmSystemTools.h"
 #include "cmSourceFile.h"
 #include "cmCacheManager.h"
+#include "cmGeneratorTarget.h"
 #include "cmake.h"
 
 #include "cmComputeLinkInformation.h"
@@ -126,6 +127,7 @@ void cmLocalVisualStudio6Generator::OutputDSPFile()
     switch(l->second.GetType())
       {
       case cmTarget::STATIC_LIBRARY:
+      case cmTarget::OBJECT_LIBRARY:
         this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second);
         break;
       case cmTarget::SHARED_LIBRARY:
@@ -336,9 +338,6 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
       }
     }
 
-  // Compute which sources need unique object computation.
-  this->ComputeObjectNameRequirements(classes);
-  
   // Write the DSP file's header.
   this->WriteDSPHeader(fout, libName, target, sourceGroups);
   
@@ -358,6 +357,8 @@ void cmLocalVisualStudio6Generator
 ::WriteGroup(const cmSourceGroup *sg, cmTarget& target,
              std::ostream &fout, const char *libName)
 {
+  cmGeneratorTarget* gt =
+    this->GlobalGenerator->GetGeneratorTarget(&target);
   const std::vector<const cmSourceFile *> &sourceFiles = 
     sg->GetSourceFiles();
   // If the group is empty, don't write it at all.
@@ -374,28 +375,6 @@ void cmLocalVisualStudio6Generator
     this->WriteDSPBeginGroup(fout, name.c_str(), "");
     }
 
-  // Compute the maximum length configuration name.
-  std::string config_max;
-  for(std::vector<std::string>::iterator i = this->Configurations.begin();
-      i != this->Configurations.end(); ++i)
-    {
-    // Strip the subdirectory name out of the configuration name.
-    std::string config = this->GetConfigName(*i);
-    if(config.size() > config_max.size())
-      {
-      config_max = config;
-      }
-    }
-
-  // Compute the maximum length full path to the intermediate
-  // files directory for any configuration.  This is used to construct
-  // object file names that do not produce paths that are too long.
-  std::string dir_max;
-  dir_max += this->Makefile->GetCurrentOutputDirectory();
-  dir_max += "/";
-  dir_max += config_max;
-  dir_max += "/";
-
   // Loop through each source in the source group.
   for(std::vector<const cmSourceFile *>::const_iterator sf =
         sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
@@ -406,11 +385,9 @@ void cmLocalVisualStudio6Generator
     std::string compileFlags;
     std::vector<std::string> depends;
     std::string objectNameDir;
-    if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
+    if(gt->ExplicitObjectName.find(*sf) != gt->ExplicitObjectName.end())
       {
-      objectNameDir =
-        cmSystemTools::GetFilenamePath(
-          this->GetObjectFileNameWithoutTarget(*(*sf), dir_max));
+      objectNameDir = cmSystemTools::GetFilenamePath(gt->Objects[*sf]);
       }
 
     // Add per-source file flags.
@@ -1264,8 +1241,18 @@ void cmLocalVisualStudio6Generator
     outputNameMinSizeRel = target.GetFullName("MinSizeRel");
     outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo");
     }
+  else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    outputName = target.GetName();
+    outputName += ".lib";
+    outputNameDebug = outputName;
+    outputNameRelease = outputName;
+    outputNameMinSizeRel = outputName;
+    outputNameRelWithDebInfo = outputName;
+    }
 
   // Compute the output directory for the target.
+  std::string outputDirOld;
   std::string outputDirDebug;
   std::string outputDirRelease;
   std::string outputDirMinSizeRel;
@@ -1275,6 +1262,11 @@ void cmLocalVisualStudio6Generator
      target.GetType() == cmTarget::SHARED_LIBRARY ||
      target.GetType() == cmTarget::MODULE_LIBRARY)
     {
+#ifdef CM_USE_OLD_VS6
+    outputDirOld =
+      removeQuotes(this->ConvertToOptionallyRelativeOutputPath
+                   (target.GetDirectory().c_str()));
+#endif
     outputDirDebug =
         removeQuotes(this->ConvertToOptionallyRelativeOutputPath(
                        target.GetDirectory("Debug").c_str()));
@@ -1288,6 +1280,14 @@ void cmLocalVisualStudio6Generator
         removeQuotes(this->ConvertToOptionallyRelativeOutputPath(
                  target.GetDirectory("RelWithDebInfo").c_str()));
     }
+  else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    std::string outputDir = cmake::GetCMakeFilesDirectoryPostSlash();
+    outputDirDebug = outputDir + "Debug";
+    outputDirRelease = outputDir + "Release";
+    outputDirMinSizeRel = outputDir + "MinSizeRel";
+    outputDirRelWithDebInfo = outputDir + "RelWithDebInfo";
+    }
 
   // Compute the proper link information for the target.
   std::string optionsDebug;
@@ -1428,6 +1428,16 @@ void cmLocalVisualStudio6Generator
       staticLibOptionsRelWithDebInfo += " ";
       staticLibOptionsRelWithDebInfo = libflagsRelWithDebInfo;
       }
+    std::string objects;
+    this->OutputObjects(target, "LIB", objects);
+    if(!objects.empty())
+      {
+      objects = "\n" + objects;
+      staticLibOptionsDebug += objects;
+      staticLibOptionsRelease += objects;
+      staticLibOptionsMinSizeRel += objects;
+      staticLibOptionsRelWithDebInfo += objects;
+      }
     }
 
   // Add the export symbol definition for shared library objects.
@@ -1456,7 +1466,8 @@ void cmLocalVisualStudio6Generator
                                  libnameExports.c_str());
     cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
                                  mfcFlag);
-    if(target.GetType() == cmTarget::STATIC_LIBRARY )
+    if(target.GetType() == cmTarget::STATIC_LIBRARY ||
+       target.GetType() == cmTarget::OBJECT_LIBRARY)
       {
       cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_DEBUG",
                                    staticLibOptionsDebug.c_str());
@@ -1555,7 +1566,7 @@ void cmLocalVisualStudio6Generator
                     (exePath.c_str())).c_str());
 #endif
 
-    if(targetBuilds)
+    if(targetBuilds || target.GetType() == cmTarget::OBJECT_LIBRARY)
       {
       cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_DEBUG",
                                    outputDirDebug.c_str());
@@ -1565,13 +1576,11 @@ void cmLocalVisualStudio6Generator
                                    outputDirMinSizeRel.c_str());
       cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_RELWITHDEBINFO",
                                    outputDirRelWithDebInfo.c_str());
-#ifdef CM_USE_OLD_VS6
-      std::string outPath = target.GetDirectory();
-      cmSystemTools::ReplaceString
-        (line, "OUTPUT_DIRECTORY",
-         removeQuotes(this->ConvertToOptionallyRelativeOutputPath
-                      (outPath.c_str())).c_str());
-#endif
+      if(!outputDirOld.empty())
+        {
+        cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY",
+                                     outputDirOld.c_str());
+        }
       }
 
     cmSystemTools::ReplaceString(line, 
@@ -1588,7 +1597,7 @@ void cmLocalVisualStudio6Generator
     std::string flagsDebug = " ";
     std::string flagsDebugRel = " ";
     if(target.GetType() >= cmTarget::EXECUTABLE && 
-       target.GetType() <= cmTarget::MODULE_LIBRARY)
+       target.GetType() <= cmTarget::OBJECT_LIBRARY)
       {
       const char* linkLanguage = target.GetLinkerLanguage();
       if(!linkLanguage)
@@ -1743,6 +1752,8 @@ void cmLocalVisualStudio6Generator
   ItemVector const& linkLibs = cli.GetItems();
   std::vector<std::string> const& linkDirs = cli.GetDirectories();
 
+  this->OutputObjects(target, "LINK", options);
+
   // Build the link options code.
   for(std::vector<std::string>::const_iterator d = linkDirs.begin();
       d != linkDirs.end(); ++d)
@@ -1787,6 +1798,28 @@ void cmLocalVisualStudio6Generator
     }
 }
 
+//----------------------------------------------------------------------------
+void cmLocalVisualStudio6Generator
+::OutputObjects(cmTarget& target, const char* tool,
+                std::string& options)
+{
+  // VS 6 does not support per-config source locations so we
+  // list object library content on the link line instead.
+  cmGeneratorTarget* gt =
+    this->GlobalGenerator->GetGeneratorTarget(&target);
+  std::vector<std::string> objs;
+  gt->UseObjectLibraries(objs);
+  for(std::vector<std::string>::const_iterator
+        oi = objs.begin(); oi != objs.end(); ++oi)
+    {
+    options += "# ADD ";
+    options += tool;
+    options += "32 ";
+    options += this->ConvertToOptionallyRelativeOutputPath(oi->c_str());
+    options += "\n";
+    }
+}
+
 std::string
 cmLocalVisualStudio6Generator
 ::GetTargetDirectory(cmTarget const&) const
@@ -1795,6 +1828,36 @@ cmLocalVisualStudio6Generator
   return "";
 }
 
+//----------------------------------------------------------------------------
+std::string
+cmLocalVisualStudio6Generator
+::ComputeLongestObjectDirectory(cmTarget&) const
+{
+  // Compute the maximum length configuration name.
+  std::string config_max;
+  for(std::vector<std::string>::const_iterator
+        i = this->Configurations.begin();
+      i != this->Configurations.end(); ++i)
+    {
+    // Strip the subdirectory name out of the configuration name.
+    std::string config = this->GetConfigName(*i);
+    if(config.size() > config_max.size())
+      {
+      config_max = config;
+      }
+    }
+
+  // Compute the maximum length full path to the intermediate
+  // files directory for any configuration.  This is used to construct
+  // object file names that do not produce paths that are too long.
+  std::string dir_max;
+  dir_max += this->Makefile->GetCurrentOutputDirectory();
+  dir_max += "/";
+  dir_max += config_max;
+  dir_max += "/";
+  return dir_max;
+}
+
 std::string
 cmLocalVisualStudio6Generator
 ::GetConfigName(std::string const& configuration) const

+ 3 - 0
Source/cmLocalVisualStudio6Generator.h

@@ -50,6 +50,7 @@ public:
   void SetBuildType(BuildType, const char* libName, cmTarget&);
 
   virtual std::string GetTargetDirectory(cmTarget const& target) const;
+  virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
 private:
   std::string DSPHeaderTemplate;
   std::string DSPFooterTemplate;
@@ -86,6 +87,8 @@ private:
   void ComputeLinkOptions(cmTarget& target, const char* configName,
                           const std::string extraOptions,
                           std::string& options);
+  void OutputObjects(cmTarget& target, const char* tool,
+                     std::string& options);
   std::string GetTargetIncludeOptions(cmTarget &target);
   std::vector<std::string> Configurations;
 

+ 99 - 27
Source/cmLocalVisualStudio7Generator.cxx

@@ -17,6 +17,7 @@
 #include "cmSystemTools.h"
 #include "cmSourceFile.h"
 #include "cmCacheManager.h"
+#include "cmGeneratorTarget.h"
 #include "cmake.h"
 
 #include "cmComputeLinkInformation.h"
@@ -38,6 +39,7 @@ public:
     LocalGenerator(e) {}
   typedef cmComputeLinkInformation::ItemVector ItemVector;
   void OutputLibraries(std::ostream& fout, ItemVector const& libs);
+  void OutputObjects(std::ostream& fout, cmTarget* t, const char* isep = 0);
 private:
   cmLocalVisualStudio7Generator* LocalGenerator;
 };
@@ -641,6 +643,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
   bool targetBuilds = true;
   switch(target.GetType())
     {
+    case cmTarget::OBJECT_LIBRARY:
+      targetBuilds = false; // TODO: PDB for object library?
     case cmTarget::STATIC_LIBRARY:
       projectType = "typeStaticLibrary";
       configType = "4";
@@ -1000,6 +1004,22 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     }
   switch(target.GetType())
     {
+    case cmTarget::OBJECT_LIBRARY:
+      {
+      std::string libpath = this->GetTargetDirectory(target);
+      libpath += "/";
+      libpath += configName;
+      libpath += "/";
+      libpath += target.GetName();
+      libpath += ".lib";
+      const char* tool =
+        this->FortranProject? "VFLibrarianTool":"VCLibrarianTool";
+      fout << "\t\t\t<Tool\n"
+           << "\t\t\t\tName=\"" << tool << "\"\n";
+      fout << "\t\t\t\tOutputFile=\""
+           << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
+      break;
+      }
     case cmTarget::STATIC_LIBRARY:
     {
     std::string targetNameFull = target.GetFullName(configName);
@@ -1014,6 +1034,15 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     fout << "\t\t\t<Tool\n"
          << "\t\t\t\tName=\"" << tool << "\"\n";
 
+    if(this->GetVersion() < VS8)
+      {
+      cmOStringStream libdeps;
+      this->Internal->OutputObjects(libdeps, &target);
+      if(!libdeps.str().empty())
+        {
+        fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str() << "\"\n";
+        }
+      }
     std::string libflags;
     if(const char* flags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
       {
@@ -1074,8 +1103,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     // Use the NOINHERIT macro to avoid getting VS project default
     // libraries which may be set by the user to something bad.
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
-         << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
-         << " ";
+         << this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
+    if(this->GetVersion() < VS8)
+      {
+      this->Internal->OutputObjects(fout, &target, " ");
+      }
+    fout << " ";
     this->Internal->OutputLibraries(fout, cli.GetItems());
     fout << "\"\n";
     temp = target.GetDirectory(configName);
@@ -1155,8 +1188,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     // Use the NOINHERIT macro to avoid getting VS project default
     // libraries which may be set by the user to something bad.
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
-         << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
-         << " ";
+         << this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
+    if(this->GetVersion() < VS8)
+      {
+      this->Internal->OutputObjects(fout, &target, " ");
+      }
+    fout << " ";
     this->Internal->OutputLibraries(fout, cli.GetItems());
     fout << "\"\n";
     temp = target.GetDirectory(configName);
@@ -1242,6 +1279,30 @@ cmLocalVisualStudio7GeneratorInternals
     }
 }
 
+//----------------------------------------------------------------------------
+void
+cmLocalVisualStudio7GeneratorInternals
+::OutputObjects(std::ostream& fout, cmTarget* t, const char* isep)
+{
+  // VS < 8 does not support per-config source locations so we
+  // list object library content on the link line instead.
+  cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+  cmGeneratorTarget* gt =
+    lg->GetGlobalGenerator()->GetGeneratorTarget(t);
+  std::vector<std::string> objs;
+  gt->UseObjectLibraries(objs);
+  const char* sep = isep? isep : "";
+  for(std::vector<std::string>::const_iterator
+        oi = objs.begin(); oi != objs.end(); ++oi)
+    {
+    std::string rel = lg->Convert(oi->c_str(),
+                                  cmLocalGenerator::START_OUTPUT,
+                                  cmLocalGenerator::UNCHANGED);
+    fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
+    sep = " ";
+    }
+}
+
 //----------------------------------------------------------------------------
 void
 cmLocalVisualStudio7Generator
@@ -1310,9 +1371,6 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
     sourceGroup.AssignSource(*i);
     }
 
-  // Compute which sources need unique object computation.
-  this->ComputeObjectNameRequirements(classes);
-
   // open the project
   this->WriteProjectStart(fout, libName, target, sourceGroups);
   // write the configuration information
@@ -1328,7 +1386,27 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
     this->WriteGroup(&sg, target, fout, libName, configs);
     }
 
-  //}
+  if(this->GetVersion() >= VS8)
+    {
+    // VS >= 8 support per-config source locations so we
+    // list object library content as external objects.
+    cmGeneratorTarget* gt =
+      this->GlobalGenerator->GetGeneratorTarget(&target);
+    std::vector<std::string> objs;
+    gt->UseObjectLibraries(objs);
+    if(!objs.empty())
+      {
+      // TODO: Separate sub-filter for each object library used?
+      fout << "\t\t<Filter Name=\"Object Libraries\">\n";
+      for(std::vector<std::string>::const_iterator
+            oi = objs.begin(); oi != objs.end(); ++oi)
+        {
+        std::string o = this->ConvertToXMLOutputPathSingle(oi->c_str());
+        fout << "\t\t\t<File RelativePath=\"" << o << "\" />\n";
+        }
+      fout << "\t\t</Filter>\n";
+      }
+    }
 
   fout << "\t</Files>\n";
 
@@ -1352,8 +1430,7 @@ public:
   cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
                                       cmTarget& target,
                                       cmSourceFile const& sf,
-                                      std::vector<std::string>* configs,
-                                      std::string const& dir_max);
+                                      std::vector<std::string>* configs);
   std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap;
 };
 
@@ -1361,13 +1438,14 @@ cmLocalVisualStudio7GeneratorFCInfo
 ::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
                                       cmTarget& target,
                                       cmSourceFile const& sf,
-                                      std::vector<std::string>* configs,
-                                      std::string const& dir_max)
+                                      std::vector<std::string>* configs)
 {
+  cmGeneratorTarget* gt =
+    lg->GetGlobalGenerator()->GetGeneratorTarget(&target);
   std::string objectName;
-  if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end())
+  if(gt->ExplicitObjectName.find(&sf) != gt->ExplicitObjectName.end())
     {
-    objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max);
+    objectName = gt->Objects[&sf];
     }
 
   // Compute per-source, per-config information.
@@ -1478,11 +1556,11 @@ cmLocalVisualStudio7GeneratorFCInfo
     }
 }
 
-
-void cmLocalVisualStudio7Generator
-::ComputeMaxDirectoryLength(std::string& maxdir,
-  cmTarget& target)
-{  
+//----------------------------------------------------------------------------
+std::string
+cmLocalVisualStudio7Generator
+::ComputeLongestObjectDirectory(cmTarget& target) const
+{
   std::vector<std::string> *configs =
     static_cast<cmGlobalVisualStudio7Generator *>
     (this->GlobalGenerator)->GetConfigurations();
@@ -1507,7 +1585,7 @@ void cmLocalVisualStudio7Generator
   dir_max += "/";
   dir_max += config_max;
   dir_max += "/";
-  maxdir = dir_max;
+  return dir_max;
 }
 
 void cmLocalVisualStudio7Generator
@@ -1530,19 +1608,13 @@ void cmLocalVisualStudio7Generator
     this->WriteVCProjBeginGroup(fout, name.c_str(), "");
     }
 
-  // Compute the maximum length full path to the intermediate
-  // files directory for any configuration.  This is used to construct
-  // object file names that do not produce paths that are too long.
-  std::string dir_max;
-  this->ComputeMaxDirectoryLength(dir_max, target);
-
   // Loop through each source in the source group.
   std::string objectName;
   for(std::vector<const cmSourceFile *>::const_iterator sf =
         sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
     {
     std::string source = (*sf)->GetFullPath();
-    FCInfo fcinfo(this, target, *(*sf), configs, dir_max);
+    FCInfo fcinfo(this, target, *(*sf), configs);
 
     if (source != libName || target.GetType() == cmTarget::UTILITY ||
       target.GetType() == cmTarget::GLOBAL_TARGET )

+ 1 - 5
Source/cmLocalVisualStudio7Generator.h

@@ -60,11 +60,7 @@ public:
   virtual std::string GetTargetDirectory(cmTarget const&) const;
   cmSourceFile* CreateVCProjBuildRule();
   void WriteStampFiles();
-  // Compute the maximum length full path to the intermediate
-  // files directory for any configuration.  This is used to construct
-  // object file names that do not produce paths that are too long.
-  void ComputeMaxDirectoryLength(std::string& maxdir,
-                                 cmTarget& target);
+  virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
 
   virtual void ReadAndStoreExternalGUID(const char* name,
                                         const char* path);

+ 0 - 63
Source/cmLocalVisualStudioGenerator.cxx

@@ -64,69 +64,6 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
   return pcc;
 }
 
-//----------------------------------------------------------------------------
-bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
-{
-  // Identify the language of the source file.
-  if(const char* lang = this->GetSourceFileLanguage(*sf))
-    {
-    // Check whether this source will actually be compiled.
-    return (!sf->GetCustomCommand() &&
-            !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
-            !sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
-    }
-  else
-    {
-    // Unknown source file language.  Assume it will not be compiled.
-    return false;
-    }
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalVisualStudioGenerator::ComputeObjectNameRequirements(
-  std::vector<cmSourceFile*> const& sources
-  )
-{
-  // Clear the current set of requirements.
-  this->NeedObjectName.clear();
-
-  // Count the number of object files with each name.  Note that
-  // windows file names are not case sensitive.
-  std::map<cmStdString, int> counts;
-  for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
-      s != sources.end(); ++s)
-    {
-    const cmSourceFile* sf = *s;
-    if(this->SourceFileCompiles(sf))
-      {
-      std::string objectName = cmSystemTools::LowerCase(
-        cmSystemTools::GetFilenameWithoutLastExtension(
-          sf->GetFullPath()));
-      objectName += ".obj";
-      counts[objectName] += 1;
-      }
-    }
-
-  // For all source files producing duplicate names we need unique
-  // object name computation.
-  for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
-      s != sources.end(); ++s)
-    {
-    const cmSourceFile* sf = *s;
-    if(this->SourceFileCompiles(sf))
-      {
-      std::string objectName = cmSystemTools::LowerCase(
-         cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
-      objectName += ".obj";
-      if(counts[objectName] > 1)
-        {
-        this->NeedObjectName.insert(sf);
-        }
-      }
-    }
-}
-
 //----------------------------------------------------------------------------
 const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
 {

+ 2 - 6
Source/cmLocalVisualStudioGenerator.h

@@ -56,6 +56,8 @@ public:
   /** Version of Visual Studio.  */
   VSVersion GetVersion() const { return this->Version; }
 
+  virtual std::string ComputeLongestObjectDirectory(cmTarget&) const = 0;
+
 protected:
   virtual const char* ReportErrorLabel() const;
   virtual bool CustomCommandUseLocal() const { return false; }
@@ -64,12 +66,6 @@ protected:
   cmsys::auto_ptr<cmCustomCommand>
   MaybeCreateImplibDir(cmTarget& target, const char* config, bool isFortran);
 
-  // Safe object file name generation.
-  void ComputeObjectNameRequirements(std::vector<cmSourceFile*> const&);
-  bool SourceFileCompiles(const cmSourceFile* sf);
-  std::set<const cmSourceFile*> NeedObjectName;
-  friend class cmVisualStudio10TargetGenerator;
-
   VSVersion Version;
 };
 

+ 15 - 3
Source/cmMakefile.cxx

@@ -782,6 +782,7 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg)
                        "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$");
   this->AddSourceGroup("CMake Rules", "\\.rule$");
   this->AddSourceGroup("Resources", "\\.plist$");
+  this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
 #endif
 
   this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
@@ -853,6 +854,14 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
   cmTargets::iterator ti = this->Targets.find(target);
   if(ti != this->Targets.end())
     {
+    if(ti->second.GetType() == cmTarget::OBJECT_LIBRARY)
+      {
+      cmOStringStream e;
+      e << "Target \"" << target << "\" is an OBJECT library "
+        "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
+      this->IssueMessage(cmake::FATAL_ERROR, e.str());
+      return;
+      }
     // Add the command to the appropriate build step for the target.
     std::vector<std::string> no_output;
     cmCustomCommand cc(this, no_output, depends,
@@ -945,7 +954,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
     outName += ".rule";
     const char* dir =
       this->LocalGenerator->GetGlobalGenerator()->
-      GetCMakeCFGInitDirectory();
+      GetCMakeCFGIntDir();
     if(dir && dir[0] == '$')
       {
       cmSystemTools::ReplaceString(outName, dir,
@@ -1912,8 +1921,11 @@ cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
   // wrong type ? default to STATIC
   if (    (type != cmTarget::STATIC_LIBRARY)
        && (type != cmTarget::SHARED_LIBRARY)
-       && (type != cmTarget::MODULE_LIBRARY))
+       && (type != cmTarget::MODULE_LIBRARY)
+       && (type != cmTarget::OBJECT_LIBRARY))
     {
+    this->IssueMessage(cmake::INTERNAL_ERROR,
+                       "cmMakefile::AddLibrary given invalid target type.");
     type = cmTarget::STATIC_LIBRARY;
     }
 
@@ -2865,7 +2877,7 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const &  lang,
 {
   this->AddDefinition("CMAKE_CFG_INTDIR",
                       this->LocalGenerator->GetGlobalGenerator()
-                      ->GetCMakeCFGInitDirectory());
+                      ->GetCMakeCFGIntDir());
   this->LocalGenerator->GetGlobalGenerator()->EnableLanguage(lang, this,
                                                              optional);
 }

+ 26 - 0
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -101,6 +101,9 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
         this->WriteModuleLibraryRules(true);
         }
       break;
+    case cmTarget::OBJECT_LIBRARY:
+      this->WriteObjectLibraryRules();
+      break;
     default:
       // If language is not known, this is an error.
       cmSystemTools::Error("Unknown Library Type");
@@ -121,6 +124,29 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
   this->CloseFileStreams();
 }
 
+//----------------------------------------------------------------------------
+void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
+{
+  std::vector<std::string> commands;
+  std::vector<std::string> depends;
+
+  // Add post-build rules.
+  this->LocalGenerator->
+    AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
+                         this->Target);
+
+  // Depend on the object files.
+  this->AppendObjectDepends(depends);
+
+  // Write the rule.
+  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
+                                      this->Target->GetName(),
+                                      depends, commands, true);
+
+  // Write the main driver rule to build everything in this target.
+  this->WriteTargetDriverRule(this->Target->GetName(), false);
+}
+
 //----------------------------------------------------------------------------
 void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
 {

+ 1 - 0
Source/cmMakefileLibraryTargetGenerator.h

@@ -25,6 +25,7 @@ public:
   virtual void WriteRuleFiles();  
   
 protected:
+  void WriteObjectLibraryRules();
   void WriteStaticLibraryRules();
   void WriteSharedLibraryRules(bool relink);
   void WriteModuleLibraryRules(bool relink);

+ 66 - 71
Source/cmMakefileTargetGenerator.cxx

@@ -11,6 +11,7 @@
 ============================================================================*/
 #include "cmMakefileTargetGenerator.h"
 
+#include "cmGeneratorTarget.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
@@ -42,6 +43,7 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target)
   this->GlobalGenerator =
     static_cast<cmGlobalUnixMakefileGenerator3*>(
       this->LocalGenerator->GetGlobalGenerator());
+  this->GeneratorTarget = this->GlobalGenerator->GetGeneratorTarget(target);
   cmake* cm = this->GlobalGenerator->GetCMakeInstance();
   this->NoRuleMessages = false;
   if(const char* ruleStatus = cm->GetProperty("RULE_MESSAGES"))
@@ -63,6 +65,7 @@ cmMakefileTargetGenerator::New(cmTarget *tgt)
     case cmTarget::STATIC_LIBRARY:
     case cmTarget::SHARED_LIBRARY:
     case cmTarget::MODULE_LIBRARY:
+    case cmTarget::OBJECT_LIBRARY:
       result = new cmMakefileLibraryTargetGenerator(tgt);
       break;
     case cmTarget::UTILITY:
@@ -131,58 +134,49 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
 
   // First generate the object rule files.  Save a list of all object
   // files for this target.
-  const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles();
-  for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
-      source != sources.end(); ++source)
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->CustomCommands.begin();
+      si != this->GeneratorTarget->CustomCommands.end(); ++si)
     {
-    cmTarget::SourceFileFlags tsFlags =
-      this->Target->GetTargetSourceFileFlags(*source);
-    if(cmCustomCommand* cc = (*source)->GetCustomCommand())
+    cmCustomCommand const* cc = (*si)->GetCustomCommand();
+    this->GenerateCustomRuleFile(*cc);
+    if (clean)
       {
-      this->GenerateCustomRuleFile(*cc);
-      if (clean)
-        {
-        const std::vector<std::string>& outputs = cc->GetOutputs();
-        for(std::vector<std::string>::const_iterator o = outputs.begin();
-            o != outputs.end(); ++o)
-          {
-          this->CleanFiles.push_back
-            (this->Convert(o->c_str(),
-                           cmLocalGenerator::START_OUTPUT,
-                           cmLocalGenerator::UNCHANGED));
-          }
-        }
-      }
-    else if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
-      {
-      this->WriteMacOSXContentRules(*(*source), tsFlags.MacFolder);
-      }
-    else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
-      {
-      if(!this->GlobalGenerator->IgnoreFile
-         ((*source)->GetExtension().c_str()))
-        {
-        // Generate this object file's rule file.
-        this->WriteObjectRuleFiles(*(*source));
-        }
-      else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
-        {
-        // This is an external object file.  Just add it.
-        this->ExternalObjects.push_back((*source)->GetFullPath());
-        }
-      else if(cmSystemTools::UpperCase((*source)->GetExtension()) == "DEF")
-        {
-        this->ModuleDefinitionFile = (*source)->GetFullPath();
-        }
-      else
+      const std::vector<std::string>& outputs = cc->GetOutputs();
+      for(std::vector<std::string>::const_iterator o = outputs.begin();
+          o != outputs.end(); ++o)
         {
-        // We only get here if a source file is not an external object
-        // and has an extension that is listed as an ignored file type
-        // for this language.  No message or diagnosis should be
-        // given.
+        this->CleanFiles.push_back
+          (this->Convert(o->c_str(),
+                         cmLocalGenerator::START_OUTPUT,
+                         cmLocalGenerator::UNCHANGED));
         }
       }
     }
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->OSXContent.begin();
+      si != this->GeneratorTarget->OSXContent.end(); ++si)
+    {
+    cmTarget::SourceFileFlags tsFlags =
+      this->Target->GetTargetSourceFileFlags(*si);
+    this->WriteMacOSXContentRules(**si, tsFlags.MacFolder);
+    }
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->ExternalObjects.begin();
+      si != this->GeneratorTarget->ExternalObjects.end(); ++si)
+    {
+    this->ExternalObjects.push_back((*si)->GetFullPath());
+    }
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->ObjectSources.begin();
+      si != this->GeneratorTarget->ObjectSources.end(); ++si)
+    {
+    // Generate this object file's rule file.
+    this->WriteObjectRuleFiles(**si);
+    }
+
+  // Add object library contents as external objects.
+  this->GeneratorTarget->UseObjectLibraries(this->ExternalObjects);
 }
 
 
@@ -428,12 +422,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
     }
 
   // Get the full path name of the object file.
-  bool hasSourceExtension;
-  std::string objNoTargetDir;
-  std::string obj =
-    this->LocalGenerator->GetObjectFileName(*this->Target, source,
-                                            &objNoTargetDir,
-                                            &hasSourceExtension);
+  std::string const& objectName = this->GeneratorTarget->Objects[&source];
+  std::string obj = this->LocalGenerator->GetTargetDirectory(*this->Target);
+  obj += "/";
+  obj += objectName;
 
   // Avoid generating duplicate rules.
   if(this->ObjectFiles.find(obj) == this->ObjectFiles.end())
@@ -487,10 +479,6 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
     AddImplicitDepends(*this->Target, lang,
                        objFullPath.c_str(),
                        srcFullPath.c_str());
-
-  // add this to the list of objects for this local generator
-  this->LocalGenerator->AddLocalObjectFile(
-    this->Target, &source, objNoTargetDir, hasSourceExtension);
 }
 
 //----------------------------------------------------------------------------
@@ -1612,7 +1600,7 @@ void cmMakefileTargetGenerator
 
 //----------------------------------------------------------------------------
 void cmMakefileTargetGenerator
-::AppendLinkDepends(std::vector<std::string>& depends)
+::AppendObjectDepends(std::vector<std::string>& depends)
 {
   // Add dependencies on the compiled object files.
   std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
@@ -1625,25 +1613,32 @@ void cmMakefileTargetGenerator
     depends.push_back(objTarget);
     }
 
-  // Add dependencies on targets that must be built first.
-  this->AppendTargetDepends(depends);
+  // Add dependencies on the external object files.
+  for(std::vector<std::string>::const_iterator obj
+        = this->ExternalObjects.begin();
+      obj != this->ExternalObjects.end(); ++obj)
+    {
+    depends.push_back(*obj);
+    }
 
   // Add a dependency on the rule file itself.
   this->LocalGenerator->AppendRuleDepend(depends,
                                          this->BuildFileNameFull.c_str());
+}
 
-  // Add a dependency on the link definitions file, if any.
-  if(!this->ModuleDefinitionFile.empty())
-    {
-    depends.push_back(this->ModuleDefinitionFile);
-    }
+//----------------------------------------------------------------------------
+void cmMakefileTargetGenerator
+::AppendLinkDepends(std::vector<std::string>& depends)
+{
+  this->AppendObjectDepends(depends);
 
-  // Add dependencies on the external object files.
-  for(std::vector<std::string>::const_iterator obj
-        = this->ExternalObjects.begin();
-      obj != this->ExternalObjects.end(); ++obj)
+  // Add dependencies on targets that must be built first.
+  this->AppendTargetDepends(depends);
+
+  // Add a dependency on the link definitions file, if any.
+  if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
     {
-    depends.push_back(*obj);
+    depends.push_back(this->GeneratorTarget->ModuleDefinitionFile);
     }
 
   // Add user-specified dependencies.
@@ -1971,7 +1966,7 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags)
 //----------------------------------------------------------------------------
 void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
 {
-  if(this->ModuleDefinitionFile.empty())
+  if(this->GeneratorTarget->ModuleDefinitionFile.empty())
     {
     return;
     }
@@ -1988,7 +1983,7 @@ void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
   // vs6's "cl -link" pass it to the linker.
   std::string flag = defFileFlag;
   flag += (this->LocalGenerator->ConvertToLinkReference(
-             this->ModuleDefinitionFile.c_str()));
+             this->GeneratorTarget->ModuleDefinitionFile.c_str()));
   this->LocalGenerator->AppendFlags(flags, flag.c_str());
 }
 

+ 5 - 3
Source/cmMakefileTargetGenerator.h

@@ -17,6 +17,7 @@
 class cmCustomCommand;
 class cmDependInformation;
 class cmDepends;
+class cmGeneratorTarget;
 class cmGeneratedFileStream;
 class cmGlobalUnixMakefileGenerator3;
 class cmLocalUnixMakefileGenerator3;
@@ -117,6 +118,9 @@ protected:
   // append intertarget dependencies
   void AppendTargetDepends(std::vector<std::string>& depends);
 
+  // Append object file dependencies.
+  void AppendObjectDepends(std::vector<std::string>& depends);
+
   // Append link rule dependencies (objects, etc.).
   void AppendLinkDepends(std::vector<std::string>& depends);
 
@@ -157,6 +161,7 @@ protected:
   void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
                             std::string& linkFlags);
   cmTarget *Target;
+  cmGeneratorTarget* GeneratorTarget;
   cmLocalUnixMakefileGenerator3 *LocalGenerator;
   cmGlobalUnixMakefileGenerator3 *GlobalGenerator;
   cmMakefile *Makefile;
@@ -198,9 +203,6 @@ protected:
   std::vector<std::string> Objects;
   std::vector<std::string> ExternalObjects;
 
-  // The windows module definition source file (.def), if any.
-  std::string ModuleDefinitionFile;
-
   // Set of object file names that will be built in this directory.
   std::set<cmStdString> ObjectFiles;
 

+ 34 - 6
Source/cmNinjaNormalTargetGenerator.cxx

@@ -43,10 +43,13 @@ cmNinjaNormalTargetGenerator(cmTarget* target)
                             this->TargetNamePDB,
                             GetLocalGenerator()->GetConfigName());
 
-  // on Windows the output dir is already needed at compile time
-  // ensure the directory exists (OutDir test)
-  std::string outpath = target->GetDirectory(this->GetConfigName());
-  cmSystemTools::MakeDirectory(outpath.c_str());
+  if(target->GetType() != cmTarget::OBJECT_LIBRARY)
+    {
+    // on Windows the output dir is already needed at compile time
+    // ensure the directory exists (OutDir test)
+    std::string outpath = target->GetDirectory(this->GetConfigName());
+    cmSystemTools::MakeDirectory(outpath.c_str());
+    }
 }
 
 cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
@@ -67,8 +70,15 @@ void cmNinjaNormalTargetGenerator::Generate()
   // Write the build statements
   this->WriteObjectBuildStatements();
 
-  this->WriteLinkRule();
-  this->WriteLinkStatement();
+  if(this->GetTarget()->GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    this->WriteObjectLibStatement();
+    }
+  else
+    {
+    this->WriteLinkRule();
+    this->WriteLinkStatement();
+    }
 
   this->GetBuildFileStream() << "\n";
   this->GetRulesFileStream() << "\n";
@@ -467,3 +477,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
   this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
                                              this->GetTarget());
 }
+
+//----------------------------------------------------------------------------
+void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
+{
+  // Write a phony output that depends on all object files.
+  cmNinjaDeps outputs;
+  this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
+  cmNinjaDeps depends = this->GetObjects();
+  cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
+                                          "Object library "
+                                          + this->GetTargetName(),
+                                          outputs,
+                                          depends);
+
+  // Add aliases for the target name.
+  this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+                                             this->GetTarget());
+}

+ 1 - 0
Source/cmNinjaNormalTargetGenerator.h

@@ -32,6 +32,7 @@ private:
   void WriteLanguagesRules();
   void WriteLinkRule();
   void WriteLinkStatement();
+  void WriteObjectLibStatement();
   std::vector<std::string> ComputeLinkCmd();
 
 private:

+ 54 - 42
Source/cmNinjaTargetGenerator.cxx

@@ -14,6 +14,7 @@
 #include "cmGlobalNinjaGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
 #include "cmNinjaNormalTargetGenerator.h"
 #include "cmNinjaUtilityTargetGenerator.h"
 #include "cmSystemTools.h"
@@ -33,6 +34,7 @@ cmNinjaTargetGenerator::New(cmTarget* target)
       case cmTarget::SHARED_LIBRARY:
       case cmTarget::STATIC_LIBRARY:
       case cmTarget::MODULE_LIBRARY:
+      case cmTarget::OBJECT_LIBRARY:
         return new cmNinjaNormalTargetGenerator(target);
 
       case cmTarget::UTILITY:
@@ -60,6 +62,8 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target)
       static_cast<cmLocalNinjaGenerator*>(Makefile->GetLocalGenerator())),
     Objects()
 {
+  this->GeneratorTarget =
+    this->GetGlobalGenerator()->GetGeneratorTarget(target);
 }
 
 cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
@@ -218,7 +222,8 @@ ComputeDefines(cmSourceFile *source, const std::string& language)
 cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
 {
   // Static libraries never depend on other targets for linking.
-  if (this->Target->GetType() == cmTarget::STATIC_LIBRARY)
+  if (this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
+      this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
     return cmNinjaDeps();
 
   cmComputeLinkInformation* cli =
@@ -231,9 +236,9 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
   std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
 
   // Add a dependency on the link definitions file, if any.
-  if(!this->ModuleDefinitionFile.empty())
+  if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
     {
-    result.push_back(this->ModuleDefinitionFile);
+    result.push_back(this->GeneratorTarget->ModuleDefinitionFile);
     }
 
   return result;
@@ -253,7 +258,10 @@ cmNinjaTargetGenerator
   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
   if(!path.empty())
     path += "/";
-  path += this->LocalGenerator->GetObjectFileName(*this->Target, *source);
+  std::string const& objectName = this->GeneratorTarget->Objects[source];
+  path += this->LocalGenerator->GetTargetDirectory(*this->Target);
+  path += "/";
+  path += objectName;
   return path;
 }
 
@@ -377,12 +385,37 @@ cmNinjaTargetGenerator
     << this->GetTargetName()
     << "\n\n";
 
-  // For each source files of this target.
-  for(std::vector<cmSourceFile*>::const_iterator i =
-        this->GetTarget()->GetSourceFiles().begin();
-      i != this->GetTarget()->GetSourceFiles().end();
-      ++i)
-    this->WriteObjectBuildStatement(*i);
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->CustomCommands.begin();
+      si != this->GeneratorTarget->CustomCommands.end(); ++si)
+     {
+     cmCustomCommand const* cc = (*si)->GetCustomCommand();
+     this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
+     }
+  // TODO: this->GeneratorTarget->OSXContent
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->ExternalObjects.begin();
+      si != this->GeneratorTarget->ExternalObjects.end(); ++si)
+    {
+    this->Objects.push_back(this->GetSourceFilePath(*si));
+    }
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->ObjectSources.begin();
+      si != this->GeneratorTarget->ObjectSources.end(); ++si)
+    {
+    this->WriteObjectBuildStatement(*si);
+    }
+
+  {
+  // 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";
 }
@@ -391,26 +424,10 @@ void
 cmNinjaTargetGenerator
 ::WriteObjectBuildStatement(cmSourceFile* source)
 {
-  if (cmCustomCommand *cc = source->GetCustomCommand())
-    this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
-
   cmNinjaDeps emptyDeps;
 
   std::string comment;
   const char* language = source->GetLanguage();
-  // If we cannot get the language this is probably a non-source file provided
-  // in the list (typically an header file).
-  if (!language) {
-    if (source->GetPropertyAsBool("EXTERNAL_OBJECT"))
-      this->Objects.push_back(this->GetSourceFilePath(source));
-    if(cmSystemTools::UpperCase(source->GetExtension()) == "DEF")
-      this->ModuleDefinitionFile = GetSourceFilePath(source);
-    return;
-  }
-
-  if (source->GetPropertyAsBool("HEADER_FILE_ONLY"))
-    return;
-
   std::string rule = this->LanguageCompilerRule(language);
 
   cmNinjaDeps outputs;
@@ -435,21 +452,16 @@ cmNinjaTargetGenerator
                    std::back_inserter(orderOnlyDeps), MapToNinjaPath());
   }
 
-  // Add order-only dependency on any header file with a custom command.
-  {
-    const std::vector<cmSourceFile*>& sources =
-      this->GetTarget()->GetSourceFiles();
-    for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
-        si != sources.end(); ++si) {
-      if (!(*si)->GetLanguage()) {
-        if (cmCustomCommand* cc = (*si)->GetCustomCommand()) {
-          const std::vector<std::string>& ccoutputs = cc->GetOutputs();
-          std::transform(ccoutputs.begin(), ccoutputs.end(),
-                         std::back_inserter(orderOnlyDeps), MapToNinjaPath());
-        }
-      }
+  // Add order-only dependencies on custom command outputs.
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->CustomCommands.begin();
+      si != this->GeneratorTarget->CustomCommands.end(); ++si)
+    {
+    cmCustomCommand const* cc = (*si)->GetCustomCommand();
+    const std::vector<std::string>& ccoutputs = cc->GetOutputs();
+    std::transform(ccoutputs.begin(), ccoutputs.end(),
+                   std::back_inserter(orderOnlyDeps), MapToNinjaPath());
     }
-  }
 
   // If the source file is GENERATED and does not have a custom command
   // (either attached to this source file or another one), assume that one of
@@ -493,7 +505,7 @@ void
 cmNinjaTargetGenerator
 ::AddModuleDefinitionFlag(std::string& flags)
 {
-  if(this->ModuleDefinitionFile.empty())
+  if(this->GeneratorTarget->ModuleDefinitionFile.empty())
     {
     return;
     }
@@ -510,6 +522,6 @@ cmNinjaTargetGenerator
   // vs6's "cl -link" pass it to the linker.
   std::string flag = defFileFlag;
   flag += (this->LocalGenerator->ConvertToLinkReference(
-             this->ModuleDefinitionFile.c_str()));
+             this->GeneratorTarget->ModuleDefinitionFile.c_str()));
   this->LocalGenerator->AppendFlags(flags, flag.c_str());
 }

+ 2 - 3
Source/cmNinjaTargetGenerator.h

@@ -20,6 +20,7 @@
 class cmTarget;
 class cmGlobalNinjaGenerator;
 class cmGeneratedFileStream;
+class cmGeneratorTarget;
 class cmMakefile;
 class cmSourceFile;
 class cmCustomCommand;
@@ -112,13 +113,11 @@ protected:
 
 private:
   cmTarget* Target;
+  cmGeneratorTarget* GeneratorTarget;
   cmMakefile* Makefile;
   cmLocalNinjaGenerator* LocalGenerator;
   /// List of object files for this target.
   cmNinjaDeps Objects;
-
-  // The windows module definition source file (.def), if any.
-  std::string ModuleDefinitionFile;
 };
 
 #endif // ! cmNinjaTargetGenerator_h

+ 0 - 6
Source/cmSourceGroup.cxx

@@ -119,12 +119,6 @@ const std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles() const
   return this->SourceFiles;
 }
 
-//----------------------------------------------------------------------------
-std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles()
-{
-  return this->SourceFiles;
-}
-
 //----------------------------------------------------------------------------
 void cmSourceGroup::AddChild(cmSourceGroup child)
 {

+ 0 - 1
Source/cmSourceGroup.h

@@ -100,7 +100,6 @@ public:
    * source group.
    */
   const std::vector<const cmSourceFile*>& GetSourceFiles() const;
-  std::vector<const cmSourceFile*>& GetSourceFiles();
   
   std::vector<cmSourceGroup> const& GetGroupChildren() const;
 private:

+ 43 - 1
Source/cmTarget.cxx

@@ -37,6 +37,8 @@ const char* cmTarget::GetTargetTypeName(TargetType targetType)
         return "MODULE_LIBRARY";
       case cmTarget::SHARED_LIBRARY:
         return "SHARED_LIBRARY";
+      case cmTarget::OBJECT_LIBRARY:
+        return "OBJECT_LIBRARY";
       case cmTarget::EXECUTABLE:
         return "EXECUTABLE";
       case cmTarget::UTILITY:
@@ -1727,7 +1729,15 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
   for(std::vector<std::string>::const_iterator i = srcs.begin();
       i != srcs.end(); ++i)
     {
-    this->AddSource(i->c_str());
+    const char* src = i->c_str();
+    if(src[0] == '$' && src[1] == '<')
+      {
+      this->ProcessSourceExpression(*i);
+      }
+    else
+      {
+      this->AddSource(src);
+      }
     }
 }
 
@@ -1745,6 +1755,24 @@ cmSourceFile* cmTarget::AddSource(const char* s)
   return sf;
 }
 
+//----------------------------------------------------------------------------
+void cmTarget::ProcessSourceExpression(std::string const& expr)
+{
+  if(strncmp(expr.c_str(), "$<TARGET_OBJECTS:", 17) == 0 &&
+     expr[expr.size()-1] == '>')
+    {
+    std::string objLibName = expr.substr(17, expr.size()-18);
+    this->ObjectLibraries.push_back(objLibName);
+    }
+  else
+    {
+    cmOStringStream e;
+    e << "Unrecognized generator expression:\n"
+      << "  " << expr;
+    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+    }
+}
+
 //----------------------------------------------------------------------------
 struct cmTarget::SourceFileFlags
 cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf)
@@ -4545,7 +4573,21 @@ void cmTarget::ComputeLinkImplementation(const char* config,
 
   // This target needs runtime libraries for its source languages.
   std::set<cmStdString> languages;
+  // Get languages used in our source files.
   this->GetLanguages(languages);
+  // Get languages used in object library sources.
+  for(std::vector<std::string>::iterator i = this->ObjectLibraries.begin();
+      i != this->ObjectLibraries.end(); ++i)
+    {
+    if(cmTarget* objLib = this->Makefile->FindTargetToUse(i->c_str()))
+      {
+      if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
+        {
+        objLib->GetLanguages(languages);
+        }
+      }
+    }
+  // Copy the set of langauges to the link implementation.
   for(std::set<cmStdString>::iterator li = languages.begin();
       li != languages.end(); ++li)
     {

+ 9 - 1
Source/cmTarget.h

@@ -59,7 +59,8 @@ class cmTarget
 public:
   cmTarget();
   enum TargetType { EXECUTABLE, STATIC_LIBRARY,
-                    SHARED_LIBRARY, MODULE_LIBRARY, UTILITY, GLOBAL_TARGET,
+                    SHARED_LIBRARY, MODULE_LIBRARY,
+                    OBJECT_LIBRARY, UTILITY, GLOBAL_TARGET,
                     UNKNOWN_LIBRARY};
   static const char* GetTargetTypeName(TargetType targetType);
   enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD };
@@ -116,6 +117,10 @@ public:
    */
   std::vector<cmSourceFile*> const& GetSourceFiles();
   void AddSourceFile(cmSourceFile* sf);
+  std::vector<std::string> const& GetObjectLibraries() const
+    {
+    return this->ObjectLibraries;
+    }
 
   /** Get sources that must be built before the given source.  */
   std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf);
@@ -548,6 +553,7 @@ private:
   std::vector<cmCustomCommand> PostBuildCommands;
   TargetType TargetTypeValue;
   std::vector<cmSourceFile*> SourceFiles;
+  std::vector<std::string> ObjectLibraries;
   LinkLibraryVectorType LinkLibraries;
   LinkLibraryVectorType PrevLinkedLibraries;
   bool LinkLibrariesAnalyzed;
@@ -589,6 +595,8 @@ private:
 
   void MaybeInvalidatePropertyCache(const char* prop);
 
+  void ProcessSourceExpression(std::string const& expr);
+
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;

+ 10 - 0
Source/cmTargetLinkLibrariesCommand.cxx

@@ -84,6 +84,16 @@ bool cmTargetLinkLibrariesCommand
     return true;
     }
 
+  if(this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
+    {
+    cmOStringStream e;
+    e << "Object library target \"" << args[0] << "\" "
+      << "may not link to anything.";
+    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return true;
+    }
+
   // but we might not have any libs after variable expansion
   if(args.size() < 2)
     {

+ 79 - 45
Source/cmVisualStudio10TargetGenerator.cxx

@@ -11,6 +11,7 @@
 ============================================================================*/
 #include "cmVisualStudio10TargetGenerator.h"
 #include "cmGlobalVisualStudio10Generator.h"
+#include "cmGeneratorTarget.h"
 #include "cmTarget.h"
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
@@ -62,6 +63,7 @@ cmVisualStudio10TargetGenerator(cmTarget* target,
 {
   this->GlobalGenerator = gg;
   this->Target = target;
+  this->GeneratorTarget = gg->GetGeneratorTarget(target);
   this->Makefile = target->GetMakefile();
   this->LocalGenerator =  
     (cmLocalVisualStudio7Generator*)
@@ -70,7 +72,6 @@ cmVisualStudio10TargetGenerator(cmTarget* target,
   this->GlobalGenerator->CreateGUID(this->Name.c_str());
   this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str());
   this->Platform = gg->GetPlatformName();
-  this->ComputeObjectNames();
   this->BuildFileStream = 0;
 }
 
@@ -147,7 +148,7 @@ void cmVisualStudio10TargetGenerator::Generate()
   this->Target->SetProperty("GENERATOR_FILE_NAME",this->Name.c_str());
   this->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
                             ".vcxproj");
-  if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
+  if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
     {
     if(!this->ComputeClOptions())
       {
@@ -358,6 +359,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
       case cmTarget::MODULE_LIBRARY:
         configType += "DynamicLibrary";
         break;
+      case cmTarget::OBJECT_LIBRARY:
       case cmTarget::STATIC_LIBRARY:
         configType += "StaticLibrary";
         break;
@@ -388,7 +390,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
     mfcLine += useOfMfcValue + "</UseOfMfc>\n";
     this->WriteString(mfcLine.c_str(), 2);
 
-    if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY &&
+    if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY &&
        this->ClOptions[*i]->UsingUnicode() ||
        this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS"))
       {
@@ -421,12 +423,11 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
 void cmVisualStudio10TargetGenerator::WriteCustomCommands()
 {
   this->SourcesVisited.clear();
-  std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
-  for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
-      source != sources.end(); ++source)
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = this->GeneratorTarget->CustomCommands.begin();
+      si != this->GeneratorTarget->CustomCommands.end(); ++si)
     {
-    cmSourceFile* sf = *source;
-    this->WriteCustomCommand(sf);
+    this->WriteCustomCommand(*si);
     }
 }
 
@@ -634,6 +635,25 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
   this->WriteGroupSources("Midl", idls, sourceGroups);
   this->WriteGroupSources("CustomBuild", customBuild, sourceGroups);
 
+  // Add object library contents as external objects.
+  std::vector<std::string> objs;
+  this->GeneratorTarget->UseObjectLibraries(objs);
+  if(!objs.empty())
+    {
+    this->WriteString("<ItemGroup>\n", 1);
+    for(std::vector<std::string>::const_iterator
+          oi = objs.begin(); oi != objs.end(); ++oi)
+      {
+      std::string obj = *oi;
+      this->WriteString("<Object Include=\"", 2);
+      this->ConvertToWindowsSlash(obj);
+      (*this->BuildFileStream ) << obj << "\">\n";
+      this->WriteString("<Filter>Object Libraries</Filter>\n", 3);
+      this->WriteString("</Object>\n", 2);
+      }
+    this->WriteString("</ItemGroup>\n", 1);
+    }
+
   this->WriteString("<ItemGroup>\n", 1);
   for(std::set<cmSourceGroup*>::iterator g = groupsUsed.begin();
       g != groupsUsed.end(); ++g)
@@ -657,6 +677,18 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
       this->WriteString("</Filter>\n", 2);
       }
     }
+  if(!objs.empty())
+    {
+    this->WriteString("<Filter Include=\"Object Libraries\">\n", 2);
+    std::string guidName = "SG_Filter_Object Libraries";
+    this->GlobalGenerator->CreateGUID(guidName.c_str());
+    this->WriteString("<UniqueIdentifier>", 3);
+    std::string guid =
+      this->GlobalGenerator->GetGUID(guidName.c_str());
+    (*this->BuildFileStream) << "{" << guid << "}"
+                             << "</UniqueIdentifier>\n";
+    this->WriteString("</Filter>\n", 2);
+    }
   this->WriteString("</ItemGroup>\n", 1);
   this->WriteGroupSources("None", none, sourceGroups);
   this->WriteString("</Project>\n", 0);
@@ -872,26 +904,20 @@ void cmVisualStudio10TargetGenerator::WriteCLSources()
       (*this->BuildFileStream ) << " />\n";
       }
     }
-  this->WriteString("</ItemGroup>\n", 1);
-}
 
-void cmVisualStudio10TargetGenerator::ComputeObjectNames()
-{
-  // get the classes from the source lists then add them to the groups
-  std::vector<cmSourceFile*>const & classes = this->Target->GetSourceFiles();
-  for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
-      i != classes.end(); i++)
-    {
-    // Add the file to the list of sources.
-    std::string source = (*i)->GetFullPath();
-    if(cmSystemTools::UpperCase((*i)->GetExtension()) == "DEF")
-      {
-      this->ModuleDefinitionFile = (*i)->GetFullPath();
-      }
+  // Add object library contents as external objects.
+  std::vector<std::string> objs;
+  this->GeneratorTarget->UseObjectLibraries(objs);
+  for(std::vector<std::string>::const_iterator
+        oi = objs.begin(); oi != objs.end(); ++oi)
+    {
+    std::string obj = *oi;
+    this->WriteString("<Object Include=\"", 2);
+    this->ConvertToWindowsSlash(obj);
+    (*this->BuildFileStream ) << obj << "\" />\n";
     }
 
-  // Compute which sources need unique object computation.
-  this->LocalGenerator->ComputeObjectNameRequirements(classes);
+  this->WriteString("</ItemGroup>\n", 1);
 }
 
 bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
@@ -900,16 +926,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   cmSourceFile& sf = *source;
   cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
 
-  // Compute the maximum length full path to the intermediate
-  // files directory for any configuration.  This is used to construct
-  // object file names that do not produce paths that are too long.
-  std::string dir_max;
-  lg->ComputeMaxDirectoryLength(dir_max, *this->Target);
-
   std::string objectName;
-  if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end())
+  if(this->GeneratorTarget->ExplicitObjectName.find(&sf)
+     != this->GeneratorTarget->ExplicitObjectName.end())
     {
-    objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max);
+    objectName = this->GeneratorTarget->Objects[&sf];
     }
   std::string flags;
   std::string defines;
@@ -1030,20 +1051,29 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
       }
     else
       {
-      std::string targetNameFull =
-        this->Target->GetFullName(config->c_str());
       std::string intermediateDir = this->LocalGenerator->
         GetTargetDirectory(*this->Target);
       intermediateDir += "/";
       intermediateDir += *config;
       intermediateDir += "/";
+      std::string outDir;
+      std::string targetNameFull;
+      if(ttype == cmTarget::OBJECT_LIBRARY)
+        {
+        outDir = intermediateDir;
+        targetNameFull = this->Target->GetName();
+        targetNameFull += ".lib";
+        }
+      else
+        {
+        outDir = this->Target->GetDirectory(config->c_str()) + "/";
+        targetNameFull = this->Target->GetFullName(config->c_str());
+        }
       this->ConvertToWindowsSlash(intermediateDir);
-      std::string outDir = this->Target->GetDirectory(config->c_str());
       this->ConvertToWindowsSlash(outDir);
 
       this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
       *this->BuildFileStream << outDir
-                             << "\\"
                              << "</OutDir>\n";
 
       this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
@@ -1277,11 +1307,15 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
   *this->BuildFileStream << configName 
                          << "</AssemblerListingLocation>\n";
   this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
-  this->WriteString("<ProgramDataBaseFileName>", 3);
-  *this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
-                         << "/" 
-                         << this->Target->GetPDBName(configName.c_str())
-                         << "</ProgramDataBaseFileName>\n";
+  if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY)
+    {
+    // TODO: PDB for object library?
+    this->WriteString("<ProgramDataBaseFileName>", 3);
+    *this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
+                           << "/"
+                           << this->Target->GetPDBName(configName.c_str())
+                           << "</ProgramDataBaseFileName>\n";
+    }
   this->WriteString("</ClCompile>\n", 2);
 }
 
@@ -1513,10 +1547,10 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
   linkOptions.AddFlag("ImportLibrary", imLib.c_str());
   linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str());
   linkOptions.Parse(flags.c_str());
-  if(!this->ModuleDefinitionFile.empty())
+  if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
     {
     linkOptions.AddFlag("ModuleDefinitionFile",
-                        this->ModuleDefinitionFile.c_str());
+                        this->GeneratorTarget->ModuleDefinitionFile.c_str());
     }
 
   linkOptions.RemoveFlag("GenerateManifest");
@@ -1592,7 +1626,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
     this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
     *this->BuildFileStream << "\n";
     //    output cl compile flags <ClCompile></ClCompile>
-    if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
+    if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
       {
       this->WriteClOptions(*i, includes);
       //    output rc compile flags <ResourceCompile></ResourceCompile>

+ 2 - 2
Source/cmVisualStudio10TargetGenerator.h

@@ -15,6 +15,7 @@
 
 class cmTarget;
 class cmMakefile;
+class cmGeneratorTarget;
 class cmGeneratedFileStream;
 class cmGlobalVisualStudio10Generator;
 class cmSourceFile;
@@ -75,7 +76,6 @@ private:
   void WriteEvents(std::string const& configName);
   void WriteEvent(const char* name, std::vector<cmCustomCommand> & commands,
                   std::string const& configName);
-  void ComputeObjectNames();
   void WriteGroupSources(const char* name,
                          std::vector<cmSourceFile*> const& sources,
                          std::vector<cmSourceGroup>& );
@@ -87,9 +87,9 @@ private:
   typedef cmVisualStudioGeneratorOptions Options;
   typedef std::map<cmStdString, Options*> OptionsMap;
   OptionsMap ClOptions;
-  std::string ModuleDefinitionFile;
   std::string PathToVcxproj;
   cmTarget* Target;
+  cmGeneratorTarget* GeneratorTarget;
   cmMakefile* Makefile;
   std::string Platform;
   std::string GUID;

+ 1 - 0
Tests/CMakeLists.txt

@@ -199,6 +199,7 @@ IF(BUILD_TESTING)
   ADD_TEST_MACRO(CxxOnly CxxOnly)
   ADD_TEST_MACRO(IPO COnly/COnly)
   ADD_TEST_MACRO(OutDir runtime/OutDir)
+  ADD_TEST_MACRO(ObjectLibrary UseCshared)
   ADD_TEST_MACRO(NewlineArgs NewlineArgs)
   ADD_TEST_MACRO(SetLang SetLang)
   ADD_TEST_MACRO(ExternalOBJ ExternalOBJ)

+ 17 - 0
Tests/ObjectLibrary/A/CMakeLists.txt

@@ -0,0 +1,17 @@
+# Add -fPIC so objects can be used in shared libraries.
+# TODO: Need property for this.
+if(CMAKE_SHARED_LIBRARY_C_FLAGS)
+  set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
+endif()
+
+add_definitions(-DA)
+
+add_custom_command(
+  OUTPUT a1.c
+  DEPENDS a1.c.in
+  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
+                                   ${CMAKE_CURRENT_BINARY_DIR}/a1.c
+  )
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+add_library(A OBJECT a1.c a2.c)

+ 6 - 0
Tests/ObjectLibrary/A/a.h

@@ -0,0 +1,6 @@
+#ifndef A
+# error "A not defined"
+#endif
+#ifdef B
+# error "B must not be defined"
+#endif

+ 2 - 0
Tests/ObjectLibrary/A/a1.c.in

@@ -0,0 +1,2 @@
+#include "a.h"
+int a1(void) { return 0; }

+ 2 - 0
Tests/ObjectLibrary/A/a2.c

@@ -0,0 +1,2 @@
+#include "a.h"
+int a2(void) { return 0; }

+ 5 - 0
Tests/ObjectLibrary/AB.def

@@ -0,0 +1,5 @@
+EXPORTS
+a1
+a2
+b1
+b2

+ 15 - 0
Tests/ObjectLibrary/B/CMakeLists.txt

@@ -0,0 +1,15 @@
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
+  # VS 6 generator does not use per-target object locations.
+  set(vs6 _vs6)
+endif()
+
+# Add -fPIC so objects can be used in shared libraries.
+# TODO: Need property for this.
+if(CMAKE_SHARED_LIBRARY_C_FLAGS)
+  set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
+endif()
+
+add_definitions(-DB)
+add_library(B OBJECT b1.c b2.c)
+add_library(Bexport OBJECT b1${vs6}.c b2${vs6}.c)
+set_property(TARGET Bexport PROPERTY COMPILE_DEFINITIONS Bexport)

+ 11 - 0
Tests/ObjectLibrary/B/b.h

@@ -0,0 +1,11 @@
+#ifdef A
+# error "A must not be defined"
+#endif
+#ifndef B
+# error "B not defined"
+#endif
+#if defined(_WIN32) && defined(Bexport)
+# define EXPORT_B __declspec(dllexport)
+#else
+# define EXPORT_B
+#endif

+ 2 - 0
Tests/ObjectLibrary/B/b1.c

@@ -0,0 +1,2 @@
+#include "b.h"
+EXPORT_B int b1(void) { return 0; }

+ 1 - 0
Tests/ObjectLibrary/B/b1_vs6.c

@@ -0,0 +1 @@
+#include "b1.c"

+ 2 - 0
Tests/ObjectLibrary/B/b2.c

@@ -0,0 +1,2 @@
+#include "b.h"
+EXPORT_B int b2(void) { return 0; }

+ 1 - 0
Tests/ObjectLibrary/B/b2_vs6.c

@@ -0,0 +1 @@
+#include "b2.c"

+ 52 - 0
Tests/ObjectLibrary/CMakeLists.txt

@@ -0,0 +1,52 @@
+cmake_minimum_required(VERSION 2.8)
+project(ObjectLibrary C)
+
+add_subdirectory(A)
+add_subdirectory(B)
+
+add_library(Cstatic STATIC c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+add_executable(UseCstatic main.c)
+target_link_libraries(UseCstatic Cstatic)
+
+add_library(Cshared SHARED c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
+add_executable(UseCshared main.c)
+set_property(TARGET UseCshared PROPERTY COMPILE_DEFINITIONS SHARED_C)
+target_link_libraries(UseCshared Cshared)
+
+add_executable(UseCinternal main.c c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+
+if("${CMAKE_GENERATOR}" MATCHES "^Visual Studio (6|7|7 .NET 2003)$")
+  # VS 6 and 7 generators do not add objects as sources so we need a
+  # dummy object to convince the IDE to build the targets below.
+  set(dummy dummy.obj) # In MinGW: gcc -c dummy.c -o dummy.obj
+elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
+  # Xcode does not seem to support targets without sources.
+  set(dummy dummy.c)
+endif()
+
+# Test static library without its own sources.
+add_library(ABstatic STATIC ${dummy} $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
+add_executable(UseABstatic mainAB.c)
+target_link_libraries(UseABstatic ABstatic)
+
+# Test module definition file to export object library symbols in the test
+# below if the platform needs and supports it.
+set(ABshared_SRCS $<TARGET_OBJECTS:A>)
+if(CMAKE_LINK_DEF_FILE_FLAG OR NOT WIN32)
+  list(APPEND ABshared_SRCS $<TARGET_OBJECTS:B> AB.def)
+else()
+  set(NO_A NO_A)
+  list(APPEND ABshared_SRCS $<TARGET_OBJECTS:Bexport>)
+endif()
+
+# Test shared library without its own sources.
+add_library(ABshared SHARED ${dummy} ${ABshared_SRCS})
+add_executable(UseABshared mainAB.c)
+set_property(TARGET UseABshared PROPERTY COMPILE_DEFINITIONS SHARED_B ${NO_A})
+target_link_libraries(UseABshared ABshared)
+
+# Test executable without its own sources.
+add_library(ABmain OBJECT mainAB.c)
+add_executable(UseABinternal ${dummy}
+  $<TARGET_OBJECTS:ABmain> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>
+  )

+ 19 - 0
Tests/ObjectLibrary/c.c

@@ -0,0 +1,19 @@
+#if defined(_WIN32) && defined(Cshared_EXPORTS)
+# define EXPORT_C __declspec(dllexport)
+#else
+# define EXPORT_C
+#endif
+
+extern int a1(void);
+extern int a2(void);
+extern int b1(void);
+extern int b2(void);
+EXPORT_C int c(void)
+{
+  return 0
+    + a1()
+    + a2()
+    + b1()
+    + b2()
+    ;
+}

+ 1 - 0
Tests/ObjectLibrary/dummy.c

@@ -0,0 +1 @@
+int dummy(void) {return 0;}

BIN
Tests/ObjectLibrary/dummy.obj


+ 16 - 0
Tests/ObjectLibrary/main.c

@@ -0,0 +1,16 @@
+#if defined(_WIN32) && defined(SHARED_C)
+# define IMPORT_C __declspec(dllimport)
+#else
+# define IMPORT_C
+#endif
+extern IMPORT_C int b1(void);
+extern IMPORT_C int b2(void);
+extern IMPORT_C int c(void);
+int main(void)
+{
+  return 0
+    + c()
+    + b1()
+    + b2()
+    ;
+}

+ 22 - 0
Tests/ObjectLibrary/mainAB.c

@@ -0,0 +1,22 @@
+#if defined(_WIN32) && defined(SHARED_B)
+# define IMPORT_B __declspec(dllimport)
+#else
+# define IMPORT_B
+#endif
+extern IMPORT_B int b1(void);
+extern IMPORT_B int b2(void);
+#ifndef NO_A
+extern int a1(void);
+extern int a2(void);
+#endif
+int main(void)
+{
+  return 0
+#ifndef NO_A
+    + a1()
+    + a2()
+#endif
+    + b1()
+    + b2()
+    ;
+}

+ 2 - 0
Tests/RunCMake/CMakeLists.txt

@@ -40,5 +40,7 @@ macro(add_RunCMake_test test)
     )
 endmacro()
 
+add_RunCMake_test(ObjectLibrary)
+
 add_RunCMake_test(build_command)
 add_RunCMake_test(find_package)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource1-result.txt

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

+ 8 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource1-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at BadObjSource1.cmake:1 \(add_library\):
+  OBJECT library "A" contains:
+
+    bad.def
+
+  but may contain only headers and sources that compile.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource1.cmake

@@ -0,0 +1 @@
+add_library(A OBJECT a.c bad.def)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource2-result.txt

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

+ 8 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at BadObjSource2.cmake:1 \(add_library\):
+  OBJECT library "A" contains:
+
+    bad.obj
+
+  but may contain only headers and sources that compile.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadObjSource2.cmake

@@ -0,0 +1 @@
+add_library(A OBJECT a.c bad.obj)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression1-result.txt

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

+ 6 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression1-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error at BadSourceExpression1.cmake:1 \(add_library\):
+  Unrecognized generator expression:
+
+    \$<BAD_EXPRESSION>
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression1.cmake

@@ -0,0 +1 @@
+add_library(A STATIC a.c $<BAD_EXPRESSION>)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression2-result.txt

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

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

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

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression2.cmake

@@ -0,0 +1 @@
+add_library(A STATIC a.c $<TARGET_OBJECTS:DoesNotExist>)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression3-result.txt

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

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

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

+ 2 - 0
Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake

@@ -0,0 +1,2 @@
+add_library(NotObjLib STATIC a.c)
+add_library(A STATIC a.c $<TARGET_OBJECTS:NotObjLib>)

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

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

+ 1 - 0
Tests/RunCMake/ObjectLibrary/Export-result.txt

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

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

@@ -0,0 +1,4 @@
+CMake Error at Export.cmake:2 \(export\):
+  export given OBJECT library "A" which may not be exported.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 2 - 0
Tests/RunCMake/ObjectLibrary/Export.cmake

@@ -0,0 +1,2 @@
+add_library(A OBJECT a.c)
+export(TARGETS A FILE AExport.cmake)

+ 15 - 0
Tests/RunCMake/ObjectLibrary/ExportLanguages.cmake

@@ -0,0 +1,15 @@
+enable_language(CXX)
+add_library(A OBJECT a.cxx)
+add_library(B STATIC a.c $<TARGET_OBJECTS:A>)
+
+# Verify that object library languages are propagated.
+export(TARGETS B NAMESPACE Exp FILE BExport.cmake)
+include(${CMAKE_CURRENT_BINARY_DIR}/BExport.cmake)
+get_property(configs TARGET ExpB PROPERTY IMPORTED_CONFIGURATIONS)
+foreach(c ${configs})
+  get_property(langs TARGET ExpB PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES_${c})
+  list(FIND langs CXX pos)
+  if(${pos} LESS 0)
+    message(FATAL_ERROR "Target export does not list object library languages.")
+  endif()
+endforeach()

+ 1 - 0
Tests/RunCMake/ObjectLibrary/Import-result.txt

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

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

@@ -0,0 +1,4 @@
+CMake Error at Import.cmake:1 \(add_library\):
+  The OBJECT library type may not be used for IMPORTED libraries.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/Import.cmake

@@ -0,0 +1 @@
+add_library(A OBJECT IMPORTED)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/Install-result.txt

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

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

@@ -0,0 +1,4 @@
+CMake Error at Install.cmake:2 \(install\):
+  install TARGETS given OBJECT library "A" which may not be installed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 2 - 0
Tests/RunCMake/ObjectLibrary/Install.cmake

@@ -0,0 +1,2 @@
+add_library(A OBJECT a.c)
+install(TARGETS A DESTINATION lib)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/LinkObjLHS-result.txt

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

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

@@ -0,0 +1,4 @@
+CMake Error at LinkObjLHS.cmake:2 \(target_link_libraries\):
+  Object library target "AnObjLib" may not link to anything.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 2 - 0
Tests/RunCMake/ObjectLibrary/LinkObjLHS.cmake

@@ -0,0 +1,2 @@
+add_library(AnObjLib OBJECT a.c)
+target_link_libraries(AnObjLib OtherLib)

+ 1 - 0
Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt

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

+ 6 - 0
Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error at LinkObjRHS1.cmake:3 \(target_link_libraries\):
+  Target "AnObjLib" of type OBJECT_LIBRARY may not be linked into another
+  target.  One may link only to STATIC or SHARED libraries, or to executables
+  with the ENABLE_EXPORTS property set.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 3 - 0
Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake

@@ -0,0 +1,3 @@
+add_library(A STATIC a.c)
+add_library(AnObjLib OBJECT a.c)
+target_link_libraries(A AnObjLib)

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است