1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakefileExecutableTargetGenerator.cxx,v $
6 Date: $Date: 2009-03-16 20:55:58 $
7 Version: $Revision: 1.55 $
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 "cmMakefileExecutableTargetGenerator.h"
19 #include "cmGeneratedFileStream.h"
20 #include "cmGlobalUnixMakefileGenerator3.h"
21 #include "cmLocalUnixMakefileGenerator3.h"
22 #include "cmMakefile.h"
23 #include "cmSourceFile.h"
27 //----------------------------------------------------------------------------
28 cmMakefileExecutableTargetGenerator
29 ::cmMakefileExecutableTargetGenerator(cmTarget
* target
):
30 cmMakefileTargetGenerator(target
)
32 this->CustomCommandDriver
= OnDepends
;
33 this->Target
->GetExecutableNames(
34 this->TargetNameOut
, this->TargetNameReal
, this->TargetNameImport
,
35 this->TargetNamePDB
, this->LocalGenerator
->ConfigurationName
.c_str());
37 if(this->Target
->IsAppBundleOnApple())
39 this->MacContentDirectory
= this->Target
->GetDirectory();
40 this->MacContentDirectory
+= "/";
41 this->MacContentDirectory
+= this->TargetNameOut
;
42 this->MacContentDirectory
+= ".app/Contents/";
46 //----------------------------------------------------------------------------
47 void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
49 // create the build.make file and directory, put in the common blocks
50 this->CreateRuleFile();
52 // write rules used to help build object files
53 this->WriteCommonCodeRules();
55 // write in rules for object files and custom commands
56 this->WriteTargetBuildRules();
58 // write the per-target per-language flags
59 this->WriteTargetLanguageFlags();
61 // write the link rules
62 this->WriteExecutableRule(false);
63 if(this->Target
->NeedRelinkBeforeInstall())
65 // Write rules to link an installable version of the target.
66 this->WriteExecutableRule(true);
69 // Write the requires target.
70 this->WriteTargetRequiresRules();
73 this->WriteTargetCleanRules();
75 // Write the dependency generation rule. This must be done last so
76 // that multiple output pair information is available.
77 this->WriteTargetDependRules();
80 this->CloseFileStreams();
85 //----------------------------------------------------------------------------
86 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink
)
88 std::vector
<std::string
> commands
;
90 std::string relPath
= this->LocalGenerator
->GetHomeRelativeOutputPath();
91 std::string objTarget
;
93 // Build list of dependencies.
94 std::vector
<std::string
> depends
;
95 for(std::vector
<std::string
>::const_iterator obj
= this->Objects
.begin();
96 obj
!= this->Objects
.end(); ++obj
)
100 depends
.push_back(objTarget
);
103 // Add dependencies on targets that must be built first.
104 this->AppendTargetDepends(depends
);
106 // Add a dependency on the rule file itself.
107 this->LocalGenerator
->AppendRuleDepend(depends
,
108 this->BuildFileNameFull
.c_str());
110 for(std::vector
<std::string
>::const_iterator obj
=
111 this->ExternalObjects
.begin();
112 obj
!= this->ExternalObjects
.end(); ++obj
)
114 depends
.push_back(*obj
);
117 // from here up is the same for exe or lib
119 // Get the name of the executable to generate.
120 std::string targetName
;
121 std::string targetNameReal
;
122 std::string targetNameImport
;
123 std::string targetNamePDB
;
124 this->Target
->GetExecutableNames
125 (targetName
, targetNameReal
, targetNameImport
, targetNamePDB
,
126 this->LocalGenerator
->ConfigurationName
.c_str());
128 // Construct the full path version of the names.
129 std::string outpath
= this->Target
->GetDirectory();
131 if(this->Target
->IsAppBundleOnApple())
133 this->CreateAppBundle(targetName
, outpath
);
135 std::string outpathImp
;
138 outpath
= this->Makefile
->GetStartOutputDirectory();
139 outpath
+= cmake::GetCMakeFilesDirectory();
140 outpath
+= "/CMakeRelink.dir";
141 cmSystemTools::MakeDirectory(outpath
.c_str());
143 if(!targetNameImport
.empty())
145 outpathImp
= outpath
;
150 cmSystemTools::MakeDirectory(outpath
.c_str());
151 if(!targetNameImport
.empty())
153 outpathImp
= this->Target
->GetDirectory(0, true);
154 cmSystemTools::MakeDirectory(outpathImp
.c_str());
158 std::string targetFullPath
= outpath
+ targetName
;
159 std::string targetFullPathReal
= outpath
+ targetNameReal
;
160 std::string targetFullPathPDB
= outpath
+ targetNamePDB
;
161 std::string targetFullPathImport
= outpathImp
+ targetNameImport
;
162 std::string targetOutPathPDB
=
163 this->Convert(targetFullPathPDB
.c_str(),
164 cmLocalGenerator::FULL
,
165 cmLocalGenerator::SHELL
);
166 // Convert to the output path to use in constructing commands.
167 std::string targetOutPath
=
168 this->Convert(targetFullPath
.c_str(),
169 cmLocalGenerator::START_OUTPUT
,
170 cmLocalGenerator::SHELL
);
171 std::string targetOutPathReal
=
172 this->Convert(targetFullPathReal
.c_str(),
173 cmLocalGenerator::START_OUTPUT
,
174 cmLocalGenerator::SHELL
);
175 std::string targetOutPathImport
=
176 this->Convert(targetFullPathImport
.c_str(),
177 cmLocalGenerator::START_OUTPUT
,
178 cmLocalGenerator::SHELL
);
180 // Get the language to use for linking this executable.
181 const char* linkLanguage
=
182 this->Target
->GetLinkerLanguage(this->GlobalGenerator
);
184 // Make sure we have a link language.
187 cmSystemTools::Error("Cannot determine link language for target \"",
188 this->Target
->GetName(), "\".");
192 if(!this->NoRuleMessages
)
194 // Add the link message.
195 std::string buildEcho
= "Linking ";
196 buildEcho
+= linkLanguage
;
197 buildEcho
+= " executable ";
198 buildEcho
+= targetOutPath
;
199 this->LocalGenerator
->AppendEcho(commands
, buildEcho
.c_str(),
200 cmLocalUnixMakefileGenerator3::EchoLink
);
203 // Build a list of compiler flags and linker flags.
205 std::string linkFlags
;
207 // Add flags to deal with shared libraries. Any library being
208 // linked in might be shared, so always use shared flags for an
210 this->LocalGenerator
->AddSharedFlags(linkFlags
, linkLanguage
, true);
212 // Add flags to create an executable.
213 this->LocalGenerator
->
214 AddConfigVariableFlags(linkFlags
, "CMAKE_EXE_LINKER_FLAGS",
215 this->LocalGenerator
->ConfigurationName
.c_str());
218 if(this->Target
->GetPropertyAsBool("WIN32_EXECUTABLE"))
220 this->LocalGenerator
->AppendFlags
221 (linkFlags
, this->Makefile
->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
225 this->LocalGenerator
->AppendFlags
226 (linkFlags
, this->Makefile
->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
229 // Add symbol export flags if necessary.
230 if(this->Target
->IsExecutableWithExports())
232 std::string export_flag_var
= "CMAKE_EXE_EXPORTS_";
233 export_flag_var
+= linkLanguage
;
234 export_flag_var
+= "_FLAG";
235 this->LocalGenerator
->AppendFlags
236 (linkFlags
, this->Makefile
->GetDefinition(export_flag_var
.c_str()));
239 // Add language-specific flags.
241 ->AddLanguageFlags(flags
, linkLanguage
,
242 this->LocalGenerator
->ConfigurationName
.c_str());
244 // Add target-specific linker flags.
245 this->LocalGenerator
->AppendFlags
246 (linkFlags
, this->Target
->GetProperty("LINK_FLAGS"));
247 std::string linkFlagsConfig
= "LINK_FLAGS_";
249 cmSystemTools::UpperCase(this->LocalGenerator
->ConfigurationName
.c_str());
250 this->LocalGenerator
->AppendFlags
251 (linkFlags
, this->Target
->GetProperty(linkFlagsConfig
.c_str()));
253 // Construct a list of files associated with this executable that
254 // may need to be cleaned.
255 std::vector
<std::string
> exeCleanFiles
;
257 std::string cleanName
;
258 std::string cleanRealName
;
259 std::string cleanImportName
;
260 std::string cleanPDBName
;
261 this->Target
->GetExecutableCleanNames
262 (cleanName
, cleanRealName
, cleanImportName
, cleanPDBName
,
263 this->LocalGenerator
->ConfigurationName
.c_str());
265 std::string cleanFullName
= outpath
+ cleanName
;
266 std::string cleanFullRealName
= outpath
+ cleanRealName
;
267 std::string cleanFullPDBName
= outpath
+ cleanPDBName
;
268 std::string cleanFullImportName
= outpathImp
+ cleanImportName
;
269 exeCleanFiles
.push_back(this->Convert(cleanFullName
.c_str(),
270 cmLocalGenerator::START_OUTPUT
,
271 cmLocalGenerator::UNCHANGED
));
273 // There may be a manifest file for this target. Add it to the
274 // clean set just in case.
275 exeCleanFiles
.push_back(this->Convert((cleanFullName
+".manifest").c_str(),
276 cmLocalGenerator::START_OUTPUT
,
277 cmLocalGenerator::UNCHANGED
));
279 if(cleanRealName
!= cleanName
)
281 exeCleanFiles
.push_back(this->Convert(cleanFullRealName
.c_str(),
282 cmLocalGenerator::START_OUTPUT
,
283 cmLocalGenerator::UNCHANGED
));
285 if(!cleanImportName
.empty())
287 exeCleanFiles
.push_back(this->Convert(cleanFullImportName
.c_str(),
288 cmLocalGenerator::START_OUTPUT
,
289 cmLocalGenerator::UNCHANGED
));
292 // List the PDB for cleaning only when the whole target is
293 // cleaned. We do not want to delete the .pdb file just before
294 // linking the target.
295 this->CleanFiles
.push_back
296 (this->Convert(cleanFullPDBName
.c_str(),
297 cmLocalGenerator::START_OUTPUT
,
298 cmLocalGenerator::UNCHANGED
));
301 // Add the pre-build and pre-link rules building but not when relinking.
305 ->AppendCustomCommands(commands
, this->Target
->GetPreBuildCommands(),
308 ->AppendCustomCommands(commands
, this->Target
->GetPreLinkCommands(),
312 // Determine whether a link script will be used.
313 bool useLinkScript
= this->GlobalGenerator
->GetUseLinkScript();
315 // Construct the main link rule.
316 std::vector
<std::string
> real_link_commands
;
317 std::string linkRuleVar
= "CMAKE_";
318 linkRuleVar
+= linkLanguage
;
319 linkRuleVar
+= "_LINK_EXECUTABLE";
320 std::string linkRule
=
321 this->Makefile
->GetRequiredDefinition(linkRuleVar
.c_str());
322 std::vector
<std::string
> commands1
;
323 cmSystemTools::ExpandListArgument(linkRule
, real_link_commands
);
324 if(this->Target
->IsExecutableWithExports())
326 // If a separate rule for creating an import library is specified
328 std::string implibRuleVar
= "CMAKE_";
329 implibRuleVar
+= linkLanguage
;
330 implibRuleVar
+= "_CREATE_IMPORT_LIBRARY";
331 if(const char* rule
=
332 this->Makefile
->GetDefinition(implibRuleVar
.c_str()))
334 cmSystemTools::ExpandListArgument(rule
, real_link_commands
);
338 // Select whether to use a response file for objects.
339 bool useResponseFile
= false;
341 std::string responseVar
= "CMAKE_";
342 responseVar
+= linkLanguage
;
343 responseVar
+= "_USE_RESPONSE_FILE_FOR_OBJECTS";
344 if(this->Makefile
->IsOn(responseVar
.c_str()))
346 useResponseFile
= true;
350 // Expand the rule variables.
352 // Set path conversion for link script shells.
353 this->LocalGenerator
->SetLinkScriptShell(useLinkScript
);
355 // Collect up flags to link in needed libraries.
356 cmOStringStream linklibs
;
357 this->LocalGenerator
->OutputLinkLibraries(linklibs
, *this->Target
, relink
);
359 // Construct object file lists that may be needed to expand the
361 std::string buildObjs
;
362 this->CreateObjectLists(useLinkScript
, false, useResponseFile
,
365 cmLocalGenerator::RuleVariables vars
;
366 vars
.RuleLauncher
= "RULE_LAUNCH_LINK";
367 vars
.CMTarget
= this->Target
;
368 vars
.Language
= linkLanguage
;
369 vars
.Objects
= buildObjs
.c_str();
370 vars
.Target
= targetOutPathReal
.c_str();
371 vars
.TargetPDB
= targetOutPathPDB
.c_str();
373 // Setup the target version.
374 std::string targetVersionMajor
;
375 std::string targetVersionMinor
;
377 cmOStringStream majorStream
;
378 cmOStringStream minorStream
;
381 this->Target
->GetTargetVersion(major
, minor
);
382 majorStream
<< major
;
383 minorStream
<< minor
;
384 targetVersionMajor
= majorStream
.str();
385 targetVersionMinor
= minorStream
.str();
387 vars
.TargetVersionMajor
= targetVersionMajor
.c_str();
388 vars
.TargetVersionMinor
= targetVersionMinor
.c_str();
390 std::string linkString
= linklibs
.str();
391 vars
.LinkLibraries
= linkString
.c_str();
392 vars
.Flags
= flags
.c_str();
393 vars
.LinkFlags
= linkFlags
.c_str();
394 // Expand placeholders in the commands.
395 this->LocalGenerator
->TargetImplib
= targetOutPathImport
;
396 for(std::vector
<std::string
>::iterator i
= real_link_commands
.begin();
397 i
!= real_link_commands
.end(); ++i
)
399 this->LocalGenerator
->ExpandRuleVariables(*i
, vars
);
401 this->LocalGenerator
->TargetImplib
= "";
403 // Restore path conversion to normal shells.
404 this->LocalGenerator
->SetLinkScriptShell(false);
407 // Optionally convert the build rule to use a script to avoid long
408 // command lines in the make shell.
411 // Use a link script.
412 const char* name
= (relink
? "relink.txt" : "link.txt");
413 this->CreateLinkScript(name
, real_link_commands
, commands1
, depends
);
417 // No link script. Just use the link rule directly.
418 commands1
= real_link_commands
;
420 this->LocalGenerator
->CreateCDCommand
422 this->Makefile
->GetStartOutputDirectory(),
423 cmLocalGenerator::HOME_OUTPUT
);
424 commands
.insert(commands
.end(), commands1
.begin(), commands1
.end());
427 // Add a rule to create necessary symlinks for the library.
428 if(targetOutPath
!= targetOutPathReal
)
430 std::string symlink
= "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
431 symlink
+= targetOutPathReal
;
433 symlink
+= targetOutPath
;
434 commands1
.push_back(symlink
);
435 this->LocalGenerator
->CreateCDCommand(commands1
,
436 this->Makefile
->GetStartOutputDirectory(),
437 cmLocalGenerator::HOME_OUTPUT
);
438 commands
.insert(commands
.end(), commands1
.begin(), commands1
.end());
442 // Add the post-build rules when building but not when relinking.
445 this->LocalGenerator
->
446 AppendCustomCommands(commands
, this->Target
->GetPostBuildCommands(),
450 // Write the build rule.
451 this->LocalGenerator
->WriteMakeRule(*this->BuildFileStream
,
453 targetFullPathReal
.c_str(),
454 depends
, commands
, false);
456 // The symlink name for the target should depend on the real target
457 // so if the target version changes it rebuilds and recreates the
459 if(targetFullPath
!= targetFullPathReal
)
463 depends
.push_back(targetFullPathReal
.c_str());
464 this->LocalGenerator
->WriteMakeRule(*this->BuildFileStream
, 0,
465 targetFullPath
.c_str(),
466 depends
, commands
, false);
469 // Write the main driver rule to build everything in this target.
470 this->WriteTargetDriverRule(targetFullPath
.c_str(), relink
);
472 // Clean all the possible executable names and symlinks.
473 this->CleanFiles
.insert(this->CleanFiles
.end(),
474 exeCleanFiles
.begin(),
475 exeCleanFiles
.end());
478 //----------------------------------------------------------------------------
480 cmMakefileExecutableTargetGenerator::CreateAppBundle(std::string
& targetName
,
481 std::string
& outpath
)
483 // Compute bundle directory names.
484 outpath
= this->MacContentDirectory
;
486 cmSystemTools::MakeDirectory(outpath
.c_str());
487 this->Makefile
->AddCMakeOutputFile(outpath
.c_str());
490 // Configure the Info.plist file. Note that it needs the executable name
492 std::string plist
= this->MacContentDirectory
+ "Info.plist";
493 this->LocalGenerator
->GenerateAppleInfoPList(this->Target
,
496 this->Makefile
->AddCMakeOutputFile(plist
.c_str());