Imported Upstream version 2.8.9
[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 "cmGeneratedFileStream.h"
15 #include "cmInstallExportGenerator.h"
16 #include "cmInstallTargetGenerator.h"
17
18 //----------------------------------------------------------------------------
19 cmExportInstallFileGenerator
20 ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
21   InstallExportGenerator(iegen)
22 {
23 }
24
25 //----------------------------------------------------------------------------
26 std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
27 {
28   std::string glob = this->FileBase;
29   glob += "-*";
30   glob += this->FileExt;
31   return glob;
32 }
33
34 //----------------------------------------------------------------------------
35 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
36 {
37   // Create all the imported targets.
38   for(std::vector<cmTargetExport*>::const_iterator
39         tei = this->ExportSet->begin();
40       tei != this->ExportSet->end(); ++tei)
41     {
42     cmTargetExport* te = *tei;
43     if(this->ExportedTargets.insert(te->Target).second)
44       {
45       this->GenerateImportTargetCode(os, te->Target);
46       }
47     else
48       {
49       cmOStringStream e;
50       e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
51         << "includes target \"" << te->Target->GetName()
52         << "\" more than once in the export set.";
53       cmSystemTools::Error(e.str().c_str());
54       return false;
55       }
56     }
57
58   // Now load per-configuration properties for them.
59   os << "# Load information for each installed configuration.\n"
60      << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
61      << "FILE(GLOB CONFIG_FILES \"${_DIR}/"
62      << this->GetConfigImportFileGlob() << "\")\n"
63      << "FOREACH(f ${CONFIG_FILES})\n"
64      << "  INCLUDE(${f})\n"
65      << "ENDFOREACH(f)\n"
66      << "\n";
67
68   // Generate an import file for each configuration.
69   bool result = true;
70   for(std::vector<std::string>::const_iterator
71         ci = this->Configurations.begin();
72       ci != this->Configurations.end(); ++ci)
73     {
74     if(!this->GenerateImportFileConfig(ci->c_str()))
75       {
76       result = false;
77       }
78     }
79   return result;
80 }
81
82 //----------------------------------------------------------------------------
83 bool
84 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config)
85 {
86   // Skip configurations not enabled for this export.
87   if(!this->InstallExportGenerator->InstallsForConfig(config))
88     {
89     return true;
90     }
91
92   // Construct the name of the file to generate.
93   std::string fileName = this->FileDir;
94   fileName += "/";
95   fileName += this->FileBase;
96   fileName += "-";
97   if(config && *config)
98     {
99     fileName += cmSystemTools::LowerCase(config);
100     }
101   else
102     {
103     fileName += "noconfig";
104     }
105   fileName += this->FileExt;
106
107   // Open the output file to generate it.
108   cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
109   if(!exportFileStream)
110     {
111     std::string se = cmSystemTools::GetLastSystemError();
112     cmOStringStream e;
113     e << "cannot write to file \"" << fileName.c_str()
114       << "\": " << se;
115     cmSystemTools::Error(e.str().c_str());
116     return false;
117     }
118   std::ostream& os = exportFileStream;
119
120   // Start with the import file header.
121   this->GenerateImportHeaderCode(os, config);
122
123   // Generate the per-config target information.
124   this->GenerateImportConfig(os, config);
125
126   // End with the import file footer.
127   this->GenerateImportFooterCode(os);
128
129   // Record this per-config import file.
130   this->ConfigImportFiles[config] = fileName;
131
132   return true;
133 }
134
135 //----------------------------------------------------------------------------
136 void
137 cmExportInstallFileGenerator
138 ::GenerateImportTargetsConfig(std::ostream& os,
139                               const char* config, std::string const& suffix)
140 {
141   // Add code to compute the installation prefix relative to the
142   // import file location.
143   const char* installDest = this->InstallExportGenerator->GetDestination();
144   if(!cmSystemTools::FileIsFullPath(installDest))
145     {
146     std::string dest = installDest;
147     os << "# Compute the installation prefix relative to this file.\n"
148        << "GET_FILENAME_COMPONENT(_IMPORT_PREFIX "
149        << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
150     while(!dest.empty())
151       {
152       os <<
153         "GET_FILENAME_COMPONENT(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
154       dest = cmSystemTools::GetFilenamePath(dest);
155       }
156     os << "\n";
157
158     // Import location properties may reference this variable.
159     this->ImportPrefix = "${_IMPORT_PREFIX}/";
160     }
161
162   // Add each target in the set to the export.
163   for(std::vector<cmTargetExport*>::const_iterator
164         tei = this->ExportSet->begin();
165       tei != this->ExportSet->end(); ++tei)
166     {
167     // Collect import properties for this target.
168     cmTargetExport* te = *tei;
169     ImportPropertyMap properties;
170     std::set<std::string> importedLocations;
171     this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
172                                     properties, importedLocations);
173     this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
174                                     properties, importedLocations);
175     this->SetImportLocationProperty(config, suffix,
176                                     te->RuntimeGenerator, properties,
177                                     importedLocations);
178     this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
179                                     properties, importedLocations);
180     this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
181                                     properties, importedLocations);
182
183     // If any file location was set for the target add it to the
184     // import file.
185     if(!properties.empty())
186       {
187       // Get the rest of the target details.
188       this->SetImportDetailProperties(config, suffix,
189                                       te->Target, properties);
190
191       // TOOD: PUBLIC_HEADER_LOCATION
192       // This should wait until the build feature propagation stuff
193       // is done.  Then this can be a propagated include directory.
194       // this->GenerateImportProperty(config, te->HeaderGenerator,
195       //                              properties);
196
197       // Generate code in the export file.
198       this->GenerateImportPropertyCode(os, config, te->Target, properties);
199       this->GenerateImportedFileChecksCode(os, te->Target, properties,
200                                            importedLocations);
201       }
202     }
203
204   this->GenerateImportedFileCheckLoop(os);
205
206   // Cleanup the import prefix variable.
207   if(!this->ImportPrefix.empty())
208     {
209     os << "# Cleanup temporary variables.\n"
210        << "SET(_IMPORT_PREFIX)\n"
211        << "\n";
212     }
213 }
214
215 //----------------------------------------------------------------------------
216 void
217 cmExportInstallFileGenerator
218 ::SetImportLocationProperty(const char* config, std::string const& suffix,
219                             cmInstallTargetGenerator* itgen,
220                             ImportPropertyMap& properties,
221                             std::set<std::string>& importedLocations
222                            )
223 {
224   // Skip rules that do not match this configuration.
225   if(!(itgen && itgen->InstallsForConfig(config)))
226     {
227     return;
228     }
229
230   // Get the target to be installed.
231   cmTarget* target = itgen->GetTarget();
232
233   // Construct the installed location of the target.
234   std::string dest = itgen->GetDestination();
235   std::string value;
236   if(!cmSystemTools::FileIsFullPath(dest.c_str()))
237     {
238     // The target is installed relative to the installation prefix.
239     if(this->ImportPrefix.empty())
240       {
241       this->ComplainAboutImportPrefix(itgen);
242       }
243     value = this->ImportPrefix;
244     }
245   value += dest;
246   value += "/";
247
248   if(itgen->IsImportLibrary())
249     {
250     // Construct the property name.
251     std::string prop = "IMPORTED_IMPLIB";
252     prop += suffix;
253
254     // Append the installed file name.
255     value += itgen->GetInstallFilename(target, config,
256                                        cmInstallTargetGenerator::NameImplib);
257
258     // Store the property.
259     properties[prop] = value;
260     importedLocations.insert(prop);
261     }
262   else
263     {
264     // Construct the property name.
265     std::string prop = "IMPORTED_LOCATION";
266     prop += suffix;
267
268     // Append the installed file name.
269     if(target->IsFrameworkOnApple())
270       {
271       value += itgen->GetInstallFilename(target, config);
272       value += ".framework/";
273       value += itgen->GetInstallFilename(target, config);
274       }
275     else if(target->IsCFBundleOnApple())
276       {
277       const char *ext = target->GetProperty("BUNDLE_EXTENSION");
278       if (!ext)
279         {
280         ext = "bundle";
281         }
282
283       value += itgen->GetInstallFilename(target, config);
284       value += ".";
285       value += ext;
286       value += "/";
287       value += itgen->GetInstallFilename(target, config);
288       }
289     else if(target->IsAppBundleOnApple())
290       {
291       value += itgen->GetInstallFilename(target, config);
292       value += ".app/Contents/MacOS/";
293       value += itgen->GetInstallFilename(target, config);
294       }
295     else
296       {
297       value += itgen->GetInstallFilename(target, config,
298                                          cmInstallTargetGenerator::NameReal);
299       }
300
301     // Store the property.
302     properties[prop] = value;
303     importedLocations.insert(prop);
304     }
305 }
306
307 //----------------------------------------------------------------------------
308 void
309 cmExportInstallFileGenerator
310 ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
311 {
312   const char* installDest = this->InstallExportGenerator->GetDestination();
313   cmOStringStream e;
314   e << "INSTALL(EXPORT \"" << this->Name << "\") given absolute "
315     << "DESTINATION \"" << installDest << "\" but the export "
316     << "references an installation of target \""
317     << itgen->GetTarget()->GetName() << "\" which has relative "
318     << "DESTINATION \"" << itgen->GetDestination() << "\".";
319   cmSystemTools::Error(e.str().c_str());
320 }
321
322 //----------------------------------------------------------------------------
323 void
324 cmExportInstallFileGenerator
325 ::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee)
326 {
327   cmOStringStream e;
328   e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
329     << "includes target \"" << depender->GetName()
330     << "\" which requires target \"" << dependee->GetName()
331     << "\" that is not in the export set.";
332   cmSystemTools::Error(e.str().c_str());
333 }