| /*============================================================================ |
| 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. |
| ============================================================================*/ |
| #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 "cmComputeLinkInformation.h" |
| |
| #include <cmsys/auto_ptr.hxx> |
| #include <assert.h> |
| |
| //---------------------------------------------------------------------------- |
| cmExportFileGenerator::cmExportFileGenerator() |
| { |
| this->AppendMode = false; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::AddConfiguration(const char* config) |
| { |
| this->Configurations.push_back(config); |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::SetExportFile(const char* mainFile) |
| { |
| this->MainImportFile = mainFile; |
| this->FileDir = |
| cmSystemTools::GetFilenamePath(this->MainImportFile); |
| this->FileBase = |
| cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile); |
| this->FileExt = |
| cmSystemTools::GetFilenameLastExtension(this->MainImportFile); |
| } |
| |
| //---------------------------------------------------------------------------- |
| bool cmExportFileGenerator::GenerateImportFile() |
| { |
| // Open the output file to generate it. |
| cmsys::auto_ptr<std::ofstream> foutPtr; |
| if(this->AppendMode) |
| { |
| // Open for append. |
| cmsys::auto_ptr<std::ofstream> |
| ap(new std::ofstream(this->MainImportFile.c_str(), std::ios::app)); |
| foutPtr = ap; |
| } |
| else |
| { |
| // Generate atomically and with copy-if-different. |
| cmsys::auto_ptr<cmGeneratedFileStream> |
| ap(new cmGeneratedFileStream(this->MainImportFile.c_str(), true)); |
| ap->SetCopyIfDifferent(true); |
| foutPtr = ap; |
| } |
| if(!foutPtr.get() || !*foutPtr) |
| { |
| std::string se = cmSystemTools::GetLastSystemError(); |
| cmOStringStream e; |
| e << "cannot write to file \"" << this->MainImportFile |
| << "\": " << se; |
| cmSystemTools::Error(e.str().c_str()); |
| return false; |
| } |
| std::ostream& os = *foutPtr; |
| |
| // Protect that file against use with older CMake versions. |
| os << "# Generated by CMake " << cmVersion::GetCMakeVersion() << "\n\n"; |
| os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n" |
| << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n" |
| << "endif()\n"; |
| |
| // Isolate the file policy level. |
| // We use 2.6 here instead of the current version because newer |
| // versions of CMake should be able to export files imported by 2.6 |
| // until the import format changes. |
| os << "cmake_policy(PUSH)\n" |
| << "cmake_policy(VERSION 2.6)\n"; |
| |
| // Start with the import file header. |
| this->GenerateImportHeaderCode(os); |
| |
| // Create all the imported targets. |
| bool result = this->GenerateMainFile(os); |
| |
| // End with the import file footer. |
| this->GenerateImportFooterCode(os); |
| os << "cmake_policy(POP)\n"; |
| |
| return result; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, |
| const char* config, |
| std::vector<std::string> &missingTargets) |
| { |
| // Construct the property configuration suffix. |
| std::string suffix = "_"; |
| if(config && *config) |
| { |
| suffix += cmSystemTools::UpperCase(config); |
| } |
| else |
| { |
| suffix += "NOCONFIG"; |
| } |
| |
| // Generate the per-config target information. |
| this->GenerateImportTargetsConfig(os, config, suffix, missingTargets); |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, |
| cmTarget *target, |
| ImportPropertyMap &properties) |
| { |
| const char *input = target->GetProperty(propName); |
| if (input) |
| { |
| properties[propName] = input; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, |
| const char *outputName, |
| cmTarget *target, |
| cmGeneratorExpression::PreprocessContext preprocessRule, |
| ImportPropertyMap &properties, |
| std::vector<std::string> &missingTargets) |
| { |
| const char *input = target->GetProperty(propName); |
| if (input) |
| { |
| if (!*input) |
| { |
| // Set to empty |
| properties[outputName] = ""; |
| return; |
| } |
| |
| std::string prepro = cmGeneratorExpression::Preprocess(input, |
| preprocessRule); |
| if (!prepro.empty()) |
| { |
| this->ResolveTargetsInGeneratorExpressions(prepro, target, |
| missingTargets); |
| properties[outputName] = prepro; |
| } |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| static bool isSubDirectory(const char* a, const char* b) |
| { |
| return (cmSystemTools::ComparePath(a, b) || |
| cmSystemTools::IsSubDirectory(a, b)); |
| } |
| |
| //---------------------------------------------------------------------------- |
| static bool checkInterfaceDirs(const std::string &prepro, |
| cmTarget *target) |
| { |
| const char* installDir = |
| target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); |
| const char* topSourceDir = target->GetMakefile()->GetHomeDirectory(); |
| const char* topBinaryDir = target->GetMakefile()->GetHomeOutputDirectory(); |
| |
| std::vector<std::string> parts; |
| cmGeneratorExpression::Split(prepro, parts); |
| |
| const bool inSourceBuild = strcmp(topSourceDir, topBinaryDir) == 0; |
| |
| for(std::vector<std::string>::iterator li = parts.begin(); |
| li != parts.end(); ++li) |
| { |
| if (cmGeneratorExpression::Find(*li) != std::string::npos) |
| { |
| continue; |
| } |
| if (strncmp(li->c_str(), "${_IMPORT_PREFIX}", 17) == 0) |
| { |
| continue; |
| } |
| if (!cmSystemTools::FileIsFullPath(li->c_str())) |
| { |
| cmOStringStream e; |
| e << "Target \"" << target->GetName() << "\" " |
| "INTERFACE_INCLUDE_DIRECTORIES property contains relative path:\n" |
| " \"" << *li << "\""; |
| target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, |
| e.str().c_str()); |
| return false; |
| } |
| if (isSubDirectory(li->c_str(), installDir)) |
| { |
| continue; |
| } |
| if (isSubDirectory(li->c_str(), topBinaryDir)) |
| { |
| cmOStringStream e; |
| e << "Target \"" << target->GetName() << "\" " |
| "INTERFACE_INCLUDE_DIRECTORIES property contains path:\n" |
| " \"" << *li << "\"\nwhich is prefixed in the build directory."; |
| target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, |
| e.str().c_str()); |
| return false; |
| } |
| if (!inSourceBuild) |
| { |
| if (isSubDirectory(li->c_str(), topSourceDir)) |
| { |
| cmOStringStream e; |
| e << "Target \"" << target->GetName() << "\" " |
| "INTERFACE_INCLUDE_DIRECTORIES property contains path:\n" |
| " \"" << *li << "\"\nwhich is prefixed in the source directory."; |
| target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, |
| e.str().c_str()); |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( |
| cmTarget *target, |
| cmGeneratorExpression::PreprocessContext preprocessRule, |
| ImportPropertyMap &properties, |
| std::vector<std::string> &missingTargets) |
| { |
| assert(preprocessRule == cmGeneratorExpression::InstallInterface); |
| |
| const char *propName = "INTERFACE_INCLUDE_DIRECTORIES"; |
| const char *input = target->GetProperty(propName); |
| if (!input) |
| { |
| return; |
| } |
| if (!*input) |
| { |
| // Set to empty |
| properties[propName] = ""; |
| return; |
| } |
| |
| std::string prepro = cmGeneratorExpression::Preprocess(input, |
| preprocessRule); |
| if (!prepro.empty()) |
| { |
| this->ResolveTargetsInGeneratorExpressions(prepro, target, |
| missingTargets); |
| |
| if (!checkInterfaceDirs(prepro, target)) |
| { |
| return; |
| } |
| properties[propName] = prepro; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, |
| cmTarget *target, |
| cmGeneratorExpression::PreprocessContext preprocessRule, |
| ImportPropertyMap &properties, |
| std::vector<std::string> &missingTargets) |
| { |
| this->PopulateInterfaceProperty(propName, propName, target, preprocessRule, |
| properties, missingTargets); |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| void getPropertyContents(cmTarget *tgt, const char *prop, |
| std::set<std::string> &ifaceProperties) |
| { |
| const char *p = tgt->GetProperty(prop); |
| if (!p) |
| { |
| return; |
| } |
| std::vector<std::string> content; |
| cmSystemTools::ExpandListArgument(p, content); |
| for (std::vector<std::string>::const_iterator ci = content.begin(); |
| ci != content.end(); ++ci) |
| { |
| ifaceProperties.insert(*ci); |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void getCompatibleInterfaceProperties(cmTarget *target, |
| std::set<std::string> &ifaceProperties, |
| const char *config) |
| { |
| cmComputeLinkInformation *info = target->GetLinkInformation(config); |
| |
| const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); |
| |
| for(cmComputeLinkInformation::ItemVector::const_iterator li = |
| deps.begin(); |
| li != deps.end(); ++li) |
| { |
| if (!li->Target) |
| { |
| continue; |
| } |
| getPropertyContents(li->Target, |
| "COMPATIBLE_INTERFACE_BOOL", |
| ifaceProperties); |
| getPropertyContents(li->Target, |
| "COMPATIBLE_INTERFACE_STRING", |
| ifaceProperties); |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( |
| cmTarget *target, |
| ImportPropertyMap &properties) |
| { |
| this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", |
| target, properties); |
| this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", |
| target, properties); |
| |
| std::set<std::string> ifaceProperties; |
| |
| getPropertyContents(target, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties); |
| getPropertyContents(target, "COMPATIBLE_INTERFACE_STRING", ifaceProperties); |
| |
| getCompatibleInterfaceProperties(target, ifaceProperties, 0); |
| |
| std::vector<std::string> configNames; |
| target->GetMakefile()->GetConfigurations(configNames); |
| |
| for (std::vector<std::string>::const_iterator ci = configNames.begin(); |
| ci != configNames.end(); ++ci) |
| { |
| getCompatibleInterfaceProperties(target, ifaceProperties, ci->c_str()); |
| } |
| |
| for (std::set<std::string>::const_iterator it = ifaceProperties.begin(); |
| it != ifaceProperties.end(); ++it) |
| { |
| this->PopulateInterfaceProperty(("INTERFACE_" + *it).c_str(), |
| target, properties); |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target, |
| std::ostream& os, |
| const ImportPropertyMap &properties) |
| { |
| if (!properties.empty()) |
| { |
| std::string targetName = this->Namespace; |
| targetName += target->GetName(); |
| os << "set_target_properties(" << targetName << " PROPERTIES\n"; |
| for(ImportPropertyMap::const_iterator pi = properties.begin(); |
| pi != properties.end(); ++pi) |
| { |
| os << " " << pi->first << " \"" << pi->second << "\"\n"; |
| } |
| os << ")\n\n"; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| bool |
| cmExportFileGenerator::AddTargetNamespace(std::string &input, |
| cmTarget* target, |
| std::vector<std::string> &missingTargets) |
| { |
| cmMakefile *mf = target->GetMakefile(); |
| |
| cmTarget *tgt = mf->FindTargetToUse(input.c_str()); |
| if (!tgt) |
| { |
| return false; |
| } |
| |
| if(tgt->IsImported()) |
| { |
| return true; |
| } |
| if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) |
| { |
| input = this->Namespace + input; |
| } |
| else |
| { |
| std::string namespacedTarget; |
| this->HandleMissingTarget(namespacedTarget, missingTargets, |
| mf, target, tgt); |
| if (!namespacedTarget.empty()) |
| { |
| input = namespacedTarget; |
| } |
| } |
| return true; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( |
| std::string &input, |
| cmTarget* target, |
| std::vector<std::string> &missingTargets, |
| FreeTargetsReplace replace) |
| { |
| if (replace == NoReplaceFreeTargets) |
| { |
| this->ResolveTargetsInGeneratorExpression(input, target, missingTargets); |
| return; |
| } |
| std::vector<std::string> parts; |
| cmGeneratorExpression::Split(input, parts); |
| |
| std::string sep; |
| input = ""; |
| for(std::vector<std::string>::iterator li = parts.begin(); |
| li != parts.end(); ++li) |
| { |
| if (cmGeneratorExpression::Find(*li) == std::string::npos) |
| { |
| this->AddTargetNamespace(*li, target, missingTargets); |
| } |
| else |
| { |
| this->ResolveTargetsInGeneratorExpression( |
| *li, |
| target, |
| missingTargets); |
| } |
| input += sep + *li; |
| sep = ";"; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator::ResolveTargetsInGeneratorExpression( |
| std::string &input, |
| cmTarget* target, |
| std::vector<std::string> &missingTargets) |
| { |
| std::string::size_type pos = 0; |
| std::string::size_type lastPos = pos; |
| |
| cmMakefile *mf = target->GetMakefile(); |
| |
| while((pos = input.find("$<TARGET_PROPERTY:", lastPos)) != input.npos) |
| { |
| std::string::size_type nameStartPos = pos + |
| sizeof("$<TARGET_PROPERTY:") - 1; |
| std::string::size_type closePos = input.find(">", nameStartPos); |
| std::string::size_type commaPos = input.find(",", nameStartPos); |
| std::string::size_type nextOpenPos = input.find("$<", nameStartPos); |
| if (commaPos == input.npos // Implied 'this' target |
| || closePos == input.npos // Imcomplete expression. |
| || closePos < commaPos // Implied 'this' target |
| || nextOpenPos < commaPos) // Non-literal |
| { |
| lastPos = nameStartPos; |
| continue; |
| } |
| |
| std::string targetName = input.substr(nameStartPos, |
| commaPos - nameStartPos); |
| |
| if (this->AddTargetNamespace(targetName, target, missingTargets)) |
| { |
| input.replace(nameStartPos, commaPos - nameStartPos, targetName); |
| } |
| lastPos = nameStartPos + targetName.size() + 1; |
| } |
| |
| std::string errorString; |
| pos = 0; |
| lastPos = pos; |
| while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos) |
| { |
| std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1; |
| std::string::size_type endPos = input.find(">", nameStartPos); |
| if (endPos == input.npos) |
| { |
| errorString = "$<TARGET_NAME:...> expression incomplete"; |
| break; |
| } |
| std::string targetName = input.substr(nameStartPos, |
| endPos - nameStartPos); |
| if(targetName.find("$<") != input.npos) |
| { |
| errorString = "$<TARGET_NAME:...> requires its parameter to be a " |
| "literal."; |
| break; |
| } |
| if (!this->AddTargetNamespace(targetName, target, missingTargets)) |
| { |
| errorString = "$<TARGET_NAME:...> requires its parameter to be a " |
| "reachable target."; |
| break; |
| } |
| input.replace(pos, endPos - pos + 1, targetName); |
| lastPos = endPos; |
| } |
| |
| this->ReplaceInstallPrefix(input); |
| |
| if (!errorString.empty()) |
| { |
| mf->IssueMessage(cmake::FATAL_ERROR, errorString); |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator::ReplaceInstallPrefix(std::string &) |
| { |
| // Do nothing |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::SetImportLinkInterface(const char* config, std::string const& suffix, |
| cmGeneratorExpression::PreprocessContext preprocessRule, |
| cmTarget* target, ImportPropertyMap& properties, |
| std::vector<std::string>& missingTargets) |
| { |
| // Add the transitive link dependencies for this configuration. |
| cmTarget::LinkInterface const* iface = target->GetLinkInterface(config, |
| target); |
| if (!iface) |
| { |
| return; |
| } |
| |
| if (iface->ImplementationIsInterface) |
| { |
| this->SetImportLinkProperty(suffix, target, |
| "IMPORTED_LINK_INTERFACE_LIBRARIES", |
| iface->Libraries, properties, missingTargets); |
| return; |
| } |
| |
| const char *propContent; |
| |
| if (const char *prop_suffixed = target->GetProperty( |
| ("LINK_INTERFACE_LIBRARIES" + suffix).c_str())) |
| { |
| propContent = prop_suffixed; |
| } |
| else if (const char *prop = target->GetProperty( |
| "LINK_INTERFACE_LIBRARIES")) |
| { |
| propContent = prop; |
| } |
| else |
| { |
| return; |
| } |
| |
| if (!*propContent) |
| { |
| properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = ""; |
| return; |
| } |
| |
| std::string prepro = cmGeneratorExpression::Preprocess(propContent, |
| preprocessRule); |
| if (!prepro.empty()) |
| { |
| this->ResolveTargetsInGeneratorExpressions(prepro, target, |
| missingTargets, |
| ReplaceFreeTargets); |
| properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::SetImportDetailProperties(const char* config, std::string const& suffix, |
| cmTarget* target, ImportPropertyMap& properties, |
| std::vector<std::string>& missingTargets |
| ) |
| { |
| // Get the makefile in which to lookup target information. |
| cmMakefile* mf = target->GetMakefile(); |
| |
| // Add the soname for unix shared libraries. |
| if(target->GetType() == cmTarget::SHARED_LIBRARY || |
| target->GetType() == cmTarget::MODULE_LIBRARY) |
| { |
| // Check whether this is a DLL platform. |
| bool dll_platform = |
| (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW")); |
| if(!dll_platform) |
| { |
| std::string prop; |
| std::string value; |
| if(target->HasSOName(config)) |
| { |
| prop = "IMPORTED_SONAME"; |
| value = target->GetSOName(config); |
| } |
| else |
| { |
| prop = "IMPORTED_NO_SONAME"; |
| value = "TRUE"; |
| } |
| prop += suffix; |
| properties[prop] = value; |
| } |
| } |
| |
| // Add the transitive link dependencies for this configuration. |
| if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config, |
| target)) |
| { |
| this->SetImportLinkProperty(suffix, target, |
| "IMPORTED_LINK_INTERFACE_LANGUAGES", |
| iface->Languages, properties, missingTargets); |
| |
| this->SetImportLinkProperty(suffix, target, |
| "IMPORTED_LINK_DEPENDENT_LIBRARIES", |
| iface->SharedDeps, properties, missingTargets); |
| if(iface->Multiplicity > 0) |
| { |
| std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY"; |
| prop += suffix; |
| cmOStringStream m; |
| m << iface->Multiplicity; |
| properties[prop] = m.str(); |
| } |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::SetImportLinkProperty(std::string const& suffix, |
| cmTarget* target, |
| const char* propName, |
| std::vector<std::string> const& libs, |
| ImportPropertyMap& properties, |
| std::vector<std::string>& missingTargets |
| ) |
| { |
| // Skip the property if there are no libraries. |
| if(libs.empty()) |
| { |
| return; |
| } |
| |
| // Construct the property value. |
| std::string link_libs; |
| const char* sep = ""; |
| for(std::vector<std::string>::const_iterator li = libs.begin(); |
| li != libs.end(); ++li) |
| { |
| // Separate this from the previous entry. |
| link_libs += sep; |
| sep = ";"; |
| |
| std::string temp = *li; |
| this->AddTargetNamespace(temp, target, missingTargets); |
| link_libs += temp; |
| } |
| |
| // Store the property. |
| std::string prop = propName; |
| prop += suffix; |
| properties[prop] = link_libs; |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, |
| const char* config) |
| { |
| os << "#----------------------------------------------------------------\n" |
| << "# Generated CMake target import file"; |
| if(config) |
| { |
| os << " for configuration \"" << config << "\".\n"; |
| } |
| else |
| { |
| os << ".\n"; |
| } |
| os << "#----------------------------------------------------------------\n" |
| << "\n"; |
| this->GenerateImportVersionCode(os); |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os) |
| { |
| os << "# Commands beyond this point should not need to know the version.\n" |
| << "set(CMAKE_IMPORT_FILE_VERSION)\n"; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os) |
| { |
| // Store an import file format version. This will let us change the |
| // format later while still allowing old import files to work. |
| os << "# Commands may need to know the format version.\n" |
| << "set(CMAKE_IMPORT_FILE_VERSION 1)\n" |
| << "\n"; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateExpectedTargetsCode(std::ostream& os, |
| const std::string &expectedTargets) |
| { |
| os << "set(_targetsDefined)\n" |
| "set(_targetsNotDefined)\n" |
| "set(_expectedTargets)\n" |
| "foreach(_expectedTarget " << expectedTargets << ")\n" |
| " list(APPEND _expectedTargets ${_expectedTarget})\n" |
| " if(NOT TARGET ${_expectedTarget})\n" |
| " list(APPEND _targetsNotDefined ${_expectedTarget})\n" |
| " endif()\n" |
| " if(TARGET ${_expectedTarget})\n" |
| " list(APPEND _targetsDefined ${_expectedTarget})\n" |
| " endif()\n" |
| "endforeach()\n" |
| "if(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n" |
| " set(CMAKE_IMPORT_FILE_VERSION)\n" |
| " cmake_policy(POP)\n" |
| " return()\n" |
| "endif()\n" |
| "if(NOT \"${_targetsDefined}\" STREQUAL \"\")\n" |
| " message(FATAL_ERROR \"Some (but not all) targets in this export " |
| "set were already defined.\\nTargets Defined: ${_targetsDefined}\\n" |
| "Targets not yet defined: ${_targetsNotDefined}\\n\")\n" |
| "endif()\n" |
| "unset(_targetsDefined)\n" |
| "unset(_targetsNotDefined)\n" |
| "unset(_expectedTargets)\n" |
| "\n\n"; |
| } |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::GenerateImportTargetCode(std::ostream& os, cmTarget* target) |
| { |
| // Construct the imported target name. |
| std::string targetName = this->Namespace; |
| targetName += target->GetName(); |
| |
| // Create the imported target. |
| os << "# Create imported target " << targetName << "\n"; |
| switch(target->GetType()) |
| { |
| case cmTarget::EXECUTABLE: |
| os << "add_executable(" << targetName << " IMPORTED)\n"; |
| break; |
| case cmTarget::STATIC_LIBRARY: |
| os << "add_library(" << targetName << " STATIC IMPORTED)\n"; |
| break; |
| case cmTarget::SHARED_LIBRARY: |
| os << "add_library(" << targetName << " SHARED IMPORTED)\n"; |
| break; |
| case cmTarget::MODULE_LIBRARY: |
| os << "add_library(" << targetName << " MODULE IMPORTED)\n"; |
| break; |
| case cmTarget::UNKNOWN_LIBRARY: |
| os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; |
| break; |
| default: // should never happen |
| break; |
| } |
| |
| // Mark the imported executable if it has exports. |
| if(target->IsExecutableWithExports()) |
| { |
| os << "set_property(TARGET " << targetName |
| << " PROPERTY ENABLE_EXPORTS 1)\n"; |
| } |
| |
| // Mark the imported library if it is a framework. |
| if(target->IsFrameworkOnApple()) |
| { |
| os << "set_property(TARGET " << targetName |
| << " PROPERTY FRAMEWORK 1)\n"; |
| } |
| |
| // Mark the imported executable if it is an application bundle. |
| if(target->IsAppBundleOnApple()) |
| { |
| os << "set_property(TARGET " << targetName |
| << " PROPERTY MACOSX_BUNDLE 1)\n"; |
| } |
| |
| if (target->IsCFBundleOnApple()) |
| { |
| os << "set_property(TARGET " << targetName |
| << " PROPERTY BUNDLE 1)\n"; |
| } |
| os << "\n"; |
| } |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::GenerateImportPropertyCode(std::ostream& os, const char* config, |
| cmTarget* target, |
| ImportPropertyMap const& properties) |
| { |
| // Construct the imported target name. |
| std::string targetName = this->Namespace; |
| targetName += target->GetName(); |
| |
| // Set the import properties. |
| os << "# Import target \"" << targetName << "\" for configuration \"" |
| << config << "\"\n"; |
| os << "set_property(TARGET " << targetName |
| << " APPEND PROPERTY IMPORTED_CONFIGURATIONS "; |
| if(config && *config) |
| { |
| os << cmSystemTools::UpperCase(config); |
| } |
| else |
| { |
| os << "NOCONFIG"; |
| } |
| os << ")\n"; |
| os << "set_target_properties(" << targetName << " PROPERTIES\n"; |
| for(ImportPropertyMap::const_iterator pi = properties.begin(); |
| pi != properties.end(); ++pi) |
| { |
| os << " " << pi->first << " \"" << pi->second << "\"\n"; |
| } |
| os << " )\n" |
| << "\n"; |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os, |
| const std::vector<std::string>& missingTargets) |
| { |
| if (missingTargets.empty()) |
| { |
| os << "# This file does not depend on other imported targets which have\n" |
| "# been exported from the same project but in a separate " |
| "export set.\n\n"; |
| return; |
| } |
| os << "# Make sure the targets which have been exported in some other \n" |
| "# export set exist.\n" |
| "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" |
| "foreach(_target "; |
| std::set<std::string> emitted; |
| for(unsigned int i=0; i<missingTargets.size(); ++i) |
| { |
| if (emitted.insert(missingTargets[i]).second) |
| { |
| os << "\"" << missingTargets[i] << "\" "; |
| } |
| } |
| os << ")\n" |
| " if(NOT TARGET \"${_target}\" )\n" |
| " set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets \"" |
| "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets} ${_target}\")" |
| "\n" |
| " endif()\n" |
| "endforeach()\n" |
| "\n" |
| "if(DEFINED ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" |
| " if(CMAKE_FIND_PACKAGE_NAME)\n" |
| " set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n" |
| " set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE " |
| "\"The following imported targets are " |
| "referenced, but are missing: " |
| "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n" |
| " else()\n" |
| " message(FATAL_ERROR \"The following imported targets are " |
| "referenced, but are missing: " |
| "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}\")\n" |
| " endif()\n" |
| "endif()\n" |
| "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" |
| "\n"; |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os) |
| { |
| // Add code which verifies at cmake time that the file which is being |
| // imported actually exists on disk. This should in theory always be theory |
| // case, but still when packages are split into normal and development |
| // packages this might get broken (e.g. the Config.cmake could be part of |
| // the non-development package, something similar happened to me without |
| // on SUSE with a mysql pkg-config file, which claimed everything is fine, |
| // but the development package was not installed.). |
| os << "# Loop over all imported files and verify that they actually exist\n" |
| "foreach(target ${_IMPORT_CHECK_TARGETS} )\n" |
| " foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n" |
| " if(NOT EXISTS \"${file}\" )\n" |
| " message(FATAL_ERROR \"The imported target \\\"${target}\\\"" |
| " references the file\n" |
| " \\\"${file}\\\"\n" |
| "but this file does not exist. Possible reasons include:\n" |
| "* The file was deleted, renamed, or moved to another location.\n" |
| "* An install or uninstall procedure did not complete successfully.\n" |
| "* The installation package was faulty and contained\n" |
| " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n" |
| "but not all the files it references.\n" |
| "\")\n" |
| " endif()\n" |
| " endforeach()\n" |
| " unset(_IMPORT_CHECK_FILES_FOR_${target})\n" |
| "endforeach()\n" |
| "unset(_IMPORT_CHECK_TARGETS)\n" |
| "\n"; |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| void |
| cmExportFileGenerator |
| ::GenerateImportedFileChecksCode(std::ostream& os, cmTarget* target, |
| ImportPropertyMap const& properties, |
| const std::set<std::string>& importedLocations) |
| { |
| // Construct the imported target name. |
| std::string targetName = this->Namespace; |
| targetName += target->GetName(); |
| |
| os << "list(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n" |
| "list(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " "; |
| |
| for(std::set<std::string>::const_iterator li = importedLocations.begin(); |
| li != importedLocations.end(); |
| ++li) |
| { |
| ImportPropertyMap::const_iterator pi = properties.find(*li); |
| if (pi != properties.end()) |
| { |
| os << "\"" << pi->second << "\" "; |
| } |
| } |
| |
| os << ")\n\n"; |
| } |