1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmExportInstallFileGenerator.h"
14 #include "cmExportSet.h"
15 #include "cmExportSetMap.h"
16 #include "cmGeneratedFileStream.h"
17 #include "cmGlobalGenerator.h"
18 #include "cmLocalGenerator.h"
19 #include "cmInstallExportGenerator.h"
20 #include "cmInstallTargetGenerator.h"
21 #include "cmTargetExport.h"
23 //----------------------------------------------------------------------------
24 cmExportInstallFileGenerator
25 ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
30 //----------------------------------------------------------------------------
31 std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
33 std::string glob = this->FileBase;
35 glob += this->FileExt;
39 //----------------------------------------------------------------------------
40 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
42 std::vector<cmTargetExport*> allTargets;
44 std::string expectedTargets;
46 for(std::vector<cmTargetExport*>::const_iterator
47 tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
48 tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
50 expectedTargets += sep + this->Namespace + (*tei)->Target->GetExportName();
52 cmTargetExport * te = *tei;
53 if(this->ExportedTargets.insert(te->Target).second)
55 allTargets.push_back(te);
60 e << "install(EXPORT \""
61 << this->IEGen->GetExportSet()->GetName()
62 << "\" ...) " << "includes target \"" << te->Target->GetName()
63 << "\" more than once in the export set.";
64 cmSystemTools::Error(e.str().c_str());
69 this->GenerateExpectedTargetsCode(os, expectedTargets);
72 // Add code to compute the installation prefix relative to the
73 // import file location.
74 const char* installDest = this->IEGen->GetDestination();
75 if(!cmSystemTools::FileIsFullPath(installDest))
77 std::string installPrefix =
78 this->IEGen->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
79 std::string absDest = installPrefix + "/" + installDest;
80 std::string absDestS = absDest + "/";
81 os << "# Compute the installation prefix relative to this file.\n"
82 << "get_filename_component(_IMPORT_PREFIX"
83 << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
84 if(strncmp(absDestS.c_str(), "/lib/", 5) == 0 ||
85 strncmp(absDestS.c_str(), "/lib64/", 7) == 0 ||
86 strncmp(absDestS.c_str(), "/usr/lib/", 9) == 0 ||
87 strncmp(absDestS.c_str(), "/usr/lib64/", 11) == 0)
89 // Handle "/usr move" symlinks created by some Linux distros.
91 "# Use original install prefix when loaded through a\n"
92 "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
93 "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
94 "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n"
95 "if(_realCurr STREQUAL _realOrig)\n"
96 " set(_IMPORT_PREFIX \"" << absDest << "\")\n"
101 std::string dest = installDest;
105 "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
106 dest = cmSystemTools::GetFilenamePath(dest);
110 // Import location properties may reference this variable.
111 this->ImportPrefix = "${_IMPORT_PREFIX}/";
114 std::vector<std::string> missingTargets;
116 bool require2_8_12 = false;
117 // Create all the imported targets.
118 for(std::vector<cmTargetExport*>::const_iterator
119 tei = allTargets.begin();
120 tei != allTargets.end(); ++tei)
122 cmTarget* te = (*tei)->Target;
123 this->GenerateImportTargetCode(os, te);
125 ImportPropertyMap properties;
127 this->PopulateIncludeDirectoriesInterface(*tei,
128 cmGeneratorExpression::InstallInterface,
129 properties, missingTargets);
130 this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
132 cmGeneratorExpression::InstallInterface,
133 properties, missingTargets);
134 this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",
136 cmGeneratorExpression::InstallInterface,
137 properties, missingTargets);
138 this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS",
140 cmGeneratorExpression::InstallInterface,
141 properties, missingTargets);
143 const bool newCMP0022Behavior =
144 te->GetPolicyStatusCMP0022() != cmPolicies::WARN
145 && te->GetPolicyStatusCMP0022() != cmPolicies::OLD;
146 if (newCMP0022Behavior)
148 if (this->PopulateInterfaceLinkLibrariesProperty(te,
149 cmGeneratorExpression::InstallInterface,
150 properties, missingTargets)
153 require2_8_12 = true;
156 this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
158 this->PopulateCompatibleInterfaceProperties(te, properties);
160 this->GenerateInterfaceProperties(te, os, properties);
165 this->GenerateRequiredCMakeVersion(os, "2.8.12");
168 // Now load per-configuration properties for them.
169 os << "# Load information for each installed configuration.\n"
170 << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
171 << "file(GLOB CONFIG_FILES \"${_DIR}/"
172 << this->GetConfigImportFileGlob() << "\")\n"
173 << "foreach(f ${CONFIG_FILES})\n"
174 << " include(${f})\n"
178 // Cleanup the import prefix variable.
179 if(!this->ImportPrefix.empty())
181 os << "# Cleanup temporary variables.\n"
182 << "set(_IMPORT_PREFIX)\n"
185 this->GenerateImportedFileCheckLoop(os);
187 // Generate an import file for each configuration.
189 for(std::vector<std::string>::const_iterator
190 ci = this->Configurations.begin();
191 ci != this->Configurations.end(); ++ci)
193 if(!this->GenerateImportFileConfig(ci->c_str(), missingTargets))
199 this->GenerateMissingTargetsCheckCode(os, missingTargets);
204 //----------------------------------------------------------------------------
206 cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string &input)
208 std::string::size_type pos = 0;
209 std::string::size_type lastPos = pos;
211 while((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != input.npos)
213 std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
214 input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
219 //----------------------------------------------------------------------------
221 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config,
222 std::vector<std::string> &missingTargets)
224 // Skip configurations not enabled for this export.
225 if(!this->IEGen->InstallsForConfig(config))
230 // Construct the name of the file to generate.
231 std::string fileName = this->FileDir;
233 fileName += this->FileBase;
235 if(config && *config)
237 fileName += cmSystemTools::LowerCase(config);
241 fileName += "noconfig";
243 fileName += this->FileExt;
245 // Open the output file to generate it.
246 cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
247 if(!exportFileStream)
249 std::string se = cmSystemTools::GetLastSystemError();
251 e << "cannot write to file \"" << fileName.c_str()
253 cmSystemTools::Error(e.str().c_str());
256 std::ostream& os = exportFileStream;
258 // Start with the import file header.
259 this->GenerateImportHeaderCode(os, config);
261 // Generate the per-config target information.
262 this->GenerateImportConfig(os, config, missingTargets);
264 // End with the import file footer.
265 this->GenerateImportFooterCode(os);
267 // Record this per-config import file.
268 this->ConfigImportFiles[config] = fileName;
273 //----------------------------------------------------------------------------
275 cmExportInstallFileGenerator
276 ::GenerateImportTargetsConfig(std::ostream& os,
277 const char* config, std::string const& suffix,
278 std::vector<std::string> &missingTargets)
280 // Add each target in the set to the export.
281 for(std::vector<cmTargetExport*>::const_iterator
282 tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
283 tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
285 // Collect import properties for this target.
286 cmTargetExport const* te = *tei;
287 ImportPropertyMap properties;
288 std::set<std::string> importedLocations;
289 this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
290 properties, importedLocations);
291 this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
292 properties, importedLocations);
293 this->SetImportLocationProperty(config, suffix,
294 te->RuntimeGenerator, properties,
296 this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
297 properties, importedLocations);
298 this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
299 properties, importedLocations);
301 // If any file location was set for the target add it to the
303 if(!properties.empty())
305 // Get the rest of the target details.
306 this->SetImportDetailProperties(config, suffix,
307 te->Target, properties, missingTargets);
309 this->SetImportLinkInterface(config, suffix,
310 cmGeneratorExpression::InstallInterface,
311 te->Target, properties, missingTargets);
313 // TOOD: PUBLIC_HEADER_LOCATION
314 // This should wait until the build feature propagation stuff
315 // is done. Then this can be a propagated include directory.
316 // this->GenerateImportProperty(config, te->HeaderGenerator,
319 // Generate code in the export file.
320 this->GenerateImportPropertyCode(os, config, te->Target, properties);
321 this->GenerateImportedFileChecksCode(os, te->Target, properties,
327 //----------------------------------------------------------------------------
329 cmExportInstallFileGenerator
330 ::SetImportLocationProperty(const char* config, std::string const& suffix,
331 cmInstallTargetGenerator* itgen,
332 ImportPropertyMap& properties,
333 std::set<std::string>& importedLocations
336 // Skip rules that do not match this configuration.
337 if(!(itgen && itgen->InstallsForConfig(config)))
342 // Get the target to be installed.
343 cmTarget* target = itgen->GetTarget();
345 // Construct the installed location of the target.
346 std::string dest = itgen->GetDestination();
348 if(!cmSystemTools::FileIsFullPath(dest.c_str()))
350 // The target is installed relative to the installation prefix.
351 if(this->ImportPrefix.empty())
353 this->ComplainAboutImportPrefix(itgen);
355 value = this->ImportPrefix;
360 if(itgen->IsImportLibrary())
362 // Construct the property name.
363 std::string prop = "IMPORTED_IMPLIB";
366 // Append the installed file name.
367 value += itgen->GetInstallFilename(target, config,
368 cmInstallTargetGenerator::NameImplib);
370 // Store the property.
371 properties[prop] = value;
372 importedLocations.insert(prop);
376 // Construct the property name.
377 std::string prop = "IMPORTED_LOCATION";
380 // Append the installed file name.
381 if(target->IsAppBundleOnApple())
383 value += itgen->GetInstallFilename(target, config);
384 value += ".app/Contents/MacOS/";
385 value += itgen->GetInstallFilename(target, config);
389 value += itgen->GetInstallFilename(target, config,
390 cmInstallTargetGenerator::NameReal);
393 // Store the property.
394 properties[prop] = value;
395 importedLocations.insert(prop);
399 //----------------------------------------------------------------------------
401 cmExportInstallFileGenerator::HandleMissingTarget(
402 std::string& link_libs, std::vector<std::string>& missingTargets,
403 cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
405 const std::string name = dependee->GetName();
406 std::vector<std::string> namespaces = this->FindNamespaces(mf, name);
407 int targetOccurrences = (int)namespaces.size();
408 if (targetOccurrences == 1)
410 std::string missingTarget = namespaces[0];
412 missingTarget += dependee->GetExportName();
413 link_libs += missingTarget;
414 missingTargets.push_back(missingTarget);
418 // We are not appending, so all exported targets should be
419 // known here. This is probably user-error.
420 this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
424 //----------------------------------------------------------------------------
425 std::vector<std::string>
426 cmExportInstallFileGenerator
427 ::FindNamespaces(cmMakefile* mf, const std::string& name)
429 std::vector<std::string> namespaces;
430 cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
431 const cmExportSetMap& exportSets = gg->GetExportSets();
433 for(cmExportSetMap::const_iterator expIt = exportSets.begin();
434 expIt != exportSets.end();
437 const cmExportSet* exportSet = expIt->second;
438 std::vector<cmTargetExport*> const* targets =
439 exportSet->GetTargetExports();
441 bool containsTarget = false;
442 for(unsigned int i=0; i<targets->size(); i++)
444 if (name == (*targets)[i]->Target->GetName())
446 containsTarget = true;
453 std::vector<cmInstallExportGenerator const*> const* installs =
454 exportSet->GetInstallations();
455 for(unsigned int i=0; i<installs->size(); i++)
457 namespaces.push_back((*installs)[i]->GetNamespace());
466 //----------------------------------------------------------------------------
468 cmExportInstallFileGenerator
469 ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
471 const char* installDest = this->IEGen->GetDestination();
473 e << "install(EXPORT \""
474 << this->IEGen->GetExportSet()->GetName()
475 << "\") given absolute "
476 << "DESTINATION \"" << installDest << "\" but the export "
477 << "references an installation of target \""
478 << itgen->GetTarget()->GetName() << "\" which has relative "
479 << "DESTINATION \"" << itgen->GetDestination() << "\".";
480 cmSystemTools::Error(e.str().c_str());
483 //----------------------------------------------------------------------------
485 cmExportInstallFileGenerator
486 ::ComplainAboutMissingTarget(cmTarget* depender,
491 e << "install(EXPORT \""
492 << this->IEGen->GetExportSet()->GetName()
494 << "includes target \"" << depender->GetName()
495 << "\" which requires target \"" << dependee->GetName() << "\" ";
496 if (occurrences == 0)
498 e << "that is not in the export set.";
502 e << "that is not in this export set, but " << occurrences
503 << " times in others.";
505 cmSystemTools::Error(e.str().c_str());
509 cmExportInstallFileGenerator::InstallNameDir(cmTarget* target,
512 std::string install_name_dir;
514 cmMakefile* mf = target->GetMakefile();
515 if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
518 target->GetInstallNameDirForInstallTree();
521 return install_name_dir;