From 66b290e7e2bbeb987ea83e2f9edaac99fe8593f5 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sat, 6 Oct 2012 17:27:40 +0200 Subject: 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 + Tests/RunCMake/CMP0022/CMP0022-export-stderr.txt | 2 +- .../ExportWithoutLanguage/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 e2ad74f..e593e0c 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 4436896..0392d80 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 9d0d478..86ddc3f 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 87c3452..38e8d9a 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 25c5710..b01e499 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -52,6 +52,12 @@ void cmExportFileGenerator::SetExportFile(const char* mainFile) } //---------------------------------------------------------------------------- +const char* cmExportFileGenerator::GetMainExportFileName() const +{ + return this->MainImportFile.c_str(); +} + +//---------------------------------------------------------------------------- bool cmExportFileGenerator::GenerateImportFile() { // Open the output file to generate it. diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 9628b96..f3d0807 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 eacf85b..fb205be 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 b8860f1..c930b2b 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 39d4993..5b93171 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 ae7627e..405dd8d 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 67a0ae3..5658d85 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 0000000..0c803ed --- /dev/null +++ b/Tests/RunCMake/ExportWithoutLanguage/header.h @@ -0,0 +1,2 @@ + +enum some_compilers { need_more_than_nothing }; -- cgit v0.12