diff options
Diffstat (limited to 'Source/cmExportBuildFileGenerator.cxx')
-rw-r--r-- | Source/cmExportBuildFileGenerator.cxx | 184 |
1 files changed, 106 insertions, 78 deletions
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index a1c424aca..7e9a98738 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -2,32 +2,32 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportBuildFileGenerator.h" -#include "cmAlgorithms.h" +#include <map> +#include <memory> +#include <set> +#include <sstream> +#include <utility> + #include "cmExportSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmPolicies.h" #include "cmStateTypes.h" -#include "cmSystemTools.h" +#include "cmStringAlgorithms.h" #include "cmTarget.h" #include "cmTargetExport.h" #include "cmake.h" -#include <algorithm> -#include <map> -#include <set> -#include <sstream> -#include <utility> - class cmSourceFile; cmExportBuildFileGenerator::cmExportBuildFileGenerator() { - this->LG = CM_NULLPTR; - this->ExportSet = CM_NULLPTR; + this->LG = nullptr; + this->ExportSet = nullptr; } void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg) @@ -44,10 +44,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) std::string expectedTargets; std::string sep; std::vector<std::string> targets; + bool generatedInterfaceRequired = false; this->GetTargets(targets); - for (std::vector<std::string>::const_iterator tei = targets.begin(); - tei != targets.end(); ++tei) { - cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(*tei); + for (std::string const& tei : targets) { + cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei); expectedTargets += sep + this->Namespace + te->GetExportName(); sep = " "; if (this->ExportedTargets.insert(te).second) { @@ -56,26 +56,25 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) std::ostringstream e; e << "given target \"" << te->GetName() << "\" more than once."; this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - cmake::FATAL_ERROR, e.str(), + MessageType::FATAL_ERROR, e.str(), this->LG->GetMakefile()->GetBacktrace()); return false; } - if (te->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - this->GenerateRequiredCMakeVersion(os, "3.0.0"); - } + generatedInterfaceRequired |= + this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY; } + if (generatedInterfaceRequired) { + this->GenerateRequiredCMakeVersion(os, "3.0.0"); + } this->GenerateExpectedTargetsCode(os, expectedTargets); } std::vector<std::string> missingTargets; // Create all the imported targets. - for (std::vector<cmGeneratorTarget*>::const_iterator tei = - this->Exports.begin(); - tei != this->Exports.end(); ++tei) { - cmGeneratorTarget* gte = *tei; - this->GenerateImportTargetCode(os, gte); + for (cmGeneratorTarget* gte : this->Exports) { + this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); gte->Target->AppendBuildInterfaceIncludes(); @@ -93,14 +92,35 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); + + std::string errorMessage; + if (!this->PopulateExportProperties(gte, properties, errorMessage)) { + this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, errorMessage, + this->LG->GetMakefile()->GetBacktrace()); + return false; + } + const bool newCMP0022Behavior = gte->GetPolicyStatusCMP0022() != cmPolicies::WARN && gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; @@ -115,10 +135,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) } // Generate import file content for each configuration. - for (std::vector<std::string>::const_iterator ci = - this->Configurations.begin(); - ci != this->Configurations.end(); ++ci) { - this->GenerateImportConfig(os, *ci, missingTargets); + for (std::string const& c : this->Configurations) { + this->GenerateImportConfig(os, c, missingTargets); } this->GenerateMissingTargetsCheckCode(os, missingTargets); @@ -130,19 +148,17 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( std::ostream& os, const std::string& config, std::string const& suffix, std::vector<std::string>& missingTargets) { - for (std::vector<cmGeneratorTarget*>::const_iterator tei = - this->Exports.begin(); - tei != this->Exports.end(); ++tei) { + for (cmGeneratorTarget* target : this->Exports) { // Collect import properties for this target. - cmGeneratorTarget* target = *tei; ImportPropertyMap properties; - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) { this->SetImportLocationProperty(config, suffix, target, properties); } if (!properties.empty()) { // Get the rest of the target details. - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != + cmStateEnums::INTERFACE_LIBRARY) { this->SetImportDetailProperties(config, suffix, target, properties, missingTargets); this->SetImportLinkInterface(config, suffix, @@ -150,7 +166,7 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( target, properties, missingTargets); } - // TOOD: PUBLIC_HEADER_LOCATION + // TODO: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff // is done. Then this can be a propagated include directory. // this->GenerateImportProperty(config, te->HeaderGenerator, @@ -162,6 +178,21 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( } } +cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType( + cmGeneratorTarget const* target) const +{ + cmStateEnums::TargetType targetType = target->GetType(); + // An object library exports as an interface library if we cannot + // tell clients where to find the objects. This is sufficient + // to support transitive usage requirements on other targets that + // use the object library. + if (targetType == cmStateEnums::OBJECT_LIBRARY && + !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) { + targetType = cmStateEnums::INTERFACE_LIBRARY; + } + return targetType; +} + void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet) { this->ExportSet = exportSet; @@ -175,8 +206,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( cmMakefile* mf = target->Makefile; if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string prop = "IMPORTED_OBJECTS"; - prop += suffix; + std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix); // Compute all the object files inside this target and setup // IMPORTED_OBJECTS as a list of object files @@ -184,10 +214,8 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( 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); + for (cmSourceFile const* sf : objectSources) { + const std::string& obj = target->GetObjectName(sf); objects.push_back(obj_dir + obj); } @@ -196,8 +224,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( } else { // Add the main target file. { - std::string prop = "IMPORTED_LOCATION"; - prop += suffix; + std::string prop = cmStrCat("IMPORTED_LOCATION", suffix); std::string value; if (target->IsAppBundleOnApple()) { value = @@ -210,13 +237,14 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( } // Add the import library for windows DLLs. - if (target->HasImportLibrary() && - mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { - std::string prop = "IMPORTED_IMPLIB"; - prop += suffix; + if (target->HasImportLibrary(config)) { + std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix); std::string value = target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact); - target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); + if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { + target->GetImplibGNUtoMS(config, value, value, + "${CMAKE_IMPORT_LIBRARY_SUFFIX}"); + } properties[prop] = value; } } @@ -231,20 +259,20 @@ void cmExportBuildFileGenerator::HandleMissingTarget( const std::string name = dependee->GetName(); cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); - std::vector<std::string> namespaces = this->FindNamespaces(gg, name); + auto exportInfo = this->FindBuildExportInfo(gg, name); + std::vector<std::string> const& exportFiles = exportInfo.first; - int targetOccurrences = (int)namespaces.size(); - if (targetOccurrences == 1) { - std::string missingTarget = namespaces[0]; + if (exportFiles.size() == 1) { + std::string missingTarget = exportInfo.second; missingTarget += dependee->GetExportName(); link_libs += missingTarget; - missingTargets.push_back(missingTarget); + missingTargets.push_back(std::move(missingTarget)); return; } // We are not appending, so all exported targets should be // known here. This is probably user-error. - this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); + this->ComplainAboutMissingTarget(depender, dependee, exportFiles); } // Assume the target will be exported by another command. // Append it with the export namespace. @@ -256,59 +284,59 @@ void cmExportBuildFileGenerator::GetTargets( std::vector<std::string>& targets) const { if (this->ExportSet) { - for (std::vector<cmTargetExport*>::const_iterator tei = - this->ExportSet->GetTargetExports()->begin(); - tei != this->ExportSet->GetTargetExports()->end(); ++tei) { - targets.push_back((*tei)->TargetName); + for (std::unique_ptr<cmTargetExport> const& te : + this->ExportSet->GetTargetExports()) { + targets.push_back(te->TargetName); } return; } targets = this->Targets; } -std::vector<std::string> cmExportBuildFileGenerator::FindNamespaces( - cmGlobalGenerator* gg, const std::string& name) +std::pair<std::vector<std::string>, std::string> +cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, + const std::string& name) { - std::vector<std::string> namespaces; + std::vector<std::string> exportFiles; + std::string ns; std::map<std::string, cmExportBuildFileGenerator*>& exportSets = gg->GetBuildExportSets(); - for (std::map<std::string, cmExportBuildFileGenerator*>::const_iterator - expIt = exportSets.begin(); - expIt != exportSets.end(); ++expIt) { - const cmExportBuildFileGenerator* exportSet = expIt->second; + for (auto const& exp : exportSets) { + const cmExportBuildFileGenerator* exportSet = exp.second; std::vector<std::string> targets; exportSet->GetTargets(targets); - if (std::find(targets.begin(), targets.end(), name) != targets.end()) { - namespaces.push_back(exportSet->GetNamespace()); + if (cmContains(targets, name)) { + exportFiles.push_back(exp.first); + ns = exportSet->GetNamespace(); } } - return namespaces; + return { exportFiles, ns }; } void cmExportBuildFileGenerator::ComplainAboutMissingTarget( - cmGeneratorTarget* depender, cmGeneratorTarget* dependee, int occurrences) + cmGeneratorTarget* depender, cmGeneratorTarget* dependee, + std::vector<std::string> const& exportFiles) { - if (cmSystemTools::GetErrorOccuredFlag()) { - return; - } - std::ostringstream e; e << "export called with target \"" << depender->GetName() << "\" which requires target \"" << dependee->GetName() << "\" "; - if (occurrences == 0) { - e << "that is not in the export set.\n"; + if (exportFiles.empty()) { + e << "that is not in any export set."; } else { - e << "that is not in this export set, but " << occurrences - << " times in others.\n"; + e << "that is not in this export set, but in multiple other export sets: " + << cmJoin(exportFiles, ", ") << ".\n"; + e << "An exported target cannot depend upon another target which is " + "exported multiple times. Consider consolidating the exports of the " + "\"" + << dependee->GetName() << "\" target to a single export."; } - e << "If the required target is not easy to reference in this call, " - << "consider using the APPEND option with multiple separate calls."; this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - cmake::FATAL_ERROR, e.str(), this->LG->GetMakefile()->GetBacktrace()); + MessageType::FATAL_ERROR, e.str(), + this->LG->GetMakefile()->GetBacktrace()); } std::string cmExportBuildFileGenerator::InstallNameDir( |