Pārlūkot izejas kodu

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 gadi atpakaļ
vecāks
revīzija
31c0bc0219
100 mainītis faili ar 1633 papildinājumiem un 477 dzēšanām
  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)

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels