Bladeren bron

Add $<TARGET_OBJECTS:...> expression to use an object library

For now do not allow an OBJECT library to reference other object
libraries.  Teach cmTarget::ComputeLinkImplementation to include the
languages of object libraries used by a target.
Brad King 13 jaren geleden
bovenliggende
commit
c403f27a2d

+ 74 - 0
Source/cmGeneratorTarget.cxx

@@ -24,6 +24,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
   this->LocalGenerator = this->Makefile->GetLocalGenerator();
   this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
   this->ClassifySources();
+  this->LookupObjectLibraries();
 }
 
 //----------------------------------------------------------------------------
@@ -93,3 +94,76 @@ void cmGeneratorTarget::ClassifySources()
                      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);
+      }
+    }
+}

+ 5 - 0
Source/cmGeneratorTarget.h

@@ -48,8 +48,13 @@ public:
       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&);

+ 35 - 1
Source/cmLocalVisualStudio6Generator.cxx

@@ -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.
@@ -1587,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)
@@ -1742,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)
@@ -1786,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

+ 2 - 0
Source/cmLocalVisualStudio6Generator.h

@@ -87,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;
 

+ 67 - 5
Source/cmLocalVisualStudio7Generator.cxx

@@ -39,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;
 };
@@ -1033,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"))
       {
@@ -1093,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);
@@ -1174,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);
@@ -1261,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
@@ -1344,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";
 

+ 3 - 0
Source/cmMakefileTargetGenerator.cxx

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

+ 41 - 1
Source/cmTarget.cxx

@@ -1724,7 +1724,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);
+      }
     }
 }
 
@@ -1742,6 +1750,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)
@@ -4542,7 +4568,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)
     {

+ 7 - 0
Source/cmTarget.h

@@ -117,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);
@@ -549,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;
@@ -590,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;

+ 44 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -635,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)
@@ -658,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);
@@ -873,6 +904,19 @@ void cmVisualStudio10TargetGenerator::WriteCLSources()
       (*this->BuildFileStream ) << " />\n";
       }
     }
+
+  // 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";
+    }
+
   this->WriteString("</ItemGroup>\n", 1);
 }