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 "cmMakefileExecutableTargetGenerator.h"
14 #include "cmGeneratedFileStream.h"
15 #include "cmGlobalUnixMakefileGenerator3.h"
16 #include "cmLocalUnixMakefileGenerator3.h"
17 #include "cmMakefile.h"
18 #include "cmSourceFile.h"
22 //----------------------------------------------------------------------------
23 cmMakefileExecutableTargetGenerator
24 ::cmMakefileExecutableTargetGenerator(cmTarget* target):
25 cmMakefileTargetGenerator(target)
27 this->CustomCommandDriver = OnDepends;
28 this->Target->GetExecutableNames(
29 this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
30 this->TargetNamePDB, this->ConfigName);
32 this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
34 this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
37 //----------------------------------------------------------------------------
38 cmMakefileExecutableTargetGenerator
39 ::~cmMakefileExecutableTargetGenerator()
41 delete this->OSXBundleGenerator;
44 //----------------------------------------------------------------------------
45 void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
47 // create the build.make file and directory, put in the common blocks
48 this->CreateRuleFile();
50 // write rules used to help build object files
51 this->WriteCommonCodeRules();
53 // write the per-target per-language flags
54 this->WriteTargetLanguageFlags();
56 // write in rules for object files and custom commands
57 this->WriteTargetBuildRules();
59 // write the link rules
60 this->WriteExecutableRule(false);
61 if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
63 // Write rules to link an installable version of the target.
64 this->WriteExecutableRule(true);
67 // Write the requires target.
68 this->WriteTargetRequiresRules();
71 this->WriteTargetCleanRules();
73 // Write the dependency generation rule. This must be done last so
74 // that multiple output pair information is available.
75 this->WriteTargetDependRules();
78 this->CloseFileStreams();
83 //----------------------------------------------------------------------------
84 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
86 std::vector<std::string> commands;
88 // Build list of dependencies.
89 std::vector<std::string> depends;
90 this->AppendLinkDepends(depends);
92 // Get the name of the executable to generate.
93 std::string targetName;
94 std::string targetNameReal;
95 std::string targetNameImport;
96 std::string targetNamePDB;
97 this->Target->GetExecutableNames
98 (targetName, targetNameReal, targetNameImport, targetNamePDB,
101 // Construct the full path version of the names.
102 std::string outpath = this->Target->GetDirectory(this->ConfigName);
103 if(this->Target->IsAppBundleOnApple())
105 this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
108 std::string outpathImp;
111 outpath = this->Makefile->GetStartOutputDirectory();
112 outpath += cmake::GetCMakeFilesDirectory();
113 outpath += "/CMakeRelink.dir";
114 cmSystemTools::MakeDirectory(outpath.c_str());
116 if(!targetNameImport.empty())
118 outpathImp = outpath;
123 cmSystemTools::MakeDirectory(outpath.c_str());
124 if(!targetNameImport.empty())
126 outpathImp = this->Target->GetDirectory(this->ConfigName, true);
127 cmSystemTools::MakeDirectory(outpathImp.c_str());
132 std::string pdbOutputPath = this->Target->GetPDBDirectory();
133 cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
134 pdbOutputPath += "/";
136 std::string targetFullPath = outpath + targetName;
137 std::string targetFullPathReal = outpath + targetNameReal;
138 std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
139 std::string targetFullPathImport = outpathImp + targetNameImport;
140 std::string targetOutPathPDB =
141 this->Convert(targetFullPathPDB.c_str(),
142 cmLocalGenerator::NONE,
143 cmLocalGenerator::SHELL);
144 // Convert to the output path to use in constructing commands.
145 std::string targetOutPath =
146 this->Convert(targetFullPath.c_str(),
147 cmLocalGenerator::START_OUTPUT,
148 cmLocalGenerator::SHELL);
149 std::string targetOutPathReal =
150 this->Convert(targetFullPathReal.c_str(),
151 cmLocalGenerator::START_OUTPUT,
152 cmLocalGenerator::SHELL);
153 std::string targetOutPathImport =
154 this->Convert(targetFullPathImport.c_str(),
155 cmLocalGenerator::START_OUTPUT,
156 cmLocalGenerator::SHELL);
158 // Get the language to use for linking this executable.
159 const char* linkLanguage =
160 this->Target->GetLinkerLanguage(this->ConfigName);
162 // Make sure we have a link language.
165 cmSystemTools::Error("Cannot determine link language for target \"",
166 this->Target->GetName(), "\".");
170 if(!this->NoRuleMessages)
172 // Add the link message.
173 std::string buildEcho = "Linking ";
174 buildEcho += linkLanguage;
175 buildEcho += " executable ";
176 buildEcho += targetOutPath;
177 this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
178 cmLocalUnixMakefileGenerator3::EchoLink);
181 // Build a list of compiler flags and linker flags.
183 std::string linkFlags;
185 // Add flags to create an executable.
186 this->LocalGenerator->
187 AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",
191 if(this->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))
193 this->LocalGenerator->AppendFlags
194 (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
198 this->LocalGenerator->AppendFlags
199 (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
202 // Add symbol export flags if necessary.
203 if(this->Target->IsExecutableWithExports())
205 std::string export_flag_var = "CMAKE_EXE_EXPORTS_";
206 export_flag_var += linkLanguage;
207 export_flag_var += "_FLAG";
208 this->LocalGenerator->AppendFlags
209 (linkFlags, this->Makefile->GetDefinition(export_flag_var.c_str()));
212 // Add language feature flags.
213 this->AddFeatureFlags(flags, linkLanguage);
215 this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
216 linkLanguage, this->ConfigName);
218 // Add target-specific linker flags.
219 this->LocalGenerator->AppendFlags
220 (linkFlags, this->Target->GetProperty("LINK_FLAGS"));
221 std::string linkFlagsConfig = "LINK_FLAGS_";
222 linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
223 this->LocalGenerator->AppendFlags
224 (linkFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
226 this->AddModuleDefinitionFlag(linkFlags);
228 // Construct a list of files associated with this executable that
229 // may need to be cleaned.
230 std::vector<std::string> exeCleanFiles;
231 exeCleanFiles.push_back(this->Convert(targetFullPath.c_str(),
232 cmLocalGenerator::START_OUTPUT,
233 cmLocalGenerator::UNCHANGED));
235 // There may be a manifest file for this target. Add it to the
236 // clean set just in case.
237 exeCleanFiles.push_back(this->Convert((targetFullPath+".manifest").c_str(),
238 cmLocalGenerator::START_OUTPUT,
239 cmLocalGenerator::UNCHANGED));
241 if(targetNameReal != targetName)
243 exeCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),
244 cmLocalGenerator::START_OUTPUT,
245 cmLocalGenerator::UNCHANGED));
247 if(!targetNameImport.empty())
249 exeCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),
250 cmLocalGenerator::START_OUTPUT,
251 cmLocalGenerator::UNCHANGED));
253 if(this->Target->GetImplibGNUtoMS(targetFullPathImport, implib))
255 exeCleanFiles.push_back(this->Convert(implib.c_str(),
256 cmLocalGenerator::START_OUTPUT,
257 cmLocalGenerator::UNCHANGED));
261 // List the PDB for cleaning only when the whole target is
262 // cleaned. We do not want to delete the .pdb file just before
263 // linking the target.
264 this->CleanFiles.push_back
265 (this->Convert(targetFullPathPDB.c_str(),
266 cmLocalGenerator::START_OUTPUT,
267 cmLocalGenerator::UNCHANGED));
269 // Add the pre-build and pre-link rules building but not when relinking.
273 ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands(),
276 ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands(),
280 // Determine whether a link script will be used.
281 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
283 // Construct the main link rule.
284 std::vector<std::string> real_link_commands;
285 std::string linkRuleVar = "CMAKE_";
286 linkRuleVar += linkLanguage;
287 linkRuleVar += "_LINK_EXECUTABLE";
288 std::string linkRule = this->GetLinkRule(linkRuleVar.c_str());
289 std::vector<std::string> commands1;
290 cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
291 if(this->Target->IsExecutableWithExports())
293 // If a separate rule for creating an import library is specified
295 std::string implibRuleVar = "CMAKE_";
296 implibRuleVar += linkLanguage;
297 implibRuleVar += "_CREATE_IMPORT_LIBRARY";
298 if(const char* rule =
299 this->Makefile->GetDefinition(implibRuleVar.c_str()))
301 cmSystemTools::ExpandListArgument(rule, real_link_commands);
305 // Select whether to use a response file for objects.
306 bool useResponseFile = false;
308 std::string responseVar = "CMAKE_";
309 responseVar += linkLanguage;
310 responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
311 if(this->Makefile->IsOn(responseVar.c_str()))
313 useResponseFile = true;
317 // Expand the rule variables.
319 // Set path conversion for link script shells.
320 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
322 // Collect up flags to link in needed libraries.
323 std::string linkLibs;
324 std::string frameworkPath;
325 std::string linkPath;
326 this->LocalGenerator->OutputLinkLibraries(linkLibs, frameworkPath, linkPath,
327 *this->GeneratorTarget,
329 linkLibs = frameworkPath + linkPath + linkLibs;
330 // Construct object file lists that may be needed to expand the
332 std::string buildObjs;
333 this->CreateObjectLists(useLinkScript, false, useResponseFile,
336 cmLocalGenerator::RuleVariables vars;
337 vars.RuleLauncher = "RULE_LAUNCH_LINK";
338 vars.CMTarget = this->Target;
339 vars.Language = linkLanguage;
340 vars.Objects = buildObjs.c_str();
341 std::string objectDir = this->Target->GetSupportDirectory();
342 objectDir = this->Convert(objectDir.c_str(),
343 cmLocalGenerator::START_OUTPUT,
344 cmLocalGenerator::SHELL);
345 vars.ObjectDir = objectDir.c_str();
346 vars.Target = targetOutPathReal.c_str();
347 vars.TargetPDB = targetOutPathPDB.c_str();
349 // Setup the target version.
350 std::string targetVersionMajor;
351 std::string targetVersionMinor;
353 cmOStringStream majorStream;
354 cmOStringStream minorStream;
357 this->Target->GetTargetVersion(major, minor);
358 majorStream << major;
359 minorStream << minor;
360 targetVersionMajor = majorStream.str();
361 targetVersionMinor = minorStream.str();
363 vars.TargetVersionMajor = targetVersionMajor.c_str();
364 vars.TargetVersionMinor = targetVersionMinor.c_str();
366 vars.LinkLibraries = linkLibs.c_str();
367 vars.Flags = flags.c_str();
368 vars.LinkFlags = linkFlags.c_str();
369 // Expand placeholders in the commands.
370 this->LocalGenerator->TargetImplib = targetOutPathImport;
371 for(std::vector<std::string>::iterator i = real_link_commands.begin();
372 i != real_link_commands.end(); ++i)
374 this->LocalGenerator->ExpandRuleVariables(*i, vars);
376 this->LocalGenerator->TargetImplib = "";
378 // Restore path conversion to normal shells.
379 this->LocalGenerator->SetLinkScriptShell(false);
382 // Optionally convert the build rule to use a script to avoid long
383 // command lines in the make shell.
386 // Use a link script.
387 const char* name = (relink? "relink.txt" : "link.txt");
388 this->CreateLinkScript(name, real_link_commands, commands1, depends);
392 // No link script. Just use the link rule directly.
393 commands1 = real_link_commands;
395 this->LocalGenerator->CreateCDCommand
397 this->Makefile->GetStartOutputDirectory(),
398 cmLocalGenerator::HOME_OUTPUT);
399 commands.insert(commands.end(), commands1.begin(), commands1.end());
402 // Add a rule to create necessary symlinks for the library.
403 if(targetOutPath != targetOutPathReal)
405 std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
406 symlink += targetOutPathReal;
408 symlink += targetOutPath;
409 commands1.push_back(symlink);
410 this->LocalGenerator->CreateCDCommand(commands1,
411 this->Makefile->GetStartOutputDirectory(),
412 cmLocalGenerator::HOME_OUTPUT);
413 commands.insert(commands.end(), commands1.begin(), commands1.end());
417 // Add the post-build rules when building but not when relinking.
420 this->LocalGenerator->
421 AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
425 // Write the build rule.
426 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,
428 targetFullPathReal.c_str(),
429 depends, commands, false);
431 // The symlink name for the target should depend on the real target
432 // so if the target version changes it rebuilds and recreates the
434 if(targetFullPath != targetFullPathReal)
438 depends.push_back(targetFullPathReal.c_str());
439 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
440 targetFullPath.c_str(),
441 depends, commands, false);
444 // Write the main driver rule to build everything in this target.
445 this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
447 // Clean all the possible executable names and symlinks.
448 this->CleanFiles.insert(this->CleanFiles.end(),
449 exeCleanFiles.begin(),
450 exeCleanFiles.end());