From e383555838c2539eca11c43abfccba9fa41ca97d Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 10 Oct 2013 11:14:11 +0200 Subject: [PATCH 1/4] cmExportInstallFileGenerator: Fix comment to match reality. It was copied from cmExportBuildFileGenerator. --- Source/cmExportInstallFileGenerator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index c71008e2c7..133944ee57 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -432,8 +432,8 @@ cmExportInstallFileGenerator::HandleMissingTarget( } else { - // We are not appending, so all exported targets should be - // known here. This is probably user-error. + // All exported targets should be known here and should be unique. + // This is probably user-error. this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); } } From 5fe5c32480a5acf26bd20e52a091cd63747ed77d Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sat, 6 Oct 2012 17:16:11 +0200 Subject: [PATCH 2/4] export(): Set a Makefile on the cmExportBuildFileGenerator. This is better than the cmCommand, because the lifetime of that is not as useful, and it is only used to report an error anyway. In the next commit, the cmExportBuildFileGenerator will outlive the cmCommand. --- Source/cmExportBuildFileGenerator.cxx | 21 ++++++++++----------- Source/cmExportBuildFileGenerator.h | 13 ++++++++----- Source/cmExportCommand.cxx | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 243e5ce54d..e2ad74f06d 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -11,12 +11,11 @@ ============================================================================*/ #include "cmExportBuildFileGenerator.h" -#include "cmExportCommand.h" //---------------------------------------------------------------------------- cmExportBuildFileGenerator::cmExportBuildFileGenerator() { - this->ExportCommand = 0; + this->Makefile = 0; } //---------------------------------------------------------------------------- @@ -39,12 +38,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) } else { - if(this->ExportCommand && this->ExportCommand->ErrorMessage.empty()) - { - cmOStringStream e; - e << "given target \"" << te->GetName() << "\" more than once."; - this->ExportCommand->ErrorMessage = e.str(); - } + cmOStringStream e; + e << "given target \"" << te->GetName() << "\" more than once."; + this->Makefile->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), this->Backtrace); return false; } if (te->GetType() == cmTarget::INTERFACE_LIBRARY) @@ -220,18 +217,20 @@ cmExportBuildFileGenerator ::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee) { - if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty()) + if(cmSystemTools::GetErrorOccuredFlag()) { return; } cmOStringStream e; - e << "called with target \"" << depender->GetName() + e << "export called with target \"" << depender->GetName() << "\" which requires target \"" << dependee->GetName() << "\" that is not in the export list.\n" << "If the required target is not easy to reference in this call, " << "consider using the APPEND option with multiple separate calls."; - this->ExportCommand->ErrorMessage = e.str(); + + this->Makefile->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), this->Backtrace); } std::string diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 3ffdf8b133..4436896107 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -13,8 +13,7 @@ #define cmExportBuildFileGenerator_h #include "cmExportFileGenerator.h" - -class cmExportCommand; +#include "cmListFileCache.h" /** \class cmExportBuildFileGenerator * \brief Generate a file exporting targets from a build tree. @@ -37,8 +36,11 @@ public: /** Set whether to append generated code to the output file. */ void SetAppendMode(bool append) { this->AppendMode = append; } - /** Set the command instance through which errors should be reported. */ - void SetCommand(cmExportCommand* cmd) { this->ExportCommand = cmd; } + void SetMakefile(cmMakefile *mf) { + this->Makefile = mf; + this->Makefile->GetBacktrace(this->Backtrace); + } + protected: // Implement virtual methods from the superclass. virtual bool GenerateMainFile(std::ostream& os); @@ -64,7 +66,8 @@ protected: std::string InstallNameDir(cmTarget* target, const std::string& config); std::vector const* Exports; - cmExportCommand* ExportCommand; + cmMakefile* Makefile; + cmListFileBacktrace Backtrace; }; #endif diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index f335b8bc53..9d0d478707 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -169,7 +169,7 @@ bool cmExportCommand ebfg.SetNamespace(this->Namespace.GetCString()); ebfg.SetAppendMode(this->Append.IsEnabled()); ebfg.SetExports(&targets); - ebfg.SetCommand(this); + ebfg.SetMakefile(this->Makefile); ebfg.SetExportOld(this->ExportOld.IsEnabled()); cmGlobalGenerator *gg = this->Makefile->GetLocalGenerator() From 66b290e7e2bbeb987ea83e2f9edaac99fe8593f5 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sat, 6 Oct 2012 17:27:40 +0200 Subject: [PATCH 3/4] export(): Process the export() command at generate time. Make the API for adding targets string based so that it can easily use cmGeneratorTarget. Teach the cmIncludeCommand to generate the exported file at configure-time instead if it is to be include()d. The RunCMake.ExportWithoutLanguage test now needs a dummy header.h file as expected error from export() is now reported after the missing file error. --- Source/cmExportBuildFileGenerator.cxx | 21 +++--- Source/cmExportBuildFileGenerator.h | 12 +++- Source/cmExportCommand.cxx | 71 ++++++------------- Source/cmExportCommand.h | 4 +- Source/cmExportFileGenerator.cxx | 6 ++ Source/cmExportFileGenerator.h | 2 + Source/cmGlobalGenerator.cxx | 56 +++++++++++++++ Source/cmGlobalGenerator.h | 22 +++--- Source/cmIncludeCommand.cxx | 1 + .../CMP0022/CMP0022-export-stderr.txt | 2 +- .../NoLanguage-stderr.txt | 4 +- Tests/RunCMake/ExportWithoutLanguage/header.h | 2 + 12 files changed, 120 insertions(+), 83 deletions(-) create mode 100644 Tests/RunCMake/ExportWithoutLanguage/header.h diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index e2ad74f06d..e593e0c5bb 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -21,20 +21,19 @@ cmExportBuildFileGenerator::cmExportBuildFileGenerator() //---------------------------------------------------------------------------- bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) { - std::vector allTargets; { std::string expectedTargets; std::string sep; - for(std::vector::const_iterator - tei = this->Exports->begin(); - tei != this->Exports->end(); ++tei) + for(std::vector::const_iterator + tei = this->Targets.begin(); + tei != this->Targets.end(); ++tei) { - expectedTargets += sep + this->Namespace + (*tei)->GetExportName(); + cmTarget *te = this->Makefile->FindTargetToUse(tei->c_str()); + expectedTargets += sep + this->Namespace + te->GetExportName(); sep = " "; - cmTarget* te = *tei; if(this->ExportedTargets.insert(te).second) { - allTargets.push_back(te); + this->Exports.push_back(te); } else { @@ -57,8 +56,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Create all the imported targets. for(std::vector::const_iterator - tei = allTargets.begin(); - tei != allTargets.end(); ++tei) + tei = this->Exports.begin(); + tei != this->Exports.end(); ++tei) { cmTarget* te = *tei; this->GenerateImportTargetCode(os, te); @@ -113,8 +112,8 @@ cmExportBuildFileGenerator std::vector &missingTargets) { for(std::vector::const_iterator - tei = this->Exports->begin(); - tei != this->Exports->end(); ++tei) + tei = this->Exports.begin(); + tei != this->Exports.end(); ++tei) { // Collect import properties for this target. cmTarget* target = *tei; diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 4436896107..0392d80266 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -30,8 +30,13 @@ public: cmExportBuildFileGenerator(); /** Set the list of targets to export. */ - void SetExports(std::vector const* exports) - { this->Exports = exports; } + void SetTargets(std::vector const& targets) + { this->Targets = targets; } + std::vector const& GetTargets() const + { return this->Targets; } + void AppendTargets(std::vector const& targets) + { this->Targets.insert(this->Targets.end(), + targets.begin(), targets.end()); } /** Set whether to append generated code to the output file. */ void SetAppendMode(bool append) { this->AppendMode = append; } @@ -65,7 +70,8 @@ protected: std::string InstallNameDir(cmTarget* target, const std::string& config); - std::vector const* Exports; + std::vector Targets; + std::vector Exports; cmMakefile* Makefile; cmListFileBacktrace Backtrace; }; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 9d0d478707..86ddc3f44f 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -108,8 +108,6 @@ bool cmExportCommand fname += this->Filename.GetString(); } - // Collect the targets to be exported. - std::vector targets; for(std::vector::const_iterator currentTarget = this->Targets.GetVector().begin(); currentTarget != this->Targets.GetVector().end(); @@ -128,15 +126,7 @@ bool cmExportCommand this->Makefile->GetLocalGenerator()-> GetGlobalGenerator()->FindTarget(0, currentTarget->c_str())) { - if((target->GetType() == cmTarget::EXECUTABLE) || - (target->GetType() == cmTarget::STATIC_LIBRARY) || - (target->GetType() == cmTarget::SHARED_LIBRARY) || - (target->GetType() == cmTarget::MODULE_LIBRARY) || - (target->GetType() == cmTarget::INTERFACE_LIBRARY)) - { - targets.push_back(target); - } - else if(target->GetType() == cmTarget::OBJECT_LIBRARY) + if(target->GetType() == cmTarget::OBJECT_LIBRARY) { cmOStringStream e; e << "given OBJECT library \"" << *currentTarget @@ -144,37 +134,28 @@ bool cmExportCommand this->SetError(e.str().c_str()); return false; } - else - { - cmOStringStream e; - e << "given target \"" << *currentTarget - << "\" which is not an executable or library."; - this->SetError(e.str().c_str()); - return false; - } } - else + } + + cmGlobalGenerator *gg = this->Makefile->GetLocalGenerator() + ->GetGlobalGenerator(); + if (this->Append.IsEnabled()) + { + if (cmExportBuildFileGenerator *ebfg = gg->GetExportedTargetsFile(fname)) { - cmOStringStream e; - e << "given target \"" << *currentTarget - << "\" which is not built by this project."; - this->SetError(e.str().c_str()); - return false; + ebfg->AppendTargets(this->Targets.GetVector()); + return true; } } // Setup export file generation. - cmExportBuildFileGenerator ebfg; - ebfg.SetExportFile(fname.c_str()); - ebfg.SetNamespace(this->Namespace.GetCString()); - ebfg.SetAppendMode(this->Append.IsEnabled()); - ebfg.SetExports(&targets); - ebfg.SetMakefile(this->Makefile); - ebfg.SetExportOld(this->ExportOld.IsEnabled()); - - cmGlobalGenerator *gg = this->Makefile->GetLocalGenerator() - ->GetGlobalGenerator(); - gg->AddExportedTargetsFile(fname); + cmExportBuildFileGenerator *ebfg = new cmExportBuildFileGenerator; + ebfg->SetExportFile(fname.c_str()); + ebfg->SetNamespace(this->Namespace.GetCString()); + ebfg->SetAppendMode(this->Append.IsEnabled()); + ebfg->SetTargets(this->Targets.GetVector()); + ebfg->SetMakefile(this->Makefile); + ebfg->SetExportOld(this->ExportOld.IsEnabled()); // Compute the set of configurations exported. std::vector configurationTypes; @@ -185,27 +166,15 @@ bool cmExportCommand ci = configurationTypes.begin(); ci != configurationTypes.end(); ++ci) { - ebfg.AddConfiguration(ci->c_str()); + ebfg->AddConfiguration(ci->c_str()); } } else { - ebfg.AddConfiguration(""); + ebfg->AddConfiguration(""); } - // Generate the import file. - if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty()) - { - this->SetError("could not write export file."); - return false; - } - - // Report generated error message if any. - if(!this->ErrorMessage.empty()) - { - this->SetError(this->ErrorMessage.c_str()); - return false; - } + gg->AddBuildExportSet(ebfg); return true; } diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h index 87c3452843..38e8d9a6d0 100644 --- a/Source/cmExportCommand.h +++ b/Source/cmExportCommand.h @@ -85,7 +85,9 @@ public: "should never be installed. " "See the install(EXPORT) command to export targets from an " "installation tree." - CM_LOCATION_UNDEFINED_BEHAVIOR("passing it to this command") + "\n" + "The properties set on the generated IMPORTED targets will have the " + "same values as the final values of the input TARGETS." "\n" " export(PACKAGE )\n" "Store the current build directory in the CMake user package registry " diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 25c57100cd..b01e4998f3 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -51,6 +51,12 @@ void cmExportFileGenerator::SetExportFile(const char* mainFile) cmSystemTools::GetFilenameLastExtension(this->MainImportFile); } +//---------------------------------------------------------------------------- +const char* cmExportFileGenerator::GetMainExportFileName() const +{ + return this->MainImportFile.c_str(); +} + //---------------------------------------------------------------------------- bool cmExportFileGenerator::GenerateImportFile() { diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 9628b96817..f3d08070f8 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -33,9 +33,11 @@ public: /** Set the full path to the export file to generate. */ void SetExportFile(const char* mainFile); + const char *GetMainExportFileName() const; /** Set the namespace in which to place exported target names. */ void SetNamespace(const char* ns) { this->Namespace = ns; } + std::string GetNamespace() const { return this->Namespace; } void SetExportOld(bool exportOld) { this->ExportOld = exportOld; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index eacf85ba29..fb205bece5 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -27,6 +27,7 @@ #include "cmGeneratorTarget.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionEvaluationFile.h" +#include "cmExportBuildFileGenerator.h" #include @@ -77,6 +78,12 @@ cmGlobalGenerator::~cmGlobalGenerator() { delete *li; } + for(std::map::iterator + i = this->BuildExportSets.begin(); + i != this->BuildExportSets.end(); ++i) + { + delete i->second; + } this->LocalGenerators.clear(); if (this->ExtraGenerator) @@ -183,6 +190,34 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang, doc.c_str(), cmCacheManager::FILEPATH); } +void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen) +{ + this->BuildExportSets[gen->GetMainExportFileName()] = gen; +} + +bool cmGlobalGenerator::GenerateImportFile(const std::string &file) +{ + std::map::iterator it + = this->BuildExportSets.find(file); + if (it != this->BuildExportSets.end()) + { + bool result = it->second->GenerateImportFile(); + delete it->second; + it->second = 0; + this->BuildExportSets.erase(it); + return result; + } + return false; +} + +bool +cmGlobalGenerator::IsExportedTargetsFile(const std::string &filename) const +{ + const std::map::const_iterator it + = this->BuildExportSets.find(filename); + return it != this->BuildExportSets.end(); +} + // Find the make program for the generator, required for try compiles void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) { @@ -966,6 +1001,14 @@ void cmGlobalGenerator::Configure() } } +cmExportBuildFileGenerator* +cmGlobalGenerator::GetExportedTargetsFile(const std::string &filename) const +{ + std::map::const_iterator it + = this->BuildExportSets.find(filename); + return it == this->BuildExportSets.end() ? 0 : it->second; +} + bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { // If the property is not enabled then okay. @@ -1091,6 +1134,19 @@ void cmGlobalGenerator::Generate() } this->SetCurrentLocalGenerator(0); + for (std::map::iterator + it = this->BuildExportSets.begin(); it != this->BuildExportSets.end(); + ++it) + { + if (!it->second->GenerateImportFile() + && !cmSystemTools::GetErrorOccuredFlag()) + { + this->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, "Could not write export file.", + cmListFileBacktrace()); + return; + } + } // Update rule hashes. this->CheckRuleHashes(); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index b8860f1f23..c930b2b6e1 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -31,6 +31,7 @@ class cmExternalMakefileProjectGenerator; class cmTarget; class cmInstallTargetGenerator; class cmInstallFilesGenerator; +class cmExportBuildFileGenerator; /** \class cmGlobalGenerator * \brief Responable for overseeing the generation process for the entire tree @@ -293,18 +294,13 @@ public: void ProcessEvaluationFiles(); - void AddExportedTargetsFile(const std::string &filename) - { - this->ExportedTargetsFiles.insert(filename); - } - - bool IsExportedTargetsFile(const std::string &filename) const - { - const std::set::const_iterator it - = this->ExportedTargetsFiles.find(filename); - return it != this->ExportedTargetsFiles.end(); - } - + std::map& GetBuildExportSets() + {return this->BuildExportSets;} + void AddBuildExportSet(cmExportBuildFileGenerator*); + bool IsExportedTargetsFile(const std::string &filename) const; + bool GenerateImportFile(const std::string &file); + cmExportBuildFileGenerator* + GetExportedTargetsFile(const std::string &filename) const; protected: typedef std::vector GeneratorVector; // for a project collect all its targets by following depend @@ -356,6 +352,7 @@ protected: bool InstallTargetEnabled; // Sets of named target exports cmExportSetMap ExportSets; + std::map BuildExportSets; // Manifest of all targets that will be built for each configuration. // This is computed just before local generators generate. @@ -384,7 +381,6 @@ private: std::map ExtensionToLanguage; std::map LanguageToLinkerPreference; std::map LanguageToOriginalSharedLibFlags; - std::set ExportedTargetsFiles; // Record hashes for rules and outputs. struct RuleHash { char Data[32]; }; diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 39d4993eba..5b931713cb 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -127,6 +127,7 @@ bool cmIncludeCommand return false; } } + gg->GenerateImportFile(fname_abs); } std::string fullFilePath; diff --git a/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt b/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt index ae7627e1e8..405dd8dc8a 100644 --- a/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt +++ b/Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at CMP0022-export.cmake:11 \(export\): +CMake Error in CMakeLists.txt: Target "cmp0022NEW" has policy CMP0022 enabled, but also has old-style LINK_INTERFACE_LIBRARIES properties populated, but it was exported without the EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties diff --git a/Tests/RunCMake/ExportWithoutLanguage/NoLanguage-stderr.txt b/Tests/RunCMake/ExportWithoutLanguage/NoLanguage-stderr.txt index 67a0ae37cd..5658d85d49 100644 --- a/Tests/RunCMake/ExportWithoutLanguage/NoLanguage-stderr.txt +++ b/Tests/RunCMake/ExportWithoutLanguage/NoLanguage-stderr.txt @@ -1,6 +1,4 @@ CMake Error: CMake can not determine linker language for target: NoLanguage -CMake Error at NoLanguage.cmake:2 \(export\): +CMake Error in CMakeLists.txt: Exporting the target "NoLanguage" is not allowed since its linker language cannot be determined -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ExportWithoutLanguage/header.h b/Tests/RunCMake/ExportWithoutLanguage/header.h new file mode 100644 index 0000000000..0c803ed036 --- /dev/null +++ b/Tests/RunCMake/ExportWithoutLanguage/header.h @@ -0,0 +1,2 @@ + +enum some_compilers { need_more_than_nothing }; From a4263c9f6447e526886d6af301b84c9097c097fa Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 10 Oct 2013 11:18:10 +0200 Subject: [PATCH 4/4] export(): Handle multiple dependent export sets. The export-sets topic, merged in commit 49c7b649 (Merge topic 'export-sets', 2012-10-01) changed install(EXPORT) to allow exporting targets whose dependents are exported separately to different locations. Doing the same for export() was not possible because the export() command was executed at configure-time. Now that export() is also executed at generate-time, make it possible to export to multiple dependent export sets. --- Source/cmExportBuildFileGenerator.cxx | 73 +++++++++++++++++++++++---- Source/cmExportBuildFileGenerator.h | 6 ++- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index e593e0c5bb..50835e2956 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmExportBuildFileGenerator.h" +#include "cmLocalGenerator.h" +#include "cmGlobalGenerator.h" //---------------------------------------------------------------------------- cmExportBuildFileGenerator::cmExportBuildFileGenerator() @@ -194,27 +196,72 @@ cmExportBuildFileGenerator //---------------------------------------------------------------------------- void cmExportBuildFileGenerator::HandleMissingTarget( - std::string& link_libs, std::vector&, - cmMakefile*, cmTarget* depender, cmTarget* dependee) + std::string& link_libs, std::vector& missingTargets, + cmMakefile* mf, cmTarget* depender, cmTarget* dependee) { // The target is not in the export. if(!this->AppendMode) { - // We are not appending, so all exported targets should be - // known here. This is probably user-error. - this->ComplainAboutMissingTarget(depender, dependee); + const std::string name = dependee->GetName(); + std::vector namespaces = this->FindNamespaces(mf, name); + + int targetOccurrences = (int)namespaces.size(); + if (targetOccurrences == 1) + { + std::string missingTarget = namespaces[0]; + + missingTarget += dependee->GetExportName(); + link_libs += missingTarget; + missingTargets.push_back(missingTarget); + return; + } + else + { + // We are not appending, so all exported targets should be + // known here. This is probably user-error. + this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); + } } // Assume the target will be exported by another command. // Append it with the export namespace. link_libs += this->Namespace; link_libs += dependee->GetExportName(); +// if generate time {} +} + + +//---------------------------------------------------------------------------- +std::vector +cmExportBuildFileGenerator +::FindNamespaces(cmMakefile* mf, const std::string& name) +{ + std::vector namespaces; + cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator(); + + std::map& exportSets + = gg->GetBuildExportSets(); + + for(std::map::const_iterator + expIt = exportSets.begin(); expIt != exportSets.end(); ++expIt) + { + const cmExportBuildFileGenerator* exportSet = expIt->second; + std::vector const& targets = exportSet->GetTargets(); + + if (std::find(targets.begin(), targets.end(), name) != targets.end()) + { + namespaces.push_back(exportSet->GetNamespace()); + } + } + + return namespaces; } //---------------------------------------------------------------------------- void cmExportBuildFileGenerator ::ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee) + cmTarget* dependee, + int occurrences) { if(cmSystemTools::GetErrorOccuredFlag()) { @@ -223,9 +270,17 @@ cmExportBuildFileGenerator cmOStringStream e; e << "export called with target \"" << depender->GetName() - << "\" which requires target \"" << dependee->GetName() - << "\" that is not in the export list.\n" - << "If the required target is not easy to reference in this call, " + << "\" which requires target \"" << dependee->GetName() << "\" "; + if (occurrences == 0) + { + e << "that is not in the export set.\n"; + } + else + { + e << "that is not in this export set, but " << occurrences + << " times in others.\n"; + } + e << "If the required target is not easy to reference in this call, " << "consider using the APPEND option with multiple separate calls."; this->Makefile->GetCMakeInstance() diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 0392d80266..2fbd98f66a 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -60,7 +60,8 @@ protected: cmTarget* dependee); void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee); + cmTarget* dependee, + int occurrences); /** Fill in properties indicating built file locations. */ void SetImportLocationProperty(const char* config, @@ -70,6 +71,9 @@ protected: std::string InstallNameDir(cmTarget* target, const std::string& config); + std::vector + FindNamespaces(cmMakefile* mf, const std::string& name); + std::vector Targets; std::vector Exports; cmMakefile* Makefile;