1
/*=========================================================================
3
Program: CMake - Cross-Platform Makefile Generator
4
Module: $RCSfile: cmMakefileExecutableTargetGenerator.cxx,v $
6
Date: $Date: 2006/05/16 18:04:08 $
7
Version: $Revision: 1.12.2.3 $
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 "cmGlobalGenerator.h"
21
#include "cmLocalUnixMakefileGenerator3.h"
22
#include "cmMakefile.h"
23
#include "cmSourceFile.h"
26
//----------------------------------------------------------------------------
27
void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
29
// create the build.make file and directory, put in the common blocks
30
this->CreateRuleFile();
32
// Add in any rules for custom commands
33
this->WriteCustomCommandsForTarget();
35
// write in rules for object files
36
this->WriteCommonCodeRules();
38
// Write the dependency generation rule.
39
this->WriteTargetDependRules();
41
// write the link rules
42
this->WriteExecutableRule(false);
43
if(this->Target->NeedRelinkBeforeInstall())
45
// Write rules to link an installable version of the target.
46
this->WriteExecutableRule(true);
49
// Write the requires target.
50
this->WriteTargetRequiresRules();
53
this->WriteTargetCleanRules();
56
this->CloseFileStreams();
61
//----------------------------------------------------------------------------
62
void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
64
std::vector<std::string> commands;
66
std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
67
std::string objTarget;
69
// Build list of dependencies.
70
std::vector<std::string> depends;
71
for(std::vector<std::string>::const_iterator obj = this->Objects.begin();
72
obj != this->Objects.end(); ++obj)
76
depends.push_back(objTarget);
79
// Add dependencies on targets that must be built first.
80
this->AppendTargetDepends(depends);
82
// Add a dependency on the rule file itself.
83
this->LocalGenerator->AppendRuleDepend(depends,
84
this->BuildFileNameFull.c_str());
86
for(std::vector<std::string>::const_iterator obj =
87
this->ExternalObjects.begin();
88
obj != this->ExternalObjects.end(); ++obj)
90
depends.push_back(*obj);
93
// from here up is the same for exe or lib
95
// Get the name of the executable to generate.
96
std::string targetName;
97
std::string targetNameReal;
98
this->Target->GetExecutableNames
99
(targetName, targetNameReal,
100
this->LocalGenerator->ConfigurationName.c_str());
102
// Construct the full path version of the names.
103
std::string outpath = this->LocalGenerator->ExecutableOutputPath;
104
if(outpath.length() == 0)
106
outpath = this->Makefile->GetStartOutputDirectory();
110
if(this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
112
// Make bundle directories
113
outpath += targetName;
114
outpath += ".app/Contents/MacOS/";
116
this->Makefile->GetModulesFile("MacOSXBundleInfo.plist.in");
117
if ( f1.size() == 0 )
119
cmSystemTools::Error("could not find Mac OSX bundle template file.");
122
this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
123
if ( macdir.size() == 0 )
125
macdir = this->Makefile->GetCurrentOutputDirectory();
127
if(macdir.size() && macdir[macdir.size()-1] != '/')
131
macdir += targetName;
132
macdir += ".app/Contents/";
134
std::vector<cmSourceFile*>::iterator sourceIt;
135
for ( sourceIt = this->Target->GetSourceFiles().begin();
136
sourceIt != this->Target->GetSourceFiles().end();
140
(*sourceIt)->GetProperty("MACOSX_PACKAGE_LOCATION");
143
std::string newDir = macdir;
145
if ( !cmSystemTools::MakeDirectory(newDir.c_str()) )
147
cmSystemTools::Error("Cannot create a subdirectory for \"",
148
newDir.c_str(), "\".");
154
// Configure the Info.plist file. Note that it needs the executable name
156
std::string f2 = macdir + "Info.plist";
158
cmSystemTools::MakeDirectory(macdir.c_str());
159
this->Makefile->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME",
161
this->Makefile->ConfigureFile(f1.c_str(), f2.c_str(),
162
false, false, false);
167
outpath = this->Makefile->GetStartOutputDirectory();
168
outpath += "/CMakeFiles/CMakeRelink.dir";
169
cmSystemTools::MakeDirectory(outpath.c_str());
172
std::string targetFullPath = outpath + targetName;
173
std::string targetFullPathReal = outpath + targetNameReal;
174
std::string targetFullPathPDB = outpath + this->Target->GetName();
175
targetFullPathPDB += ".pdb";
176
std::string targetOutPathPDB =
177
this->Convert(targetFullPathPDB.c_str(),
178
cmLocalGenerator::FULL,
179
cmLocalGenerator::MAKEFILE);
180
// Convert to the output path to use in constructing commands.
181
std::string targetOutPath =
182
this->Convert(targetFullPath.c_str(),
183
cmLocalGenerator::START_OUTPUT,
184
cmLocalGenerator::MAKEFILE);
185
std::string targetOutPathReal =
186
this->Convert(targetFullPathReal.c_str(),
187
cmLocalGenerator::START_OUTPUT,
188
cmLocalGenerator::MAKEFILE);
190
// Get the language to use for linking this executable.
191
const char* linkLanguage =
192
this->Target->GetLinkerLanguage(this->GlobalGenerator);
194
// Make sure we have a link language.
197
cmSystemTools::Error("Cannot determine link language for target \"",
198
this->Target->GetName(), "\".");
202
// Add the link message.
203
std::string buildEcho = "Linking ";
204
buildEcho += linkLanguage;
205
buildEcho += " executable ";
206
buildEcho += targetOutPath;
207
this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
208
cmLocalUnixMakefileGenerator3::EchoLink);
210
// Build a list of compiler flags and linker flags.
212
std::string linkFlags;
214
// Add flags to deal with shared libraries. Any library being
215
// linked in might be shared, so always use shared flags for an
217
this->LocalGenerator->AddSharedFlags(linkFlags, linkLanguage, true);
219
// Add flags to create an executable.
220
this->LocalGenerator->
221
AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",
222
this->LocalGenerator->ConfigurationName.c_str());
225
if(this->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))
227
this->LocalGenerator->AppendFlags
228
(linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
232
this->LocalGenerator->AppendFlags
233
(linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
236
// Add language-specific flags.
238
->AddLanguageFlags(flags, linkLanguage,
239
this->LocalGenerator->ConfigurationName.c_str());
241
// Add target-specific linker flags.
242
this->LocalGenerator->AppendFlags
243
(linkFlags, this->Target->GetProperty("LINK_FLAGS"));
244
std::string linkFlagsConfig = "LINK_FLAGS_";
246
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
247
this->LocalGenerator->AppendFlags
248
(linkFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
250
// Construct a list of files associated with this executable that
251
// may need to be cleaned.
252
std::vector<std::string> exeCleanFiles;
254
std::string cleanName;
255
std::string cleanRealName;
256
this->Target->GetExecutableCleanNames
257
(cleanName, cleanRealName,
258
this->LocalGenerator->ConfigurationName.c_str());
260
std::string cleanFullName = outpath + cleanName;
261
std::string cleanFullRealName = outpath + cleanRealName;
262
exeCleanFiles.push_back(this->Convert(cleanFullName.c_str(),
263
cmLocalGenerator::START_OUTPUT,
264
cmLocalGenerator::UNCHANGED));
265
if(cleanRealName != cleanName)
267
exeCleanFiles.push_back(this->Convert(cleanFullRealName.c_str(),
268
cmLocalGenerator::START_OUTPUT,
269
cmLocalGenerator::UNCHANGED));
273
// Add a command to remove any existing files for this executable.
274
std::vector<std::string> commands1;
275
this->LocalGenerator->AppendCleanCommand(commands1, exeCleanFiles,
276
*this->Target, "target");
277
this->LocalGenerator->CreateCDCommand
279
this->Makefile->GetStartOutputDirectory(),
280
this->Makefile->GetHomeOutputDirectory());
282
commands.insert(commands.end(), commands1.begin(), commands1.end());
285
// Add the pre-build and pre-link rules building but not when relinking.
289
->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
291
->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
294
// Construct the main link rule.
295
std::string linkRuleVar = "CMAKE_";
296
linkRuleVar += linkLanguage;
297
linkRuleVar += "_LINK_EXECUTABLE";
298
std::string linkRule =
299
this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
300
cmSystemTools::ExpandListArgument(linkRule, commands1);
301
this->LocalGenerator->CreateCDCommand
303
this->Makefile->GetStartOutputDirectory(),
304
this->Makefile->GetHomeOutputDirectory());
305
commands.insert(commands.end(), commands1.begin(), commands1.end());
307
// Add a rule to create necessary symlinks for the library.
308
if(targetOutPath != targetOutPathReal)
310
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
311
symlink += targetOutPathReal;
313
symlink += targetOutPath;
314
commands.push_back(symlink);
316
commands1.push_back(symlink);
317
this->LocalGenerator->CreateCDCommand(commands1,
318
this->Makefile->GetStartOutputDirectory(),
319
this->Makefile->GetHomeOutputDirectory());
320
commands.insert(commands.end(), commands1.begin(), commands1.end());
323
// Add the post-build rules when building but not when relinking.
326
this->LocalGenerator->
327
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
330
// Collect up flags to link in needed libraries.
331
cmOStringStream linklibs;
332
this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
334
// Construct object file lists that may be needed to expand the
336
std::string variableName;
337
std::string variableNameExternal;
338
this->WriteObjectsVariable(variableName, variableNameExternal);
339
std::string buildObjs = "$(";
340
buildObjs += variableName;
342
buildObjs += variableNameExternal;
344
std::string cleanObjs = "$(";
345
cleanObjs += variableName;
348
cmLocalGenerator::RuleVariables vars;
349
vars.Language = linkLanguage;
350
vars.Objects = buildObjs.c_str();
351
vars.Target = targetOutPathReal.c_str();
352
vars.TargetPDB = targetOutPathPDB.c_str();
353
std::string linkString = linklibs.str();
354
vars.LinkLibraries = linkString.c_str();
355
vars.Flags = flags.c_str();
356
vars.LinkFlags = linkFlags.c_str();
357
// Expand placeholders in the commands.
358
for(std::vector<std::string>::iterator i = commands.begin();
359
i != commands.end(); ++i)
361
this->LocalGenerator->ExpandRuleVariables(*i, vars);
364
// Write the build rule.
365
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,
367
targetFullPathReal.c_str(),
368
depends, commands, false);
370
// The symlink name for the target should depend on the real target
371
// so if the target version changes it rebuilds and recreates the
373
if(targetFullPath != targetFullPathReal)
377
depends.push_back(targetFullPathReal.c_str());
378
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
379
targetFullPath.c_str(),
380
depends, commands, false);
383
// Write convenience targets.
384
std::string dir = this->Makefile->GetStartOutputDirectory();
386
dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
387
std::string buildTargetRuleName = dir;
388
buildTargetRuleName += relink?"/preinstall":"/build";
389
buildTargetRuleName =
390
this->Convert(buildTargetRuleName.c_str(),
391
cmLocalGenerator::HOME_OUTPUT,
392
cmLocalGenerator::MAKEFILE);
393
this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
394
targetFullPath.c_str(),
395
buildTargetRuleName.c_str());
397
// Clean all the possible executable names and symlinks and object files.
398
this->CleanFiles.insert(this->CleanFiles.end(),
399
exeCleanFiles.begin(),
400
exeCleanFiles.end());
401
this->CleanFiles.insert(this->CleanFiles.end(),
402
this->Objects.begin(),
403
this->Objects.end());