Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmExportInstallFileGenerator.cxx
blob70860ad23512a3a1c8a111700624f161c9aa5b90
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExportInstallFileGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-01-07 19:16:28 $
7 Version: $Revision: 1.9 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmExportInstallFileGenerator.h"
19 #include "cmGeneratedFileStream.h"
20 #include "cmInstallExportGenerator.h"
21 #include "cmInstallTargetGenerator.h"
23 //----------------------------------------------------------------------------
24 cmExportInstallFileGenerator
25 ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
26 InstallExportGenerator(iegen)
30 //----------------------------------------------------------------------------
31 std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
33 std::string glob = this->FileBase;
34 glob += "-*";
35 glob += this->FileExt;
36 return glob;
39 //----------------------------------------------------------------------------
40 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
42 // Create all the imported targets.
43 for(std::vector<cmTargetExport*>::const_iterator
44 tei = this->ExportSet->begin();
45 tei != this->ExportSet->end(); ++tei)
47 cmTargetExport* te = *tei;
48 if(this->ExportedTargets.insert(te->Target).second)
50 this->GenerateImportTargetCode(os, te->Target);
52 else
54 cmOStringStream e;
55 e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
56 << "includes target \"" << te->Target->GetName()
57 << "\" more than once in the export set.";
58 cmSystemTools::Error(e.str().c_str());
59 return false;
63 // Now load per-configuration properties for them.
64 os << "# Load information for each installed configuration.\n"
65 << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
66 << "FILE(GLOB CONFIG_FILES \"${_DIR}/"
67 << this->GetConfigImportFileGlob() << "\")\n"
68 << "FOREACH(f ${CONFIG_FILES})\n"
69 << " INCLUDE(${f})\n"
70 << "ENDFOREACH(f)\n"
71 << "\n";
73 // Generate an import file for each configuration.
74 bool result = true;
75 for(std::vector<std::string>::const_iterator
76 ci = this->Configurations.begin();
77 ci != this->Configurations.end(); ++ci)
79 if(!this->GenerateImportFileConfig(ci->c_str()))
81 result = false;
84 return result;
87 //----------------------------------------------------------------------------
88 bool
89 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config)
91 // Skip configurations not enabled for this export.
92 if(!this->InstallExportGenerator->InstallsForConfig(config))
94 return true;
97 // Construct the name of the file to generate.
98 std::string fileName = this->FileDir;
99 fileName += "/";
100 fileName += this->FileBase;
101 fileName += "-";
102 if(config && *config)
104 fileName += cmSystemTools::LowerCase(config);
106 else
108 fileName += "noconfig";
110 fileName += this->FileExt;
112 // Open the output file to generate it.
113 cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
114 if(!exportFileStream)
116 std::string se = cmSystemTools::GetLastSystemError();
117 cmOStringStream e;
118 e << "cannot write to file \"" << fileName.c_str()
119 << "\": " << se;
120 cmSystemTools::Error(e.str().c_str());
121 return false;
123 std::ostream& os = exportFileStream;
125 // Start with the import file header.
126 this->GenerateImportHeaderCode(os, config);
128 // Generate the per-config target information.
129 this->GenerateImportConfig(os, config);
131 // End with the import file footer.
132 this->GenerateImportFooterCode(os);
134 // Record this per-config import file.
135 this->ConfigImportFiles[config] = fileName;
137 return true;
140 //----------------------------------------------------------------------------
141 void
142 cmExportInstallFileGenerator
143 ::GenerateImportTargetsConfig(std::ostream& os,
144 const char* config, std::string const& suffix)
146 // Add code to compute the installation prefix relative to the
147 // import file location.
148 const char* installDest = this->InstallExportGenerator->GetDestination();
149 if(!cmSystemTools::FileIsFullPath(installDest))
151 std::string dest = installDest;
152 os << "# Compute the installation prefix relative to this file.\n"
153 << "GET_FILENAME_COMPONENT(_IMPORT_PREFIX "
154 << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
155 while(!dest.empty())
157 os <<
158 "GET_FILENAME_COMPONENT(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
159 dest = cmSystemTools::GetFilenamePath(dest);
161 os << "\n";
163 // Import location properties may reference this variable.
164 this->ImportPrefix = "${_IMPORT_PREFIX}/";
167 // Add each target in the set to the export.
168 for(std::vector<cmTargetExport*>::const_iterator
169 tei = this->ExportSet->begin();
170 tei != this->ExportSet->end(); ++tei)
172 // Collect import properties for this target.
173 cmTargetExport* te = *tei;
174 ImportPropertyMap properties;
175 this->SetImportLocationProperty(config, suffix,
176 te->ArchiveGenerator, properties);
177 this->SetImportLocationProperty(config, suffix,
178 te->LibraryGenerator, properties);
179 this->SetImportLocationProperty(config, suffix,
180 te->RuntimeGenerator, properties);
181 this->SetImportLocationProperty(config, suffix,
182 te->FrameworkGenerator, properties);
183 this->SetImportLocationProperty(config, suffix,
184 te->BundleGenerator, properties);
186 // If any file location was set for the target add it to the
187 // import file.
188 if(!properties.empty())
190 // Get the rest of the target details.
191 this->SetImportDetailProperties(config, suffix,
192 te->Target, properties);
194 // TOOD: PUBLIC_HEADER_LOCATION
195 // This should wait until the build feature propagation stuff
196 // is done. Then this can be a propagated include directory.
197 // this->GenerateImportProperty(config, te->HeaderGenerator,
198 // properties);
200 // Generate code in the export file.
201 this->GenerateImportPropertyCode(os, config, te->Target, properties);
205 // Cleanup the import prefix variable.
206 if(!this->ImportPrefix.empty())
208 os << "# Cleanup temporary variables.\n"
209 << "SET(_IMPORT_PREFIX)\n"
210 << "\n";
214 //----------------------------------------------------------------------------
215 void
216 cmExportInstallFileGenerator
217 ::SetImportLocationProperty(const char* config, std::string const& suffix,
218 cmInstallTargetGenerator* itgen,
219 ImportPropertyMap& properties)
221 // Skip rules that do not match this configuration.
222 if(!(itgen && itgen->InstallsForConfig(config)))
224 return;
227 // Get the target to be installed.
228 cmTarget* target = itgen->GetTarget();
230 // Construct the installed location of the target.
231 std::string dest = itgen->GetDestination();
232 std::string value;
233 if(!cmSystemTools::FileIsFullPath(dest.c_str()))
235 // The target is installed relative to the installation prefix.
236 if(this->ImportPrefix.empty())
238 this->ComplainAboutImportPrefix(itgen);
240 value = this->ImportPrefix;
242 value += dest;
243 value += "/";
245 if(itgen->IsImportLibrary())
247 // Construct the property name.
248 std::string prop = "IMPORTED_IMPLIB";
249 prop += suffix;
251 // Append the installed file name.
252 value += itgen->GetInstallFilename(target, config,
253 cmInstallTargetGenerator::NameImplib);
255 // Store the property.
256 properties[prop] = value;
258 else
260 // Construct the property name.
261 std::string prop = "IMPORTED_LOCATION";
262 prop += suffix;
264 // Append the installed file name.
265 if(target->IsFrameworkOnApple())
267 value += itgen->GetInstallFilename(target, config);
268 value += ".framework/";
269 value += itgen->GetInstallFilename(target, config);
271 else if(target->IsAppBundleOnApple())
273 value += itgen->GetInstallFilename(target, config);
274 value += ".app/Contents/MacOS/";
275 value += itgen->GetInstallFilename(target, config);
277 else
279 value += itgen->GetInstallFilename(target, config,
280 cmInstallTargetGenerator::NameReal);
283 // Store the property.
284 properties[prop] = value;
288 //----------------------------------------------------------------------------
289 void
290 cmExportInstallFileGenerator
291 ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
293 const char* installDest = this->InstallExportGenerator->GetDestination();
294 cmOStringStream e;
295 e << "INSTALL(EXPORT \"" << this->Name << "\") given absolute "
296 << "DESTINATION \"" << installDest << "\" but the export "
297 << "references an installation of target \""
298 << itgen->GetTarget()->GetName() << "\" which has relative "
299 << "DESTINATION \"" << itgen->GetDestination() << "\".";
300 cmSystemTools::Error(e.str().c_str());
303 //----------------------------------------------------------------------------
304 void
305 cmExportInstallFileGenerator
306 ::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee)
308 cmOStringStream e;
309 e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
310 << "includes target \"" << depender->GetName()
311 << "\" which requires target \"" << dependee->GetName()
312 << "\" that is not in the export set.";
313 cmSystemTools::Error(e.str().c_str());