diff options
author | Brad King <brad.king@kitware.com> | 2017-04-19 14:47:28 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2017-04-19 14:47:31 (GMT) |
commit | 44f0d2d9913595e214048b6d5a2b9ab2e9d1cf46 (patch) | |
tree | c95b4621b9a71adc962c9c2e3e3140a0fb73e627 /Source | |
parent | 9db9bb27ea3f3dd3db3913c2bc2233f03018d5b0 (diff) | |
parent | eec93bceec5411e4409b5e3ee5dc301fca6fcbfd (diff) | |
download | CMake-44f0d2d9913595e214048b6d5a2b9ab2e9d1cf46.zip CMake-44f0d2d9913595e214048b6d5a2b9ab2e9d1cf46.tar.gz CMake-44f0d2d9913595e214048b6d5a2b9ab2e9d1cf46.tar.bz2 |
Merge topic 'objlib-extend'
eec93bce Allow OBJECT libraries to be installed, exported, and imported
93c89bc7 Genex: Allow TARGET_OBJECTS to be used everywhere
ac0cf7ff Genex: Reject TARGET_OBJECTS on non-object libraries earlier
8577978c Tests: ExportImport C code should use explicit (void) in prototypes
26cfd039 cmInstallTargetGenerator: Re-order GenerateScriptForConfig logic
25f3f22a cmGlobalGenerator: Add method to check if object file location is known
d596c550 cmGeneratorTarget: Add method to get the object file directory
930042f2 cmGeneratorTarget: Factor out a GetTargetObjectNames method
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !712
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmAddLibraryCommand.cxx | 13 | ||||
-rw-r--r-- | Source/cmExportBuildFileGenerator.cxx | 60 | ||||
-rw-r--r-- | Source/cmExportCommand.cxx | 14 | ||||
-rw-r--r-- | Source/cmExportFileGenerator.cxx | 8 | ||||
-rw-r--r-- | Source/cmExportInstallFileGenerator.cxx | 19 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluationFile.cxx | 6 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionNode.cxx | 86 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 40 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 11 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 5 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 12 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.h | 2 | ||||
-rw-r--r-- | Source/cmInstallCommand.cxx | 50 | ||||
-rw-r--r-- | Source/cmInstallTargetGenerator.cxx | 88 | ||||
-rw-r--r-- | Source/cmInstallTargetGenerator.h | 6 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 30 | ||||
-rw-r--r-- | Source/cmTargetExport.h | 1 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 3 |
18 files changed, 346 insertions, 108 deletions
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 9ae4ace..0bdf963 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -297,10 +297,15 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, return false; } if (type == cmStateEnums::OBJECT_LIBRARY) { - this->Makefile->IssueMessage( - cmake::FATAL_ERROR, - "The OBJECT library type may not be used for IMPORTED libraries."); - return true; + std::string reason; + if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation( + &reason)) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "The OBJECT library type may not be used for IMPORTED libraries" + + reason + "."); + return true; + } } if (type == cmStateEnums::INTERFACE_LIBRARY) { if (!cmGeneratorExpression::IsValidTargetName(libName)) { diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 539d854..978a7a1 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportBuildFileGenerator.h" +#include "cmAlgorithms.h" #include "cmExportSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -21,6 +22,8 @@ #include <sstream> #include <utility> +class cmSourceFile; + cmExportBuildFileGenerator::cmExportBuildFileGenerator() { this->LG = CM_NULLPTR; @@ -171,27 +174,48 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( // Get the makefile in which to lookup target information. cmMakefile* mf = target->Makefile; - // Add the main target file. - { - std::string prop = "IMPORTED_LOCATION"; + if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + std::string prop = "IMPORTED_OBJECTS"; prop += suffix; - std::string value; - if (target->IsAppBundleOnApple()) { - value = target->GetFullPath(config, false); - } else { - value = target->GetFullPath(config, false, true); + + // Compute all the object files inside this target and setup + // IMPORTED_OBJECTS as a list of object files + std::vector<cmSourceFile const*> objectSources; + target->GetObjectSources(objectSources, config); + std::string const obj_dir = target->GetObjectDirectory(config); + std::vector<std::string> objects; + for (std::vector<cmSourceFile const*>::const_iterator si = + objectSources.begin(); + si != objectSources.end(); ++si) { + const std::string& obj = target->GetObjectName(*si); + objects.push_back(obj_dir + obj); } - properties[prop] = value; - } - // Add the import library for windows DLLs. - if (target->HasImportLibrary() && - mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { - std::string prop = "IMPORTED_IMPLIB"; - prop += suffix; - std::string value = target->GetFullPath(config, true); - target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); - properties[prop] = value; + // Store the property. + properties[prop] = cmJoin(objects, ";"); + } else { + // Add the main target file. + { + std::string prop = "IMPORTED_LOCATION"; + prop += suffix; + std::string value; + if (target->IsAppBundleOnApple()) { + value = target->GetFullPath(config, false); + } else { + value = target->GetFullPath(config, false, true); + } + properties[prop] = value; + } + + // Add the import library for windows DLLs. + if (target->HasImportLibrary() && + mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { + std::string prop = "IMPORTED_IMPLIB"; + prop += suffix; + std::string value = target->GetFullPath(config, true); + target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); + properties[prop] = value; + } } } diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 691048b..38cd511 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -149,11 +149,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, if (cmTarget* target = gg->FindTarget(*currentTarget)) { if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "given OBJECT library \"" << *currentTarget - << "\" which may not be exported."; - this->SetError(e.str()); - return false; + std::string reason; + if (!this->Makefile->GetGlobalGenerator() + ->HasKnownObjectFileLocation(&reason)) { + std::ostringstream e; + e << "given OBJECT library \"" << *currentTarget + << "\" which may not be exported" << reason << "."; + this->SetError(e.str()); + return false; + } } if (target->GetType() == cmStateEnums::UTILITY) { this->SetError("given custom target \"" + *currentTarget + diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 5875f9e..ae3ec3b 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -441,6 +441,11 @@ void getCompatibleInterfaceProperties(cmGeneratorTarget* target, std::set<std::string>& ifaceProperties, const std::string& config) { + if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + // object libraries have no link information, so nothing to compute + return; + } + cmComputeLinkInformation* info = target->GetLinkInformation(config); if (!info) { @@ -927,6 +932,9 @@ void cmExportFileGenerator::GenerateImportTargetCode( case cmStateEnums::UNKNOWN_LIBRARY: os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; break; + case cmStateEnums::OBJECT_LIBRARY: + os << "add_library(" << targetName << " OBJECT IMPORTED)\n"; + break; case cmStateEnums::INTERFACE_LIBRARY: os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; break; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 3b76a87..16bd5e8 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -331,6 +331,8 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig( properties, importedLocations); this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator, properties, importedLocations); + this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator, + properties, importedLocations); this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator, properties, importedLocations); this->SetImportLocationProperty(config, suffix, te->BundleGenerator, @@ -397,6 +399,23 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( // Store the property. properties[prop] = value; importedLocations.insert(prop); + } else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) { + // Construct the property name. + std::string prop = "IMPORTED_OBJECTS"; + prop += suffix; + + // Compute all the object files inside this target and setup + // IMPORTED_OBJECTS as a list of object files + std::vector<std::string> objects; + itgen->GetInstallObjectNames(config, objects); + for (std::vector<std::string>::iterator i = objects.begin(); + i != objects.end(); ++i) { + *i = value + *i; + } + + // Store the property. + properties[prop] = cmJoin(objects, ";"); + importedLocations.insert(prop); } else { // Construct the property name. std::string prop = "IMPORTED_LOCATION"; diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index dc54488..1526454 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -64,8 +64,10 @@ void cmGeneratorExpressionEvaluationFile::Generate( return; } std::ostringstream e; - e << "Evaluation file to be written multiple times for different " - "configurations or languages with different content:\n " + e << "Evaluation file to be written multiple times with different " + "content. " + "This is generally caused by the content evaluating the " + "configuration type, language, or location of object files:\n " << outputFileName; lg->IssueMessage(cmake::FATAL_ERROR, e.str()); return; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 8fee119..77a4962 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -33,8 +33,6 @@ #include <string.h> #include <utility> -class cmSourceFile; - std::string cmGeneratorExpressionNode::EvaluateDependentExpression( std::string const& prop, cmLocalGenerator* lg, cmGeneratorExpressionContext* context, cmGeneratorTarget const* headTarget, @@ -1228,15 +1226,6 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode cmGeneratorExpressionDAGChecker* /*dagChecker*/) const CM_OVERRIDE { - if (!context->EvaluateForBuildsystem) { - std::ostringstream e; - e << "The evaluation of the TARGET_OBJECTS generator expression " - "is only suitable for consumption by CMake. It is not suitable " - "for writing out elsewhere."; - reportError(context, content->GetOriginalExpression(), e.str()); - return std::string(); - } - std::string tgtName = parameters.front(); cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName); if (!gt) { @@ -1253,39 +1242,60 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode reportError(context, content->GetOriginalExpression(), e.str()); return std::string(); } + if (!context->EvaluateForBuildsystem) { + cmGlobalGenerator* gg = context->LG->GetGlobalGenerator(); + std::string reason; + if (!gg->HasKnownObjectFileLocation(&reason)) { + std::ostringstream e; + e << "The evaluation of the TARGET_OBJECTS generator expression " + "is only suitable for consumption by CMake (limited" + << reason << "). " + "It is not suitable for writing out elsewhere."; + reportError(context, content->GetOriginalExpression(), e.str()); + return std::string(); + } + } - std::vector<cmSourceFile const*> objectSources; - gt->GetObjectSources(objectSources, context->Config); - std::map<cmSourceFile const*, std::string> mapping; + std::vector<std::string> objects; - for (std::vector<cmSourceFile const*>::const_iterator it = - objectSources.begin(); - it != objectSources.end(); ++it) { - mapping[*it]; - } + if (gt->IsImported()) { + const char* loc = CM_NULLPTR; + const char* imp = CM_NULLPTR; + std::string suffix; + if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) { + cmSystemTools::ExpandListArgument(loc, objects); + } + context->HadContextSensitiveCondition = true; + } else { + gt->GetTargetObjectNames(context->Config, objects); + + std::string obj_dir; + if (context->EvaluateForBuildsystem) { + // Use object file directory with buildsystem placeholder. + obj_dir = gt->ObjectDirectory; + // Here we assume that the set of object files produced + // by an object library does not vary with configuration + // and do not set HadContextSensitiveCondition to true. + } else { + // Use object file directory with per-config location. + obj_dir = gt->GetObjectDirectory(context->Config); + context->HadContextSensitiveCondition = true; + } - gt->LocalGenerator->ComputeObjectFilenames(mapping, gt); + for (std::vector<std::string>::iterator oi = objects.begin(); + oi != objects.end(); ++oi) { + *oi = obj_dir + *oi; + } + } + // Create the cmSourceFile instances in the referencing directory. cmMakefile* mf = context->LG->GetMakefile(); - - std::string obj_dir = gt->ObjectDirectory; - std::string result; - const char* sep = ""; - for (std::vector<cmSourceFile const*>::const_iterator it = - objectSources.begin(); - it != objectSources.end(); ++it) { - // Find the object file name corresponding to this source file. - std::map<cmSourceFile const*, std::string>::const_iterator map_it = - mapping.find(*it); - // It must exist because we populated the mapping just above. - assert(!map_it->second.empty()); - result += sep; - std::string objFile = obj_dir + map_it->second; - mf->AddTargetObject(tgtName, objFile); - result += objFile; - sep = ";"; + for (std::vector<std::string>::iterator oi = objects.begin(); + oi != objects.end(); ++oi) { + mf->AddTargetObject(tgtName, *oi); } - return result; + + return cmJoin(objects, ";"); } } targetObjectsNode; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 32e2b00..2799505 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3274,6 +3274,46 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const return prefix + base + ".pdb"; } +std::string cmGeneratorTarget::GetObjectDirectory( + std::string const& config) const +{ + std::string obj_dir = + this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config); +#if defined(__APPLE__) + // find and replace $(PROJECT_NAME) xcode placeholder + const std::string projectName = this->LocalGenerator->GetProjectName(); + cmSystemTools::ReplaceString(obj_dir, "$(PROJECT_NAME)", projectName); +#endif + return obj_dir; +} + +void cmGeneratorTarget::GetTargetObjectNames( + std::string const& config, std::vector<std::string>& objects) const +{ + std::vector<cmSourceFile const*> objectSources; + this->GetObjectSources(objectSources, config); + std::map<cmSourceFile const*, std::string> mapping; + + for (std::vector<cmSourceFile const*>::const_iterator it = + objectSources.begin(); + it != objectSources.end(); ++it) { + mapping[*it]; + } + + this->LocalGenerator->ComputeObjectFilenames(mapping, this); + + for (std::vector<cmSourceFile const*>::const_iterator it = + objectSources.begin(); + it != objectSources.end(); ++it) { + // Find the object file name corresponding to this source file. + std::map<cmSourceFile const*, std::string>::const_iterator map_it = + mapping.find(*it); + // It must exist because we populated the mapping just above. + assert(!map_it->second.empty()); + objects.push_back(map_it->second); + } +} + bool cmGeneratorTarget::StrictTargetComparison::operator()( cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index d4f48fe..5b903de 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -209,6 +209,11 @@ public: bool realname) const; std::string NormalGetRealName(const std::string& config) const; + /** Get the names of an object library's object files underneath + its object file directory. */ + void GetTargetObjectNames(std::string const& config, + std::vector<std::string>& objects) const; + /** What hierarchy level should the reported directory contain */ enum BundleDirectoryLevel { @@ -364,6 +369,10 @@ public: time config name placeholder if needed for the generator. */ std::string ObjectDirectory; + /** Full path with trailing slash to the top-level directory + holding object files for the given configuration. */ + std::string GetObjectDirectory(std::string const& config) const; + void GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const; @@ -534,7 +543,7 @@ public: std::string GetPDBDirectory(const std::string& config) const; ///! Return the preferred linker language for this target - std::string GetLinkerLanguage(const std::string& config = "") const; + std::string GetLinkerLanguage(const std::string& config) const; /** Does this target have a GNU implib to convert to MS format? */ bool HasImplibGNUtoMS() const; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 4200b21..aa2dd22 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -331,6 +331,11 @@ public: i.e. "Can I build Debug and Release in the same tree?" */ virtual bool IsMultiConfig() const { return false; } + /** Return true if we know the exact location of object files. + If false, store the reason in the given string. + This is meaningful only after EnableLanguage has been called. */ + virtual bool HasKnownObjectFileLocation(std::string*) const { return true; } + virtual bool UseFolderProperty() const; virtual bool IsIPOSupported() const { return false; } diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index ecc3e31..8c1c0e7 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -3720,6 +3720,18 @@ bool cmGlobalXCodeGenerator::IsMultiConfig() const return true; } +bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation( + std::string* reason) const +{ + if (this->ObjectDirArch.find('$') != std::string::npos) { + if (reason != CM_NULLPTR) { + *reason = " under Xcode with multiple architectures"; + } + return false; + } + return true; +} + bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const { const char* epnValue = diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 982dabd..a733d5c 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -87,6 +87,8 @@ public: i.e. "Can I build Debug and Release in the same tree?" */ bool IsMultiConfig() const CM_OVERRIDE; + bool HasKnownObjectFileLocation(std::string* reason) const CM_OVERRIDE; + bool UseEffectivePlatformName(cmMakefile* mf) const CM_OVERRIDE; bool ShouldStripResourcePath(cmMakefile*) const CM_OVERRIDE; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index c8923b0..ba554aa 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -206,6 +206,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group); cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group); cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group); + cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group); cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group); cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group); cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group); @@ -234,6 +235,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) cmInstallCommandArguments archiveArgs(this->DefaultComponentName); cmInstallCommandArguments libraryArgs(this->DefaultComponentName); cmInstallCommandArguments runtimeArgs(this->DefaultComponentName); + cmInstallCommandArguments objectArgs(this->DefaultComponentName); cmInstallCommandArguments frameworkArgs(this->DefaultComponentName); cmInstallCommandArguments bundleArgs(this->DefaultComponentName); cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName); @@ -246,6 +248,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs); libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs); runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs); + objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs); frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs); bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs); privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs); @@ -265,6 +268,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) archiveArgs.SetGenericArguments(&genericArgs); libraryArgs.SetGenericArguments(&genericArgs); runtimeArgs.SetGenericArguments(&genericArgs); + objectArgs.SetGenericArguments(&genericArgs); frameworkArgs.SetGenericArguments(&genericArgs); bundleArgs.SetGenericArguments(&genericArgs); privateHeaderArgs.SetGenericArguments(&genericArgs); @@ -274,6 +278,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) success = success && archiveArgs.Finalize(); success = success && libraryArgs.Finalize(); success = success && runtimeArgs.Finalize(); + success = success && objectArgs.Finalize(); success = success && frameworkArgs.Finalize(); success = success && bundleArgs.Finalize(); success = success && privateHeaderArgs.Finalize(); @@ -287,8 +292,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Enforce argument rules too complex to specify for the // general-purpose parser. if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() || - frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() || - privateHeaderArgs.GetNamelinkOnly() || + objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() || + bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() || publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) { this->SetError( "TARGETS given NAMELINK_ONLY option not in LIBRARY group. " @@ -296,8 +301,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) return false; } if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() || - frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() || - privateHeaderArgs.GetNamelinkSkip() || + objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() || + bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() || publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) { this->SetError( "TARGETS given NAMELINK_SKIP option not in LIBRARY group. " @@ -356,11 +361,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) return false; } if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "TARGETS given OBJECT library \"" << (*targetIt) - << "\" which may not be installed."; - this->SetError(e.str()); - return false; + std::string reason; + if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation( + &reason)) { + std::ostringstream e; + e << "TARGETS given OBJECT library \"" << (*targetIt) + << "\" which may not be installed" << reason << "."; + this->SetError(e.str()); + return false; + } } // Store the target in the list to be installed. targets.push_back(target); @@ -379,6 +388,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) bool installsArchive = false; bool installsLibrary = false; bool installsRuntime = false; + bool installsObject = false; bool installsFramework = false; bool installsBundle = false; bool installsPrivateHeader = false; @@ -393,6 +403,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) cmInstallTargetGenerator* archiveGenerator = CM_NULLPTR; cmInstallTargetGenerator* libraryGenerator = CM_NULLPTR; cmInstallTargetGenerator* runtimeGenerator = CM_NULLPTR; + cmInstallTargetGenerator* objectGenerator = CM_NULLPTR; cmInstallTargetGenerator* frameworkGenerator = CM_NULLPTR; cmInstallTargetGenerator* bundleGenerator = CM_NULLPTR; cmInstallFilesGenerator* privateHeaderGenerator = CM_NULLPTR; @@ -522,6 +533,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) return false; } } break; + case cmStateEnums::OBJECT_LIBRARY: { + // Objects use OBJECT properties. + if (!objectArgs.GetDestination().empty()) { + objectGenerator = + CreateInstallTargetGenerator(target, objectArgs, false); + } else { + std::ostringstream e; + e << "TARGETS given no OBJECTS DESTINATION for object library " + "target \"" + << target.GetName() << "\"."; + this->SetError(e.str()); + return false; + } + } break; case cmStateEnums::EXECUTABLE: { if (target.IsAppBundleOnApple()) { // Application bundles use the BUNDLE properties. @@ -664,6 +689,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) installsArchive = installsArchive || archiveGenerator != CM_NULLPTR; installsLibrary = installsLibrary || libraryGenerator != CM_NULLPTR; installsRuntime = installsRuntime || runtimeGenerator != CM_NULLPTR; + installsObject = installsObject || objectGenerator != CM_NULLPTR; installsFramework = installsFramework || frameworkGenerator != CM_NULLPTR; installsBundle = installsBundle || bundleGenerator != CM_NULLPTR; installsPrivateHeader = @@ -675,6 +701,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) this->Makefile->AddInstallGenerator(archiveGenerator); this->Makefile->AddInstallGenerator(libraryGenerator); this->Makefile->AddInstallGenerator(runtimeGenerator); + this->Makefile->AddInstallGenerator(objectGenerator); this->Makefile->AddInstallGenerator(frameworkGenerator); this->Makefile->AddInstallGenerator(bundleGenerator); this->Makefile->AddInstallGenerator(privateHeaderGenerator); @@ -692,6 +719,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) te->HeaderGenerator = publicHeaderGenerator; te->LibraryGenerator = libraryGenerator; te->RuntimeGenerator = runtimeGenerator; + te->ObjectsGenerator = objectGenerator; this->Makefile->GetGlobalGenerator() ->GetExportSets()[exports.GetString()] ->AddTargetExport(te); @@ -715,6 +743,10 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) this->Makefile->GetGlobalGenerator()->AddInstallComponent( runtimeArgs.GetComponent().c_str()); } + if (installsObject) { + this->Makefile->GetGlobalGenerator()->AddInstallComponent( + objectArgs.GetComponent().c_str()); + } if (installsFramework) { this->Makefile->GetGlobalGenerator()->AddInstallComponent( frameworkArgs.GetComponent().c_str()); diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 88fcc56..6ecf42d 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -60,25 +60,6 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os) void cmInstallTargetGenerator::GenerateScriptForConfig( std::ostream& os, const std::string& config, Indent const& indent) { - // Compute the build tree directory from which to copy the target. - std::string fromDirConfig; - if (this->Target->NeedRelinkBeforeInstall(config)) { - fromDirConfig = - this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory(); - fromDirConfig += cmake::GetCMakeFilesDirectory(); - fromDirConfig += "/CMakeRelink.dir/"; - } else { - fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary); - fromDirConfig += "/"; - } - std::string toDir = - this->ConvertToAbsoluteDestination(this->GetDestination(config)); - toDir += "/"; - - // Compute the list of files to install for this target. - std::vector<std::string> filesFrom; - std::vector<std::string> filesTo; - std::string literal_args; cmStateEnums::TargetType targetType = this->Target->GetType(); cmInstallType type = cmInstallType(); switch (targetType) { @@ -100,7 +81,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( assert(false && "INTERFACE_LIBRARY targets have no installable outputs."); break; + case cmStateEnums::OBJECT_LIBRARY: + this->GenerateScriptForConfigObjectLibrary(os, config, indent); + return; + case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: case cmStateEnums::UNKNOWN_LIBRARY: @@ -109,6 +94,28 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( "cmInstallTargetGenerator created with non-installable target."); return; } + + // Compute the build tree directory from which to copy the target. + std::string fromDirConfig; + if (this->Target->NeedRelinkBeforeInstall(config)) { + fromDirConfig = + this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory(); + fromDirConfig += cmake::GetCMakeFilesDirectory(); + fromDirConfig += "/CMakeRelink.dir/"; + } else { + fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary); + fromDirConfig += "/"; + } + + std::string toDir = + this->ConvertToAbsoluteDestination(this->GetDestination(config)); + toDir += "/"; + + // Compute the list of files to install for this target. + std::vector<std::string> filesFrom; + std::vector<std::string> filesTo; + std::string literal_args; + if (targetType == cmStateEnums::EXECUTABLE) { // There is a bug in cmInstallCommand if this fails. assert(this->NamelinkMode == NamelinkModeNone); @@ -315,6 +322,49 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( &cmInstallTargetGenerator::PostReplacementTweaks); } +static std::string computeInstallObjectDir(cmGeneratorTarget* gt, + std::string const& config) +{ + std::string objectDir = "objects"; + if (!config.empty()) { + objectDir += "-"; + objectDir += config; + } + objectDir += "/"; + objectDir += gt->GetName(); + return objectDir; +} + +void cmInstallTargetGenerator::GenerateScriptForConfigObjectLibrary( + std::ostream& os, const std::string& config, Indent const& indent) +{ + // Compute all the object files inside this target + std::vector<std::string> objects; + this->Target->GetTargetObjectNames(config, objects); + + std::string const dest = this->GetDestination(config) + "/" + + computeInstallObjectDir(this->Target, config); + + std::string const obj_dir = this->Target->GetObjectDirectory(config); + std::string const literal_args = " FILES_FROM_DIR \"" + obj_dir + "\""; + + const char* no_dir_permissions = CM_NULLPTR; + const char* no_rename = CM_NULLPTR; + this->AddInstallRule(os, dest, cmInstallType_FILES, objects, this->Optional, + this->FilePermissions.c_str(), no_dir_permissions, + no_rename, literal_args.c_str(), indent); +} + +void cmInstallTargetGenerator::GetInstallObjectNames( + std::string const& config, std::vector<std::string>& objects) const +{ + this->Target->GetTargetObjectNames(config, objects); + for (std::vector<std::string>::iterator i = objects.begin(); + i != objects.end(); ++i) { + *i = computeInstallObjectDir(this->Target, config) + "/" + *i; + } +} + std::string cmInstallTargetGenerator::GetDestination( std::string const& config) const { diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index e6b11b8..6aaa3ba 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -41,6 +41,9 @@ public: std::string GetInstallFilename(const std::string& config) const; + void GetInstallObjectNames(std::string const& config, + std::vector<std::string>& objects) const; + enum NameType { NameNormal, @@ -65,6 +68,9 @@ protected: void GenerateScript(std::ostream& os) CM_OVERRIDE; void GenerateScriptForConfig(std::ostream& os, const std::string& config, Indent const& indent) CM_OVERRIDE; + void GenerateScriptForConfigObjectLibrary(std::ostream& os, + const std::string& config, + Indent const& indent); typedef void (cmInstallTargetGenerator::*TweakMethod)(std::ostream&, Indent const&, const std::string&, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index f297988..0b1bb06 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1351,11 +1351,9 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config, // Lookup/compute/cache the import information for this // configuration. - std::string config_upper; - if (!config.empty()) { - config_upper = cmSystemTools::UpperCase(config); - } else { - config_upper = "NOCONFIG"; + std::string desired_config = config; + if (config.empty()) { + desired_config = "NOCONFIG"; } std::string result; @@ -1365,7 +1363,7 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config, std::string suffix; if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetMappedConfig(config_upper, &loc, &imp, suffix)) { + this->GetMappedConfig(desired_config, &loc, &imp, suffix)) { if (!pimplib) { if (loc) { result = loc; @@ -1448,18 +1446,28 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, const char** loc, const char** imp, std::string& suffix) const { - std::string const locPropBase = - this->GetType() == cmStateEnums::INTERFACE_LIBRARY ? "IMPORTED_LIBNAME" - : "IMPORTED_LOCATION"; + std::string config_upper; + if (!desired_config.empty()) { + config_upper = cmSystemTools::UpperCase(desired_config); + } + + std::string locPropBase; + if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + locPropBase = "IMPORTED_LIBNAME"; + } else if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { + locPropBase = "IMPORTED_OBJECTS"; + } else { + locPropBase = "IMPORTED_LOCATION"; + } // Track the configuration-specific property suffix. suffix = "_"; - suffix += desired_config; + suffix += config_upper; std::vector<std::string> mappedConfigs; { std::string mapProp = "MAP_IMPORTED_CONFIG_"; - mapProp += desired_config; + mapProp += config_upper; if (const char* mapValue = this->GetProperty(mapProp)) { cmSystemTools::ExpandListArgument(mapValue, mappedConfigs, true); } diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h index 7b5339f..9304eab 100644 --- a/Source/cmTargetExport.h +++ b/Source/cmTargetExport.h @@ -26,6 +26,7 @@ public: cmInstallTargetGenerator* ArchiveGenerator; cmInstallTargetGenerator* RuntimeGenerator; cmInstallTargetGenerator* LibraryGenerator; + cmInstallTargetGenerator* ObjectsGenerator; cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* BundleGenerator; cmInstallFilesGenerator* HeaderGenerator; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fbfc1ed..f0f04a8 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1881,7 +1881,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string lang = this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str()); std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf); - const std::string& linkLanguage = this->GeneratorTarget->GetLinkerLanguage(); + const std::string& linkLanguage = + this->GeneratorTarget->GetLinkerLanguage(""); bool needForceLang = false; // source file does not match its extension language if (lang != sourceLang) { |