1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakefileExecutableTargetGenerator.cxx,v $
6 Date: $Date: 2009-09-17 12:42:27 $
7 Version: $Revision: 1.62 $
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->ConfigName
);
37 if(this->Target
->IsAppBundleOnApple())
39 this->MacContentDirectory
= this->Target
->GetDirectory(this->ConfigName
);
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(this->ConfigName
))
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
,
128 // Construct the full path version of the names.
129 std::string outpath
= this->Target
->GetDirectory(this->ConfigName
);
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(this->ConfigName
, 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::NONE
,
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->ConfigName
);
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",
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
, this->ConfigName
);
243 // Add target-specific linker flags.
244 this->LocalGenerator
->AppendFlags
245 (linkFlags
, this->Target
->GetProperty("LINK_FLAGS"));
246 std::string linkFlagsConfig
= "LINK_FLAGS_";
247 linkFlagsConfig
+= cmSystemTools::UpperCase(this->ConfigName
);
248 this->LocalGenerator
->AppendFlags
249 (linkFlags
, this->Target
->GetProperty(linkFlagsConfig
.c_str()));
251 // Construct a list of files associated with this executable that
252 // may need to be cleaned.
253 std::vector
<std::string
> exeCleanFiles
;
254 exeCleanFiles
.push_back(this->Convert(targetFullPath
.c_str(),
255 cmLocalGenerator::START_OUTPUT
,
256 cmLocalGenerator::UNCHANGED
));
258 // There may be a manifest file for this target. Add it to the
259 // clean set just in case.
260 exeCleanFiles
.push_back(this->Convert((targetFullPath
+".manifest").c_str(),
261 cmLocalGenerator::START_OUTPUT
,
262 cmLocalGenerator::UNCHANGED
));
264 if(targetNameReal
!= targetName
)
266 exeCleanFiles
.push_back(this->Convert(targetFullPathReal
.c_str(),
267 cmLocalGenerator::START_OUTPUT
,
268 cmLocalGenerator::UNCHANGED
));
270 if(!targetNameImport
.empty())
272 exeCleanFiles
.push_back(this->Convert(targetFullPathImport
.c_str(),
273 cmLocalGenerator::START_OUTPUT
,
274 cmLocalGenerator::UNCHANGED
));
277 // List the PDB for cleaning only when the whole target is
278 // cleaned. We do not want to delete the .pdb file just before
279 // linking the target.
280 this->CleanFiles
.push_back
281 (this->Convert(targetFullPathPDB
.c_str(),
282 cmLocalGenerator::START_OUTPUT
,
283 cmLocalGenerator::UNCHANGED
));
285 // Add the pre-build and pre-link rules building but not when relinking.
289 ->AppendCustomCommands(commands
, this->Target
->GetPreBuildCommands(),
292 ->AppendCustomCommands(commands
, this->Target
->GetPreLinkCommands(),
296 // Determine whether a link script will be used.
297 bool useLinkScript
= this->GlobalGenerator
->GetUseLinkScript();
299 // Construct the main link rule.
300 std::vector
<std::string
> real_link_commands
;
301 std::string linkRuleVar
= "CMAKE_";
302 linkRuleVar
+= linkLanguage
;
303 linkRuleVar
+= "_LINK_EXECUTABLE";
304 std::string linkRule
=
305 this->Makefile
->GetRequiredDefinition(linkRuleVar
.c_str());
306 std::vector
<std::string
> commands1
;
307 cmSystemTools::ExpandListArgument(linkRule
, real_link_commands
);
308 if(this->Target
->IsExecutableWithExports())
310 // If a separate rule for creating an import library is specified
312 std::string implibRuleVar
= "CMAKE_";
313 implibRuleVar
+= linkLanguage
;
314 implibRuleVar
+= "_CREATE_IMPORT_LIBRARY";
315 if(const char* rule
=
316 this->Makefile
->GetDefinition(implibRuleVar
.c_str()))
318 cmSystemTools::ExpandListArgument(rule
, real_link_commands
);
322 // Select whether to use a response file for objects.
323 bool useResponseFile
= false;
325 std::string responseVar
= "CMAKE_";
326 responseVar
+= linkLanguage
;
327 responseVar
+= "_USE_RESPONSE_FILE_FOR_OBJECTS";
328 if(this->Makefile
->IsOn(responseVar
.c_str()))
330 useResponseFile
= true;
334 // Expand the rule variables.
336 // Set path conversion for link script shells.
337 this->LocalGenerator
->SetLinkScriptShell(useLinkScript
);
339 // Collect up flags to link in needed libraries.
340 cmOStringStream linklibs
;
341 this->LocalGenerator
->OutputLinkLibraries(linklibs
, *this->Target
, relink
);
343 // Construct object file lists that may be needed to expand the
345 std::string buildObjs
;
346 this->CreateObjectLists(useLinkScript
, false, useResponseFile
,
349 cmLocalGenerator::RuleVariables vars
;
350 vars
.RuleLauncher
= "RULE_LAUNCH_LINK";
351 vars
.CMTarget
= this->Target
;
352 vars
.Language
= linkLanguage
;
353 vars
.Objects
= buildObjs
.c_str();
354 vars
.Target
= targetOutPathReal
.c_str();
355 vars
.TargetPDB
= targetOutPathPDB
.c_str();
357 // Setup the target version.
358 std::string targetVersionMajor
;
359 std::string targetVersionMinor
;
361 cmOStringStream majorStream
;
362 cmOStringStream minorStream
;
365 this->Target
->GetTargetVersion(major
, minor
);
366 majorStream
<< major
;
367 minorStream
<< minor
;
368 targetVersionMajor
= majorStream
.str();
369 targetVersionMinor
= minorStream
.str();
371 vars
.TargetVersionMajor
= targetVersionMajor
.c_str();
372 vars
.TargetVersionMinor
= targetVersionMinor
.c_str();
374 std::string linkString
= linklibs
.str();
375 vars
.LinkLibraries
= linkString
.c_str();
376 vars
.Flags
= flags
.c_str();
377 vars
.LinkFlags
= linkFlags
.c_str();
378 // Expand placeholders in the commands.
379 this->LocalGenerator
->TargetImplib
= targetOutPathImport
;
380 for(std::vector
<std::string
>::iterator i
= real_link_commands
.begin();
381 i
!= real_link_commands
.end(); ++i
)
383 this->LocalGenerator
->ExpandRuleVariables(*i
, vars
);
385 this->LocalGenerator
->TargetImplib
= "";
387 // Restore path conversion to normal shells.
388 this->LocalGenerator
->SetLinkScriptShell(false);
391 // Optionally convert the build rule to use a script to avoid long
392 // command lines in the make shell.
395 // Use a link script.
396 const char* name
= (relink
? "relink.txt" : "link.txt");
397 this->CreateLinkScript(name
, real_link_commands
, commands1
, depends
);
401 // No link script. Just use the link rule directly.
402 commands1
= real_link_commands
;
404 this->LocalGenerator
->CreateCDCommand
406 this->Makefile
->GetStartOutputDirectory(),
407 cmLocalGenerator::HOME_OUTPUT
);
408 commands
.insert(commands
.end(), commands1
.begin(), commands1
.end());
411 // Add a rule to create necessary symlinks for the library.
412 if(targetOutPath
!= targetOutPathReal
)
414 std::string symlink
= "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
415 symlink
+= targetOutPathReal
;
417 symlink
+= targetOutPath
;
418 commands1
.push_back(symlink
);
419 this->LocalGenerator
->CreateCDCommand(commands1
,
420 this->Makefile
->GetStartOutputDirectory(),
421 cmLocalGenerator::HOME_OUTPUT
);
422 commands
.insert(commands
.end(), commands1
.begin(), commands1
.end());
426 // Add the post-build rules when building but not when relinking.
429 this->LocalGenerator
->
430 AppendCustomCommands(commands
, this->Target
->GetPostBuildCommands(),
434 // Write the build rule.
435 this->LocalGenerator
->WriteMakeRule(*this->BuildFileStream
,
437 targetFullPathReal
.c_str(),
438 depends
, commands
, false);
440 // The symlink name for the target should depend on the real target
441 // so if the target version changes it rebuilds and recreates the
443 if(targetFullPath
!= targetFullPathReal
)
447 depends
.push_back(targetFullPathReal
.c_str());
448 this->LocalGenerator
->WriteMakeRule(*this->BuildFileStream
, 0,
449 targetFullPath
.c_str(),
450 depends
, commands
, false);
453 // Write the main driver rule to build everything in this target.
454 this->WriteTargetDriverRule(targetFullPath
.c_str(), relink
);
456 // Clean all the possible executable names and symlinks.
457 this->CleanFiles
.insert(this->CleanFiles
.end(),
458 exeCleanFiles
.begin(),
459 exeCleanFiles
.end());
462 //----------------------------------------------------------------------------
464 cmMakefileExecutableTargetGenerator::CreateAppBundle(std::string
& targetName
,
465 std::string
& outpath
)
467 // Compute bundle directory names.
468 outpath
= this->MacContentDirectory
;
470 cmSystemTools::MakeDirectory(outpath
.c_str());
471 this->Makefile
->AddCMakeOutputFile(outpath
.c_str());
474 // Configure the Info.plist file. Note that it needs the executable name
476 std::string plist
= this->MacContentDirectory
+ "Info.plist";
477 this->LocalGenerator
->GenerateAppleInfoPList(this->Target
,
480 this->Makefile
->AddCMakeOutputFile(plist
.c_str());