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 // Create all the imported targets.
43 for(std::vector<cmTargetExport*>::const_iterator
44 tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
45 tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
47 cmTargetExport const* te = *tei;
48 if(this->ExportedTargets.insert(te->Target).second)
50 this->GenerateImportTargetCode(os, te->Target);
55 e << "INSTALL(EXPORT \""
56 << this->IEGen->GetExportSet()->GetName()
57 << "\" ...) " << "includes target \"" << te->Target->GetName()
58 << "\" more than once in the export set.";
59 cmSystemTools::Error(e.str().c_str());
64 // Now load per-configuration properties for them.
65 os << "# Load information for each installed configuration.\n"
66 << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
67 << "FILE(GLOB CONFIG_FILES \"${_DIR}/"
68 << this->GetConfigImportFileGlob() << "\")\n"
69 << "FOREACH(f ${CONFIG_FILES})\n"
74 // Generate an import file for each configuration.
76 for(std::vector<std::string>::const_iterator
77 ci = this->Configurations.begin();
78 ci != this->Configurations.end(); ++ci)
80 if(!this->GenerateImportFileConfig(ci->c_str()))
88 //----------------------------------------------------------------------------
90 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config)
92 // Skip configurations not enabled for this export.
93 if(!this->IEGen->InstallsForConfig(config))
98 // Construct the name of the file to generate.
99 std::string fileName = this->FileDir;
101 fileName += this->FileBase;
103 if(config && *config)
105 fileName += cmSystemTools::LowerCase(config);
109 fileName += "noconfig";
111 fileName += this->FileExt;
113 // Open the output file to generate it.
114 cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
115 if(!exportFileStream)
117 std::string se = cmSystemTools::GetLastSystemError();
119 e << "cannot write to file \"" << fileName.c_str()
121 cmSystemTools::Error(e.str().c_str());
124 std::ostream& os = exportFileStream;
126 // Start with the import file header.
127 this->GenerateImportHeaderCode(os, config);
129 // Generate the per-config target information.
130 this->GenerateImportConfig(os, config);
132 // End with the import file footer.
133 this->GenerateImportFooterCode(os);
135 // Record this per-config import file.
136 this->ConfigImportFiles[config] = fileName;
141 //----------------------------------------------------------------------------
143 cmExportInstallFileGenerator
144 ::GenerateImportTargetsConfig(std::ostream& os,
145 const char* config, std::string const& suffix)
147 // Add code to compute the installation prefix relative to the
148 // import file location.
149 const char* installDest = this->IEGen->GetDestination();
150 if(!cmSystemTools::FileIsFullPath(installDest))
152 std::string dest = installDest;
153 os << "# Compute the installation prefix relative to this file.\n"
154 << "GET_FILENAME_COMPONENT(_IMPORT_PREFIX "
155 << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
159 "GET_FILENAME_COMPONENT(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
160 dest = cmSystemTools::GetFilenamePath(dest);
164 // Import location properties may reference this variable.
165 this->ImportPrefix = "${_IMPORT_PREFIX}/";
168 // Add each target in the set to the export.
169 for(std::vector<cmTargetExport*>::const_iterator
170 tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
171 tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
173 // Collect import properties for this target.
174 cmTargetExport const* te = *tei;
175 ImportPropertyMap properties;
176 std::set<std::string> importedLocations;
177 this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
178 properties, importedLocations);
179 this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
180 properties, importedLocations);
181 this->SetImportLocationProperty(config, suffix,
182 te->RuntimeGenerator, properties,
184 this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
185 properties, importedLocations);
186 this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
187 properties, importedLocations);
189 // If any file location was set for the target add it to the
191 if(!properties.empty())
193 // Get the rest of the target details.
194 std::vector<std::string> missingTargets;
195 this->SetImportDetailProperties(config, suffix,
196 te->Target, properties, missingTargets);
198 // TOOD: PUBLIC_HEADER_LOCATION
199 // This should wait until the build feature propagation stuff
200 // is done. Then this can be a propagated include directory.
201 // this->GenerateImportProperty(config, te->HeaderGenerator,
204 // Generate code in the export file.
205 this->GenerateMissingTargetsCheckCode(os, missingTargets);
206 this->GenerateImportPropertyCode(os, config, te->Target, properties);
207 this->GenerateImportedFileChecksCode(os, te->Target, properties,
212 this->GenerateImportedFileCheckLoop(os);
214 // Cleanup the import prefix variable.
215 if(!this->ImportPrefix.empty())
217 os << "# Cleanup temporary variables.\n"
218 << "SET(_IMPORT_PREFIX)\n"
223 //----------------------------------------------------------------------------
225 cmExportInstallFileGenerator
226 ::SetImportLocationProperty(const char* config, std::string const& suffix,
227 cmInstallTargetGenerator* itgen,
228 ImportPropertyMap& properties,
229 std::set<std::string>& importedLocations
232 // Skip rules that do not match this configuration.
233 if(!(itgen && itgen->InstallsForConfig(config)))
238 // Get the target to be installed.
239 cmTarget* target = itgen->GetTarget();
241 // Construct the installed location of the target.
242 std::string dest = itgen->GetDestination();
244 if(!cmSystemTools::FileIsFullPath(dest.c_str()))
246 // The target is installed relative to the installation prefix.
247 if(this->ImportPrefix.empty())
249 this->ComplainAboutImportPrefix(itgen);
251 value = this->ImportPrefix;
256 if(itgen->IsImportLibrary())
258 // Construct the property name.
259 std::string prop = "IMPORTED_IMPLIB";
262 // Append the installed file name.
263 value += itgen->GetInstallFilename(target, config,
264 cmInstallTargetGenerator::NameImplib);
266 // Store the property.
267 properties[prop] = value;
268 importedLocations.insert(prop);
272 // Construct the property name.
273 std::string prop = "IMPORTED_LOCATION";
276 // Append the installed file name.
277 if(target->IsFrameworkOnApple())
279 value += itgen->GetInstallFilename(target, config);
280 value += ".framework/";
281 value += itgen->GetInstallFilename(target, config);
283 else if(target->IsCFBundleOnApple())
285 const char *ext = target->GetProperty("BUNDLE_EXTENSION");
291 value += itgen->GetInstallFilename(target, config);
295 value += itgen->GetInstallFilename(target, config);
297 else if(target->IsAppBundleOnApple())
299 value += itgen->GetInstallFilename(target, config);
300 value += ".app/Contents/MacOS/";
301 value += itgen->GetInstallFilename(target, config);
305 value += itgen->GetInstallFilename(target, config,
306 cmInstallTargetGenerator::NameReal);
309 // Store the property.
310 properties[prop] = value;
311 importedLocations.insert(prop);
315 //----------------------------------------------------------------------------
317 cmExportInstallFileGenerator::HandleMissingTarget(
318 std::string& link_libs, std::vector<std::string>& missingTargets,
319 cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
321 std::string name = dependee->GetName();
322 std::vector<std::string> namespaces = this->FindNamespaces(mf, name);
323 int targetOccurrences = (int)namespaces.size();
324 if (targetOccurrences == 1)
326 std::string missingTarget = namespaces[0];
327 missingTarget += name;
328 link_libs += missingTarget;
329 missingTargets.push_back(missingTarget);
333 // We are not appending, so all exported targets should be
334 // known here. This is probably user-error.
335 this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
339 //----------------------------------------------------------------------------
340 std::vector<std::string>
341 cmExportInstallFileGenerator
342 ::FindNamespaces(cmMakefile* mf, const std::string& name)
344 std::vector<std::string> namespaces;
345 cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
346 const cmExportSetMap& exportSets = gg->GetExportSets();
348 for(cmExportSetMap::const_iterator expIt = exportSets.begin();
349 expIt != exportSets.end();
352 const cmExportSet* exportSet = expIt->second;
353 std::vector<cmTargetExport*> const* targets =
354 exportSet->GetTargetExports();
356 bool containsTarget = false;
357 for(unsigned int i=0; i<targets->size(); i++)
359 if (name == (*targets)[i]->Target->GetName())
361 containsTarget = true;
368 std::vector<cmInstallExportGenerator const*> const* installs =
369 exportSet->GetInstallations();
370 for(unsigned int i=0; i<installs->size(); i++)
372 namespaces.push_back((*installs)[i]->GetNamespace());
381 //----------------------------------------------------------------------------
383 cmExportInstallFileGenerator
384 ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
386 const char* installDest = this->IEGen->GetDestination();
388 e << "INSTALL(EXPORT \""
389 << this->IEGen->GetExportSet()->GetName()
390 << "\") given absolute "
391 << "DESTINATION \"" << installDest << "\" but the export "
392 << "references an installation of target \""
393 << itgen->GetTarget()->GetName() << "\" which has relative "
394 << "DESTINATION \"" << itgen->GetDestination() << "\".";
395 cmSystemTools::Error(e.str().c_str());
398 //----------------------------------------------------------------------------
400 cmExportInstallFileGenerator
401 ::ComplainAboutMissingTarget(cmTarget* depender,
406 e << "INSTALL(EXPORT \""
407 << this->IEGen->GetExportSet()->GetName()
409 << "includes target \"" << depender->GetName()
410 << "\" which requires target \"" << dependee->GetName() << "\" ";
411 if (occurrences == 0)
413 e << "that is not in the export set.";
417 e << "that is not in this export set, but " << occurrences
418 << " times in others.";
420 cmSystemTools::Error(e.str().c_str());