Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmExportInstallFileGenerator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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"
13
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"
22
23 //----------------------------------------------------------------------------
24 cmExportInstallFileGenerator
25 ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
26   IEGen(iegen)
27 {
28 }
29
30 //----------------------------------------------------------------------------
31 std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
32 {
33   std::string glob = this->FileBase;
34   glob += "-*";
35   glob += this->FileExt;
36   return glob;
37 }
38
39 //----------------------------------------------------------------------------
40 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
41 {
42   std::vector<cmTargetExport*> allTargets;
43   {
44   std::string expectedTargets;
45   std::string sep;
46   for(std::vector<cmTargetExport*>::const_iterator
47         tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
48       tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
49     {
50     expectedTargets += sep + this->Namespace + (*tei)->Target->GetExportName();
51     sep = " ";
52     cmTargetExport * te = *tei;
53     if(this->ExportedTargets.insert(te->Target).second)
54       {
55       allTargets.push_back(te);
56       }
57     else
58       {
59       cmOStringStream e;
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());
65       return false;
66       }
67     }
68
69   this->GenerateExpectedTargetsCode(os, expectedTargets);
70   }
71
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))
76     {
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)
88       {
89       // Handle "/usr move" symlinks created by some Linux distros.
90       os <<
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"
97         "endif()\n"
98         "unset(_realOrig)\n"
99         "unset(_realCurr)\n";
100       }
101     std::string dest = installDest;
102     while(!dest.empty())
103       {
104       os <<
105         "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
106       dest = cmSystemTools::GetFilenamePath(dest);
107       }
108     os << "\n";
109
110     // Import location properties may reference this variable.
111     this->ImportPrefix = "${_IMPORT_PREFIX}/";
112     }
113
114   std::vector<std::string> missingTargets;
115
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)
121     {
122     cmTarget* te = (*tei)->Target;
123     this->GenerateImportTargetCode(os, te);
124
125     ImportPropertyMap properties;
126
127     this->PopulateIncludeDirectoriesInterface(*tei,
128                                   cmGeneratorExpression::InstallInterface,
129                                   properties, missingTargets);
130     this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
131                                   te,
132                                   cmGeneratorExpression::InstallInterface,
133                                   properties, missingTargets);
134     this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",
135                                   te,
136                                   cmGeneratorExpression::InstallInterface,
137                                   properties, missingTargets);
138     this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS",
139                                   te,
140                                   cmGeneratorExpression::InstallInterface,
141                                   properties, missingTargets);
142
143     const bool newCMP0022Behavior =
144                               te->GetPolicyStatusCMP0022() != cmPolicies::WARN
145                            && te->GetPolicyStatusCMP0022() != cmPolicies::OLD;
146     if (newCMP0022Behavior)
147       {
148       if (this->PopulateInterfaceLinkLibrariesProperty(te,
149                                     cmGeneratorExpression::InstallInterface,
150                                     properties, missingTargets)
151           && !this->ExportOld)
152         {
153         require2_8_12 = true;
154         }
155       }
156     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
157                                   te, properties);
158     this->PopulateCompatibleInterfaceProperties(te, properties);
159
160     this->GenerateInterfaceProperties(te, os, properties);
161     }
162
163   if (require2_8_12)
164     {
165     this->GenerateRequiredCMakeVersion(os, "2.8.12");
166     }
167
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"
175      << "endforeach()\n"
176      << "\n";
177
178   // Cleanup the import prefix variable.
179   if(!this->ImportPrefix.empty())
180     {
181     os << "# Cleanup temporary variables.\n"
182        << "set(_IMPORT_PREFIX)\n"
183        << "\n";
184     }
185   this->GenerateImportedFileCheckLoop(os);
186
187   // Generate an import file for each configuration.
188   bool result = true;
189   for(std::vector<std::string>::const_iterator
190         ci = this->Configurations.begin();
191       ci != this->Configurations.end(); ++ci)
192     {
193     if(!this->GenerateImportFileConfig(ci->c_str(), missingTargets))
194       {
195       result = false;
196       }
197     }
198
199   this->GenerateMissingTargetsCheckCode(os, missingTargets);
200
201   return result;
202 }
203
204 //----------------------------------------------------------------------------
205 void
206 cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string &input)
207 {
208   std::string::size_type pos = 0;
209   std::string::size_type lastPos = pos;
210
211   while((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != input.npos)
212     {
213     std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
214     input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
215     lastPos = endPos;
216     }
217 }
218
219 //----------------------------------------------------------------------------
220 bool
221 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config,
222                                     std::vector<std::string> &missingTargets)
223 {
224   // Skip configurations not enabled for this export.
225   if(!this->IEGen->InstallsForConfig(config))
226     {
227     return true;
228     }
229
230   // Construct the name of the file to generate.
231   std::string fileName = this->FileDir;
232   fileName += "/";
233   fileName += this->FileBase;
234   fileName += "-";
235   if(config && *config)
236     {
237     fileName += cmSystemTools::LowerCase(config);
238     }
239   else
240     {
241     fileName += "noconfig";
242     }
243   fileName += this->FileExt;
244
245   // Open the output file to generate it.
246   cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
247   if(!exportFileStream)
248     {
249     std::string se = cmSystemTools::GetLastSystemError();
250     cmOStringStream e;
251     e << "cannot write to file \"" << fileName.c_str()
252       << "\": " << se;
253     cmSystemTools::Error(e.str().c_str());
254     return false;
255     }
256   std::ostream& os = exportFileStream;
257
258   // Start with the import file header.
259   this->GenerateImportHeaderCode(os, config);
260
261   // Generate the per-config target information.
262   this->GenerateImportConfig(os, config, missingTargets);
263
264   // End with the import file footer.
265   this->GenerateImportFooterCode(os);
266
267   // Record this per-config import file.
268   this->ConfigImportFiles[config] = fileName;
269
270   return true;
271 }
272
273 //----------------------------------------------------------------------------
274 void
275 cmExportInstallFileGenerator
276 ::GenerateImportTargetsConfig(std::ostream& os,
277                               const char* config, std::string const& suffix,
278                               std::vector<std::string> &missingTargets)
279 {
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)
284     {
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,
295                                     importedLocations);
296     this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
297                                     properties, importedLocations);
298     this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
299                                     properties, importedLocations);
300
301     // If any file location was set for the target add it to the
302     // import file.
303     if(!properties.empty())
304       {
305       // Get the rest of the target details.
306       this->SetImportDetailProperties(config, suffix,
307                                       te->Target, properties, missingTargets);
308
309       this->SetImportLinkInterface(config, suffix,
310                                    cmGeneratorExpression::InstallInterface,
311                                    te->Target, properties, missingTargets);
312
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,
317       //                              properties);
318
319       // Generate code in the export file.
320       this->GenerateImportPropertyCode(os, config, te->Target, properties);
321       this->GenerateImportedFileChecksCode(os, te->Target, properties,
322                                            importedLocations);
323       }
324     }
325 }
326
327 //----------------------------------------------------------------------------
328 void
329 cmExportInstallFileGenerator
330 ::SetImportLocationProperty(const char* config, std::string const& suffix,
331                             cmInstallTargetGenerator* itgen,
332                             ImportPropertyMap& properties,
333                             std::set<std::string>& importedLocations
334                            )
335 {
336   // Skip rules that do not match this configuration.
337   if(!(itgen && itgen->InstallsForConfig(config)))
338     {
339     return;
340     }
341
342   // Get the target to be installed.
343   cmTarget* target = itgen->GetTarget();
344
345   // Construct the installed location of the target.
346   std::string dest = itgen->GetDestination();
347   std::string value;
348   if(!cmSystemTools::FileIsFullPath(dest.c_str()))
349     {
350     // The target is installed relative to the installation prefix.
351     if(this->ImportPrefix.empty())
352       {
353       this->ComplainAboutImportPrefix(itgen);
354       }
355     value = this->ImportPrefix;
356     }
357   value += dest;
358   value += "/";
359
360   if(itgen->IsImportLibrary())
361     {
362     // Construct the property name.
363     std::string prop = "IMPORTED_IMPLIB";
364     prop += suffix;
365
366     // Append the installed file name.
367     value += itgen->GetInstallFilename(target, config,
368                                        cmInstallTargetGenerator::NameImplib);
369
370     // Store the property.
371     properties[prop] = value;
372     importedLocations.insert(prop);
373     }
374   else
375     {
376     // Construct the property name.
377     std::string prop = "IMPORTED_LOCATION";
378     prop += suffix;
379
380     // Append the installed file name.
381     if(target->IsAppBundleOnApple())
382       {
383       value += itgen->GetInstallFilename(target, config);
384       value += ".app/Contents/MacOS/";
385       value += itgen->GetInstallFilename(target, config);
386       }
387     else
388       {
389       value += itgen->GetInstallFilename(target, config,
390                                          cmInstallTargetGenerator::NameReal);
391       }
392
393     // Store the property.
394     properties[prop] = value;
395     importedLocations.insert(prop);
396     }
397 }
398
399 //----------------------------------------------------------------------------
400 void
401 cmExportInstallFileGenerator::HandleMissingTarget(
402   std::string& link_libs, std::vector<std::string>& missingTargets,
403   cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
404 {
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)
409     {
410     std::string missingTarget = namespaces[0];
411
412     missingTarget += dependee->GetExportName();
413     link_libs += missingTarget;
414     missingTargets.push_back(missingTarget);
415     }
416   else
417     {
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);
421     }
422 }
423
424 //----------------------------------------------------------------------------
425 std::vector<std::string>
426 cmExportInstallFileGenerator
427 ::FindNamespaces(cmMakefile* mf, const std::string& name)
428 {
429   std::vector<std::string> namespaces;
430   cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
431   const cmExportSetMap& exportSets = gg->GetExportSets();
432
433   for(cmExportSetMap::const_iterator expIt = exportSets.begin();
434       expIt != exportSets.end();
435       ++expIt)
436     {
437     const cmExportSet* exportSet = expIt->second;
438     std::vector<cmTargetExport*> const* targets =
439                                                  exportSet->GetTargetExports();
440
441     bool containsTarget = false;
442     for(unsigned int i=0; i<targets->size(); i++)
443       {
444       if (name == (*targets)[i]->Target->GetName())
445         {
446         containsTarget = true;
447         break;
448         }
449       }
450
451     if (containsTarget)
452       {
453       std::vector<cmInstallExportGenerator const*> const* installs =
454                                                  exportSet->GetInstallations();
455       for(unsigned int i=0; i<installs->size(); i++)
456         {
457         namespaces.push_back((*installs)[i]->GetNamespace());
458         }
459       }
460     }
461
462   return namespaces;
463 }
464
465
466 //----------------------------------------------------------------------------
467 void
468 cmExportInstallFileGenerator
469 ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
470 {
471   const char* installDest = this->IEGen->GetDestination();
472   cmOStringStream e;
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());
481 }
482
483 //----------------------------------------------------------------------------
484 void
485 cmExportInstallFileGenerator
486 ::ComplainAboutMissingTarget(cmTarget* depender,
487                              cmTarget* dependee,
488                              int occurrences)
489 {
490   cmOStringStream e;
491   e << "install(EXPORT \""
492     << this->IEGen->GetExportSet()->GetName()
493     << "\" ...) "
494     << "includes target \"" << depender->GetName()
495     << "\" which requires target \"" << dependee->GetName() << "\" ";
496   if (occurrences == 0)
497     {
498     e << "that is not in the export set.";
499     }
500   else
501     {
502     e << "that is not in this export set, but " << occurrences
503     << " times in others.";
504     }
505   cmSystemTools::Error(e.str().c_str());
506 }
507
508 std::string
509 cmExportInstallFileGenerator::InstallNameDir(cmTarget* target,
510                                              const std::string&)
511 {
512   std::string install_name_dir;
513
514   cmMakefile* mf = target->GetMakefile();
515   if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
516     {
517     install_name_dir =
518       target->GetInstallNameDirForInstallTree();
519     }
520
521   return install_name_dir;
522 }