diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b5fcae267..4529d1c2f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/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(); } //---------------------------------------------------------------------------- @@ -96,3 +97,76 @@ void cmGeneratorTarget::ClassifySources() this->Target->GetBacktrace()); } } + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::LookupObjectLibraries() +{ + std::vector const& objLibs = + this->Target->GetObjectLibraries(); + for(std::vector::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& objs) +{ + for(std::vector::const_iterator + ti = this->ObjectLibraries.begin(); + ti != this->ObjectLibraries.end(); ++ti) + { + cmTarget* objLib = *ti; + cmGeneratorTarget* ogt = + this->GlobalGenerator->GetGeneratorTarget(objLib); + for(std::vector::const_iterator + si = ogt->ObjectSources.begin(); + si != ogt->ObjectSources.end(); ++si) + { + std::string obj = ogt->ObjectDirectory; + obj += ogt->Objects[*si]; + objs.push_back(obj); + } + } +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index b083ba1af..6319d823e 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -48,8 +48,13 @@ public: time config name placeholder if needed for the generator. */ std::string ObjectDirectory; + std::vector ObjectLibraries; + + void UseObjectLibraries(std::vector& objs); + private: void ClassifySources(); + void LookupObjectLibraries(); cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index f53ad0e3b..5b99dfd88 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/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 const& linkDirs = cli.GetDirectories(); + this->OutputObjects(target, "LINK", options); + // Build the link options code. for(std::vector::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 objs; + gt->UseObjectLibraries(objs); + for(std::vector::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 diff --git a/Source/cmLocalVisualStudio6Generator.h b/Source/cmLocalVisualStudio6Generator.h index d36d63358..a680633c3 100644 --- a/Source/cmLocalVisualStudio6Generator.h +++ b/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 Configurations; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 2f145a6bc..363d3702b 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/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\tGetVersion() < 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 objs; + gt->UseObjectLibraries(objs); + const char* sep = isep? isep : ""; + for(std::vector::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 objs; + gt->UseObjectLibraries(objs); + if(!objs.empty()) + { + // TODO: Separate sub-filter for each object library used? + fout << "\t\t\n"; + for(std::vector::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + std::string o = this->ConvertToXMLOutputPathSingle(oi->c_str()); + fout << "\t\t\t\n"; + } + fout << "\t\t\n"; + } + } fout << "\t\n"; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index d0cfd99c1..a0e04813d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/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); } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 9e8668109..708a98909 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1724,7 +1724,15 @@ void cmTarget::AddSources(std::vector const& srcs) for(std::vector::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(), "$') + { + 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 languages; + // Get languages used in our source files. this->GetLanguages(languages); + // Get languages used in object library sources. + for(std::vector::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::iterator li = languages.begin(); li != languages.end(); ++li) { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index e2502f06c..d41c827a8 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -117,6 +117,10 @@ public: */ std::vector const& GetSourceFiles(); void AddSourceFile(cmSourceFile* sf); + std::vector const& GetObjectLibraries() const + { + return this->ObjectLibraries; + } /** Get sources that must be built before the given source. */ std::vector const* GetSourceDepends(cmSourceFile* sf); @@ -549,6 +553,7 @@ private: std::vector PostBuildCommands; TargetType TargetTypeValue; std::vector SourceFiles; + std::vector 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; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index db37dfcf6..054b86b26 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/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 objs; + this->GeneratorTarget->UseObjectLibraries(objs); + if(!objs.empty()) + { + this->WriteString("\n", 1); + for(std::vector::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + std::string obj = *oi; + this->WriteString("ConvertToWindowsSlash(obj); + (*this->BuildFileStream ) << obj << "\">\n"; + this->WriteString("Object Libraries\n", 3); + this->WriteString("\n", 2); + } + this->WriteString("\n", 1); + } + this->WriteString("\n", 1); for(std::set::iterator g = groupsUsed.begin(); g != groupsUsed.end(); ++g) @@ -658,6 +677,18 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("\n", 2); } } + if(!objs.empty()) + { + this->WriteString("\n", 2); + std::string guidName = "SG_Filter_Object Libraries"; + this->GlobalGenerator->CreateGUID(guidName.c_str()); + this->WriteString("", 3); + std::string guid = + this->GlobalGenerator->GetGUID(guidName.c_str()); + (*this->BuildFileStream) << "{" << guid << "}" + << "\n"; + this->WriteString("\n", 2); + } this->WriteString("\n", 1); this->WriteGroupSources("None", none, sourceGroups); this->WriteString("\n", 0); @@ -873,6 +904,19 @@ void cmVisualStudio10TargetGenerator::WriteCLSources() (*this->BuildFileStream ) << " />\n"; } } + + // Add object library contents as external objects. + std::vector objs; + this->GeneratorTarget->UseObjectLibraries(objs); + for(std::vector::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + std::string obj = *oi; + this->WriteString("ConvertToWindowsSlash(obj); + (*this->BuildFileStream ) << obj << "\" />\n"; + } + this->WriteString("\n", 1); }