diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake index 888e1097a..25d8df39f 100644 --- a/Modules/FindPackageHandleStandardArgs.cmake +++ b/Modules/FindPackageHandleStandardArgs.cmake @@ -120,6 +120,9 @@ macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) set(configsText "${configsText} ${filename} (version ${version})\n") endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") else() diff --git a/Modules/readme.txt b/Modules/readme.txt index 7d61d8d27..4818031d7 100644 --- a/Modules/readme.txt +++ b/Modules/readme.txt @@ -18,6 +18,9 @@ XXX_VERSION_YY Expect Version YY if true. Make sure at most one of thes XXX_WRAP_YY If False, do not try to use the relevent CMake wrapping command. XXX_YY_FOUND If False, optional YY part of XXX sytem is not available. XXX_FOUND Set to false, or undefined, if we haven't found, or don't want to use XXX. +XXX_NOT_FOUND_MESSAGE Should be set by config-files in the case that it has set XXX_FOUND to FALSE. + The contained message will be printed by the find_package() command and by + find_package_handle_standard_args() to inform the user about the problem. XXX_RUNTIME_LIBRARY_DIRS Optionally, the runtime library search path for use when running an executable linked to shared libraries. The list should be used by user code to create the PATH on windows or LD_LIBRARY_PATH on unix. This should not be a cache entry. @@ -124,7 +127,7 @@ If neither the QUIET nor REQUIRED options are given then the FindXXX.cmake module should look for the package and complain without error if the module is not found. -A package can be provide sub-components. +A package can provide sub-components. Those components can be listed after the COMPONENTS (or REQUIRED) or OPTIONAL_COMPONENTS keywords. The set of all listed components will be specified in a XXX_FIND_COMPONENTS variable. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 5a3e7d104..8bf6c4084 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -176,6 +176,10 @@ set(SRCS cmExportFileGenerator.cxx cmExportInstallFileGenerator.h cmExportInstallFileGenerator.cxx + cmExportSet.h + cmExportSet.cxx + cmExportSetMap.h + cmExportSetMap.cxx cmExtraCodeBlocksGenerator.cxx cmExtraCodeBlocksGenerator.h cmExtraEclipseCDT4Generator.cxx @@ -259,6 +263,7 @@ set(SRCS cmSystemTools.h cmTarget.cxx cmTarget.h + cmTargetExport.h cmTest.cxx cmTest.h cmTestGenerator.cxx diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 32595ee4b..fb3f39fe6 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -72,8 +72,9 @@ cmExportBuildFileGenerator if(!properties.empty()) { // Get the rest of the target details. + std::vector missingTargets; this->SetImportDetailProperties(config, suffix, - target, properties); + target, properties, missingTargets); // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -82,6 +83,7 @@ cmExportBuildFileGenerator // properties); // Generate code in the export file. + this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, target, properties); } } @@ -131,6 +133,25 @@ cmExportBuildFileGenerator } } +//---------------------------------------------------------------------------- +void +cmExportBuildFileGenerator::HandleMissingTarget( + std::string& link_libs, std::vector&, + cmMakefile*, 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); + } + // Assume the target will be exported by another command. + // Append it with the export namespace. + link_libs += this->Namespace; + link_libs += dependee->GetName(); +} + //---------------------------------------------------------------------------- void cmExportBuildFileGenerator diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 0f37626cc..726537bfc 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -45,8 +45,14 @@ protected: virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, std::string const& suffix); - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee); + virtual void HandleMissingTarget(std::string& link_libs, + std::vector& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee); + + void ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee); /** Fill in properties indicating built file locations. */ void SetImportLocationProperty(const char* config, diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index eb19df5e2..8dffae43a 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -11,10 +11,15 @@ ============================================================================*/ #include "cmExportFileGenerator.h" +#include "cmExportSet.h" #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetExport.h" #include "cmVersion.h" #include @@ -123,7 +128,9 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, void cmExportFileGenerator ::SetImportDetailProperties(const char* config, std::string const& suffix, - cmTarget* target, ImportPropertyMap& properties) + cmTarget* target, ImportPropertyMap& properties, + std::vector& missingTargets + ) { // Get the makefile in which to lookup target information. cmMakefile* mf = target->GetMakefile(); @@ -159,13 +166,13 @@ cmExportFileGenerator { this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", - iface->Languages, properties); + iface->Languages, properties, missingTargets); this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties); + iface->Libraries, properties, missingTargets); this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", - iface->SharedDeps, properties); + iface->SharedDeps, properties, missingTargets); if(iface->Multiplicity > 0) { std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY"; @@ -184,7 +191,9 @@ cmExportFileGenerator cmTarget* target, const char* propName, std::vector const& libs, - ImportPropertyMap& properties) + ImportPropertyMap& properties, + std::vector& missingTargets + ) { // Skip the property if there are no libraries. if(libs.empty()) @@ -224,17 +233,7 @@ cmExportFileGenerator } else { - // 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(target, tgt); - } - // Assume the target will be exported by another command. - // Append it with the export namespace. - link_libs += this->Namespace; - link_libs += *li; + this->HandleMissingTarget(link_libs, missingTargets, mf, target, tgt); } } else @@ -250,6 +249,7 @@ cmExportFileGenerator properties[prop] = link_libs; } + //---------------------------------------------------------------------------- void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, const char* config) @@ -380,6 +380,30 @@ cmExportFileGenerator } +//---------------------------------------------------------------------------- +void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os, + const std::vector& missingTargets) +{ + os << "# Make sure the targets which have been exported in some other \n" + "# export set exist.\n"; + for(unsigned int i=0; i& importedLocations); void GenerateImportedFileCheckLoop(std::ostream& os); + void GenerateMissingTargetsCheckCode(std::ostream& os, + const std::vector& missingTargets); // Collect properties with detailed information about targets beyond // their location on disk. void SetImportDetailProperties(const char* config, std::string const& suffix, cmTarget* target, - ImportPropertyMap& properties); + ImportPropertyMap& properties, + std::vector& missingTargets); void SetImportLinkProperty(std::string const& suffix, cmTarget* target, const char* propName, std::vector const& libs, - ImportPropertyMap& properties); + ImportPropertyMap& properties, + std::vector& missingTargets); /** Each subclass knows how to generate its kind of export file. */ virtual bool GenerateMainFile(std::ostream& os) = 0; @@ -80,10 +84,13 @@ protected: const char* config, std::string const& suffix) = 0; - /** Each subclass knows how to complain about a target that is - missing from an export set. */ - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee) = 0; + /** Each subclass knows how to deal with a target that is missing from an + * export set. */ + virtual void HandleMissingTarget(std::string& link_libs, + std::vector& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee) = 0; // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index da14dd787..784173172 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -11,14 +11,19 @@ ============================================================================*/ #include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" +#include "cmExportSetMap.h" #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmInstallExportGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmTargetExport.h" //---------------------------------------------------------------------------- cmExportInstallFileGenerator ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen): - InstallExportGenerator(iegen) + IEGen(iegen) { } @@ -36,10 +41,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { // Create all the imported targets. for(std::vector::const_iterator - tei = this->ExportSet->begin(); - tei != this->ExportSet->end(); ++tei) + tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); + tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { - cmTargetExport* te = *tei; + cmTargetExport const* te = *tei; if(this->ExportedTargets.insert(te->Target).second) { this->GenerateImportTargetCode(os, te->Target); @@ -47,8 +52,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) else { cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\" ...) " - << "includes target \"" << te->Target->GetName() + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\" ...) " << "includes target \"" << te->Target->GetName() << "\" more than once in the export set."; cmSystemTools::Error(e.str().c_str()); return false; @@ -84,7 +90,7 @@ bool cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config) { // Skip configurations not enabled for this export. - if(!this->InstallExportGenerator->InstallsForConfig(config)) + if(!this->IEGen->InstallsForConfig(config)) { return true; } @@ -140,7 +146,7 @@ cmExportInstallFileGenerator { // Add code to compute the installation prefix relative to the // import file location. - const char* installDest = this->InstallExportGenerator->GetDestination(); + const char* installDest = this->IEGen->GetDestination(); if(!cmSystemTools::FileIsFullPath(installDest)) { std::string dest = installDest; @@ -161,11 +167,11 @@ cmExportInstallFileGenerator // Add each target in the set to the export. for(std::vector::const_iterator - tei = this->ExportSet->begin(); - tei != this->ExportSet->end(); ++tei) + tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); + tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { // Collect import properties for this target. - cmTargetExport* te = *tei; + cmTargetExport const* te = *tei; ImportPropertyMap properties; std::set importedLocations; this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator, @@ -185,8 +191,9 @@ cmExportInstallFileGenerator if(!properties.empty()) { // Get the rest of the target details. + std::vector missingTargets; this->SetImportDetailProperties(config, suffix, - te->Target, properties); + te->Target, properties, missingTargets); // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -195,6 +202,7 @@ cmExportInstallFileGenerator // properties); // Generate code in the export file. + this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, te->Target, properties); this->GenerateImportedFileChecksCode(os, te->Target, properties, importedLocations); @@ -304,14 +312,82 @@ cmExportInstallFileGenerator } } +//---------------------------------------------------------------------------- +void +cmExportInstallFileGenerator::HandleMissingTarget( + std::string& link_libs, std::vector& missingTargets, + cmMakefile* mf, cmTarget* depender, cmTarget* dependee) +{ + 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 += name; + link_libs += missingTarget; + missingTargets.push_back(missingTarget); + } + else + { + // We are not appending, so all exported targets should be + // known here. This is probably user-error. + this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); + } +} + +//---------------------------------------------------------------------------- +std::vector +cmExportInstallFileGenerator +::FindNamespaces(cmMakefile* mf, const std::string& name) +{ + std::vector namespaces; + cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator(); + const cmExportSetMap& exportSets = gg->GetExportSets(); + + for(cmExportSetMap::const_iterator expIt = exportSets.begin(); + expIt != exportSets.end(); + ++expIt) + { + const cmExportSet* exportSet = expIt->second; + std::vector const* targets = + exportSet->GetTargetExports(); + + bool containsTarget = false; + for(unsigned int i=0; isize(); i++) + { + if (name == (*targets)[i]->Target->GetName()) + { + containsTarget = true; + break; + } + } + + if (containsTarget) + { + std::vector const* installs = + exportSet->GetInstallations(); + for(unsigned int i=0; isize(); i++) + { + namespaces.push_back((*installs)[i]->GetNamespace()); + } + } + } + + return namespaces; +} + + //---------------------------------------------------------------------------- void cmExportInstallFileGenerator ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen) { - const char* installDest = this->InstallExportGenerator->GetDestination(); + const char* installDest = this->IEGen->GetDestination(); cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\") given absolute " + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\") given absolute " << "DESTINATION \"" << installDest << "\" but the export " << "references an installation of target \"" << itgen->GetTarget()->GetName() << "\" which has relative " @@ -322,12 +398,24 @@ cmExportInstallFileGenerator //---------------------------------------------------------------------------- void cmExportInstallFileGenerator -::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee) +::ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee, + int occurrences) { cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\" ...) " + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\" ...) " << "includes target \"" << depender->GetName() - << "\" which requires target \"" << dependee->GetName() - << "\" that is not in the export set."; + << "\" which requires target \"" << dependee->GetName() << "\" "; + if (occurrences == 0) + { + e << "that is not in the export set."; + } + else + { + e << "that is not in this export set, but " << occurrences + << " times in others."; + } cmSystemTools::Error(e.str().c_str()); } diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index fb678e891..e719eccd5 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -18,6 +18,7 @@ class cmInstallExportGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; class cmTargetExport; +class cmExportSet; /** \class cmExportInstallFileGenerator * \brief Generate a file exporting targets from an install tree. @@ -40,15 +41,6 @@ public: files. */ cmExportInstallFileGenerator(cmInstallExportGenerator* iegen); - /** Set the name of the export associated with the files. This is - the name given to the install(EXPORT) command mode. */ - void SetName(const char* name) { this->Name = name; } - - /** Set the set of targets to be exported. These are the targets - associated with the export name. */ - void SetExportSet(std::vector const* eSet) - { this->ExportSet = eSet; } - /** Get the per-config file generated for each configuraiton. This maps from the configuration name to the file temporary location for installation. */ @@ -65,8 +57,19 @@ protected: virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, std::string const& suffix); - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee); + virtual void HandleMissingTarget(std::string& link_libs, + std::vector& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee); + + void ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee, + int occurrences); + + std::vector FindNamespaces(cmMakefile* mf, + const std::string& name); + /** Generate a per-configuration file for the targets. */ bool GenerateImportFileConfig(const char* config); @@ -81,9 +84,7 @@ protected: void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen); - cmInstallExportGenerator* InstallExportGenerator; - std::string Name; - std::vector const* ExportSet; + cmInstallExportGenerator* IEGen; std::string ImportPrefix; @@ -91,34 +92,4 @@ protected: std::map ConfigImportFiles; }; -/* - cmTargetExport is used in cmGlobalGenerator to collect the install - generators for targets associated with an export. -*/ -class cmTargetExport -{ -public: - cmTargetExport(cmTarget* tgt, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runtime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* headers - ) : Target(tgt), ArchiveGenerator(archive), - RuntimeGenerator(runtime), LibraryGenerator(library), - FrameworkGenerator(framework), BundleGenerator(bundle), - HeaderGenerator(headers) {} - - cmTarget* Target; - cmInstallTargetGenerator* ArchiveGenerator; - cmInstallTargetGenerator* RuntimeGenerator; - cmInstallTargetGenerator* LibraryGenerator; - cmInstallTargetGenerator* FrameworkGenerator; - cmInstallTargetGenerator* BundleGenerator; - cmInstallFilesGenerator* HeaderGenerator; -private: - cmTargetExport(); -}; - #endif diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx new file mode 100644 index 000000000..33b063037 --- /dev/null +++ b/Source/cmExportSet.cxx @@ -0,0 +1,32 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExportSet.h" +#include "cmTargetExport.h" + +cmExportSet::~cmExportSet() +{ + for(unsigned int i = 0; i < this->TargetExports.size(); ++ i) + { + delete this->TargetExports[i]; + } +} + +void cmExportSet::AddTargetExport(cmTargetExport* te) +{ + this->TargetExports.push_back(te); +} + +void cmExportSet::AddInstallation(cmInstallExportGenerator const* installation) +{ + this->Installations.push_back(installation); +} diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h new file mode 100644 index 000000000..a57aa1204 --- /dev/null +++ b/Source/cmExportSet.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportSet_h +#define cmExportSet_h + +#include "cmSystemTools.h" +class cmTargetExport; +class cmInstallExportGenerator; + +/// A set of targets that were installed with the same EXPORT parameter. +class cmExportSet +{ +public: + /// Construct an empty export set named \a name + cmExportSet(const std::string &name) : Name(name) {} + /// Destructor + ~cmExportSet(); + + void AddTargetExport(cmTargetExport* tgt); + + void AddInstallation(cmInstallExportGenerator const* installation); + + std::string const& GetName() const { return this->Name; } + + std::vector const* GetTargetExports() const + { return &this->TargetExports; } + + std::vector const* GetInstallations() const + { return &this->Installations; } + +private: + std::vector TargetExports; + std::string Name; + std::vector Installations; +}; + +#endif diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx new file mode 100644 index 000000000..96fdb3e4f --- /dev/null +++ b/Source/cmExportSetMap.cxx @@ -0,0 +1,34 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExportSetMap.h" +#include "cmExportSet.h" + +cmExportSet* cmExportSetMap::operator[](const std::string &name) +{ + std::map::iterator it = this->find(name); + if (it == this->end()) // Export set not found + { + it = this->insert(std::make_pair(name, new cmExportSet(name))).first; + } + return it->second; +} + +cmExportSetMap::~cmExportSetMap() +{ + for(std::map::iterator it = this->begin(); + it != this->end(); + ++ it) + { + delete it->second; + } +} diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h new file mode 100644 index 000000000..4663c5538 --- /dev/null +++ b/Source/cmExportSetMap.h @@ -0,0 +1,33 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportSetMap_h +#define cmExportSetMap_h + +#include "cmSystemTools.h" +class cmExportSet; + +/// A name -> cmExportSet map with overloaded operator[]. +class cmExportSetMap : public std::map +{ +public: + /** \brief Overloaded operator[]. + * + * The operator is overloaded because cmExportSet has no default constructor: + * we do not want unnamed export sets. + */ + cmExportSet* operator[](const std::string &name); + + /// Overloaded destructor deletes all member export sets. + ~cmExportSetMap(); +}; + +#endif diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index be47f95d4..470cecabe 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -840,6 +840,8 @@ bool cmFindPackageCommand //---------------------------------------------------------------------------- void cmFindPackageCommand::SetModuleVariables(const std::string& components) { + this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name.c_str()); + // Store the list of components. std::string components_var = this->Name + "_FIND_COMPONENTS"; this->AddFindDefinition(components_var.c_str(), components.c_str()); @@ -1016,6 +1018,9 @@ bool cmFindPackageCommand::HandlePackageMode() std::string foundVar = this->Name; foundVar += "_FOUND"; + std::string notFoundMessageVar = this->Name; + notFoundMessageVar += "_NOT_FOUND_MESSAGE"; + std::string notFoundMessage; // If the directory for the config file was found, try to read the file. bool result = true; @@ -1033,6 +1038,7 @@ bool cmFindPackageCommand::HandlePackageMode() // has set Foo_FOUND to FALSE itself: this->Makefile->RemoveDefinition(foundVar.c_str()); } + this->Makefile->RemoveDefinition(notFoundMessageVar.c_str()); // Set the version variables before loading the config file. // It may override them. @@ -1051,6 +1057,8 @@ bool cmFindPackageCommand::HandlePackageMode() // we get here if the Config file has set Foo_FOUND actively to FALSE found = false; configFileSetFOUNDFalse = true; + notFoundMessage = this->Makefile->GetSafeDefinition( + notFoundMessageVar.c_str()); } } else @@ -1071,6 +1079,10 @@ bool cmFindPackageCommand::HandlePackageMode() " " << this->FileFound << "\n" "but it set " << foundVar << " to FALSE so package \"" << this->Name << "\" is considered to be NOT FOUND."; + if (!notFoundMessage.empty()) + { + e << " Reason given by package: \n" << notFoundMessage << "\n"; + } } // If there are files in ConsideredConfigs, it means that FooConfig.cmake // have been found, but they didn't have appropriate versions. diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ac75933c2..bdd34612e 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -21,7 +21,7 @@ #include "cmQtAutomoc.h" #include "cmSourceFile.h" #include "cmVersion.h" -#include "cmExportInstallFileGenerator.h" +#include "cmTargetExport.h" #include "cmComputeTargetDepends.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -76,12 +76,12 @@ cmGlobalGenerator::~cmGlobalGenerator() } this->ClearGeneratorTargets(); - this->ClearExportSets(); } void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang, cmMakefile *mf, - bool optional) { + bool optional) +{ std::string langComp = "CMAKE_"; langComp += lang; langComp += "_COMPILER"; @@ -817,7 +817,7 @@ void cmGlobalGenerator::Configure() { this->FirstTimeProgress = 0.0f; this->ClearGeneratorTargets(); - this->ClearExportSets(); + this->ExportSets.clear(); // Delete any existing cmLocalGenerators unsigned int i; for (i = 0; i < this->LocalGenerators.size(); ++i) @@ -1489,52 +1489,6 @@ void cmGlobalGenerator::AddInstallComponent(const char* component) } } -void cmGlobalGenerator::AddTargetToExports(const char* exportSetName, - cmTarget* target, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runTime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* headers) -{ - if ((exportSetName) && (*exportSetName) && (target)) - { - cmTargetExport* te = new cmTargetExport(target, archive, runTime, library, - framework, bundle, headers); - this->ExportSets[exportSetName].push_back(te); - } -} - -//---------------------------------------------------------------------------- -void cmGlobalGenerator::ClearExportSets() -{ - for(std::map >::iterator - setIt = this->ExportSets.begin(); - setIt != this->ExportSets.end(); ++setIt) - { - for(unsigned int i = 0; i < setIt->second.size(); ++i) - { - delete setIt->second[i]; - } - } - this->ExportSets.clear(); -} - -const std::vector* cmGlobalGenerator::GetExportSet( - const char* name) const -{ - std::map >::const_iterator - exportSetIt = this->ExportSets.find(name); - if (exportSetIt != this->ExportSets.end()) - { - return &exportSetIt->second; - } - - return 0; -} - - void cmGlobalGenerator::EnableInstallTarget() { this->InstallTargetEnabled = true; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 2f4ebc35a..0aab2d63e 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -18,14 +18,15 @@ #include "cmTarget.h" // For cmTargets #include "cmTargetDepend.h" // For cmTargetDependSet #include "cmSystemTools.h" // for cmSystemTools::OutputOption +#include "cmExportSetMap.h" // For cmExportSetMap #include "cmGeneratorTarget.h" + class cmake; class cmGeneratorTarget; class cmMakefile; class cmLocalGenerator; class cmExternalMakefileProjectGenerator; class cmTarget; -class cmTargetExport; class cmInstallTargetGenerator; class cmInstallFilesGenerator; @@ -128,8 +129,8 @@ public: void SetCMakeInstance(cmake *cm); ///! Get the CMake instance - cmake *GetCMakeInstance() { return this->CMakeInstance; }; - const cmake *GetCMakeInstance() const { return this->CMakeInstance; }; + cmake *GetCMakeInstance() { return this->CMakeInstance; } + const cmake *GetCMakeInstance() const { return this->CMakeInstance; } void SetConfiguredFilesPath(cmGlobalGenerator* gen); const std::vector& GetLocalGenerators() const { @@ -152,18 +153,9 @@ public: void AddInstallComponent(const char* component); const std::set* GetInstallComponents() const - { return &InstallComponents; } + { return &this->InstallComponents; } - ///! Add one installed target to the sets of the exports - void AddTargetToExports(const char* exportSet, cmTarget* target, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runTime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* publicHeaders); - ///! Get the export target set with the given name - const std::vector* GetExportSet(const char* name) const; + cmExportSetMap& GetExportSets() {return this->ExportSets;} /** Add a file to the manifest of generated targets for a configuration. */ void AddToManifest(const char* config, std::string const& f); @@ -223,7 +215,7 @@ public: /** Get the manifest of all targets that will be built for each configuration. This is valid during generation only. */ cmTargetManifest const& GetTargetManifest() const - { return this->TargetManifest; } + { return this->TargetManifest; } /** Get the content of a directory. Directory listings are loaded from disk at most once and cached. During the generation step @@ -329,15 +321,13 @@ protected: cmLocalGenerator* CurrentLocalGenerator; // map from project name to vector of local generators in that project std::map > ProjectMap; - std::map > - LocalGeneratorToTargetMap; + std::map > LocalGeneratorToTargetMap; // Set of named installation components requested by the project. std::set InstallComponents; bool InstallTargetEnabled; // Sets of named target exports - std::map > ExportSets; - void ClearExportSets(); + cmExportSetMap ExportSets; // Manifest of all targets that will be built for each configuration. // This is computed just before local generators generate. diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 401673460..dcd418b45 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -17,6 +17,8 @@ #include "cmInstallTargetGenerator.h" #include "cmInstallExportGenerator.h" #include "cmInstallCommandArguments.h" +#include "cmTargetExport.h" +#include "cmExportSet.h" #include @@ -735,11 +737,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) // this is not a namelink-only rule. if(!exports.GetString().empty() && !namelinkOnly) { + cmTargetExport *te = new cmTargetExport; + te->Target = ⌖ + te->ArchiveGenerator = archiveGenerator; + te->BundleGenerator = bundleGenerator; + te->FrameworkGenerator = frameworkGenerator; + te->HeaderGenerator = publicHeaderGenerator; + te->LibraryGenerator = libraryGenerator; + te->RuntimeGenerator = runtimeGenerator; this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->AddTargetToExports(exports.GetCString(), &target, - archiveGenerator, runtimeGenerator, - libraryGenerator, frameworkGenerator, - bundleGenerator, publicHeaderGenerator); + ->GetExportSets()[exports.GetString()]->AddTargetExport(te); } } @@ -1264,7 +1271,9 @@ bool cmInstallCommand::HandleExportMode(std::vector const& args) // Create the export install generator. cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( - exp.GetCString(), ica.GetDestination().c_str(), + this->Makefile->GetLocalGenerator() + ->GetGlobalGenerator()->GetExportSets()[exp.GetString()], + ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), fname.c_str(), name_space.GetCString(), this->Makefile); diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 28a19d740..0a645a8fa 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -23,10 +23,11 @@ #include "cmInstallFilesGenerator.h" #include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" //---------------------------------------------------------------------------- cmInstallExportGenerator::cmInstallExportGenerator( - const char* name, + cmExportSet* exportSet, const char* destination, const char* file_permissions, std::vector const& configurations, @@ -34,13 +35,14 @@ cmInstallExportGenerator::cmInstallExportGenerator( const char* filename, const char* name_space, cmMakefile* mf) :cmInstallGenerator(destination, configurations, component) - ,Name(name) + ,ExportSet(exportSet) ,FilePermissions(file_permissions) ,FileName(filename) ,Namespace(name_space) ,Makefile(mf) { this->EFGen = new cmExportInstallFileGenerator(this); + exportSet->AddInstallation(this); } //---------------------------------------------------------------------------- @@ -113,16 +115,12 @@ void cmInstallExportGenerator::ComputeTempDir() //---------------------------------------------------------------------------- void cmInstallExportGenerator::GenerateScript(std::ostream& os) { - // Get the export set requested. - ExportSet const* exportSet = - this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->GetExportSet(this->Name.c_str()); - // Skip empty sets. - if(!exportSet) + if(ExportSet->GetTargetExports()->empty()) { cmOStringStream e; - e << "INSTALL(EXPORT) given unknown export \"" << this->Name << "\""; + e << "INSTALL(EXPORT) given unknown export \"" + << ExportSet->GetName() << "\""; cmSystemTools::Error(e.str().c_str()); return; } @@ -137,8 +135,6 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os) this->MainImportFile += this->FileName; // Generate the import file for this export set. - this->EFGen->SetName(this->Name.c_str()); - this->EFGen->SetExportSet(exportSet); this->EFGen->SetExportFile(this->MainImportFile.c_str()); this->EFGen->SetNamespace(this->Namespace.c_str()); if(this->ConfigurationTypes->empty()) diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index 1ff6e38e6..ee92906fe 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -17,8 +17,7 @@ class cmExportInstallFileGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; -class cmTarget; -class cmTargetExport; +class cmExportSet; class cmMakefile; /** \class cmInstallExportGenerator @@ -27,24 +26,27 @@ class cmMakefile; class cmInstallExportGenerator: public cmInstallGenerator { public: - cmInstallExportGenerator(const char* name, + cmInstallExportGenerator(cmExportSet* exportSet, const char* dest, const char* file_permissions, const std::vector& configurations, const char* component, const char* filename, const char* name_space, cmMakefile* mf); ~cmInstallExportGenerator(); -protected: - typedef std::vector ExportSet; + cmExportSet* GetExportSet() {return this->ExportSet;} + + const std::string& GetNamespace() const { return this->Namespace; } + +protected: virtual void GenerateScript(std::ostream& os); virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); - void GenerateImportFile(ExportSet const* exportSet); - void GenerateImportFile(const char* config, ExportSet const* exportSet); + void GenerateImportFile(cmExportSet const* exportSet); + void GenerateImportFile(const char* config, cmExportSet const* exportSet); void ComputeTempDir(); - std::string Name; + cmExportSet* ExportSet; std::string FilePermissions; std::string FileName; std::string Namespace; diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h new file mode 100644 index 000000000..c9d87fb7e --- /dev/null +++ b/Source/cmTargetExport.h @@ -0,0 +1,39 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmTargetExport_h +#define cmTargetExport_h + +class cmTarget; +class cmInstallTargetGenerator; +class cmInstallFilesGenerator; + +/** \brief A member of an ExportSet + * + * This struct holds pointers to target and all relevant generators. + */ +class cmTargetExport +{ +public: + cmTarget* Target; ///< The target + + ///@name Generators + ///@{ + cmInstallTargetGenerator* ArchiveGenerator; + cmInstallTargetGenerator* RuntimeGenerator; + cmInstallTargetGenerator* LibraryGenerator; + cmInstallTargetGenerator* FrameworkGenerator; + cmInstallTargetGenerator* BundleGenerator; + cmInstallFilesGenerator* HeaderGenerator; + ///@} +}; + +#endif diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index f118c30de..e19ab88de 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -87,6 +87,18 @@ target_link_libraries(testLibCycleA testLibCycleB) target_link_libraries(testLibCycleB testLibCycleA) set_property(TARGET testLibCycleA PROPERTY LINK_INTERFACE_MULTIPLICITY 3) +# Test exporting dependent libraries into different exports +add_library(testLibRequired testLibRequired.c) +add_library(testLibDepends testLibDepends.c) +target_link_libraries(testLibDepends testLibRequired) + +install(TARGETS testLibRequired EXPORT RequiredExp DESTINATION lib ) +install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired) + +install(TARGETS testLibDepends EXPORT DependsExp DESTINATION lib ) +install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends) + + # Install and export from install tree. install( TARGETS diff --git a/Tests/ExportImport/Export/testLibDepends.c b/Tests/ExportImport/Export/testLibDepends.c new file mode 100644 index 000000000..2849b336d --- /dev/null +++ b/Tests/ExportImport/Export/testLibDepends.c @@ -0,0 +1,4 @@ + +extern int testLibRequired(void); + +int testLibDepends(void) { return testLibRequired(); } diff --git a/Tests/ExportImport/Export/testLibRequired.c b/Tests/ExportImport/Export/testLibRequired.c new file mode 100644 index 000000000..e126d44e7 --- /dev/null +++ b/Tests/ExportImport/Export/testLibRequired.c @@ -0,0 +1 @@ +int testLibRequired(void) { return 0; } diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 650af6adf..884179225 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -4,6 +4,10 @@ include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake) # Import targets from the exported install tree. include(${CMAKE_INSTALL_PREFIX}/lib/exp/exp.cmake) +# Import two exports, where the Depends one depends on an exported target from the Required one: +include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredConfig.cmake) +include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsConfig.cmake) + # Try referencing an executable imported from the install tree. add_custom_command( OUTPUT ${Import_BINARY_DIR}/exp_generated.c diff --git a/bootstrap b/bootstrap index 1466a4001..713f01f2b 100755 --- a/bootstrap +++ b/bootstrap @@ -199,6 +199,8 @@ CMAKE_CXX_SOURCES="\ cmMakefile \ cmExportFileGenerator \ cmExportInstallFileGenerator \ + cmExportSet \ + cmExportSetMap \ cmInstallDirectoryGenerator \ cmGeneratedFileStream \ cmGeneratorTarget \