packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmMakefileExecutableTargetGenerator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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"
13
14 #include "cmGeneratedFileStream.h"
15 #include "cmGlobalUnixMakefileGenerator3.h"
16 #include "cmLocalUnixMakefileGenerator3.h"
17 #include "cmMakefile.h"
18 #include "cmSourceFile.h"
19 #include "cmTarget.h"
20 #include "cmake.h"
21
22 //----------------------------------------------------------------------------
23 cmMakefileExecutableTargetGenerator
24 ::cmMakefileExecutableTargetGenerator(cmTarget* target):
25   cmMakefileTargetGenerator(target)
26 {
27   this->CustomCommandDriver = OnDepends;
28   this->Target->GetExecutableNames(
29     this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
30     this->TargetNamePDB, this->ConfigName);
31
32   this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
33                                                       this->ConfigName);
34   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
35 }
36
37 //----------------------------------------------------------------------------
38 cmMakefileExecutableTargetGenerator
39 ::~cmMakefileExecutableTargetGenerator()
40 {
41   delete this->OSXBundleGenerator;
42 }
43
44 //----------------------------------------------------------------------------
45 void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
46 {
47   // create the build.make file and directory, put in the common blocks
48   this->CreateRuleFile();
49
50   // write rules used to help build object files
51   this->WriteCommonCodeRules();
52
53   // write the per-target per-language flags
54   this->WriteTargetLanguageFlags();
55
56   // write in rules for object files and custom commands
57   this->WriteTargetBuildRules();
58
59   // write the link rules
60   this->WriteExecutableRule(false);
61   if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
62     {
63     // Write rules to link an installable version of the target.
64     this->WriteExecutableRule(true);
65     }
66
67   // Write the requires target.
68   this->WriteTargetRequiresRules();
69
70   // Write clean target
71   this->WriteTargetCleanRules();
72
73   // Write the dependency generation rule.  This must be done last so
74   // that multiple output pair information is available.
75   this->WriteTargetDependRules();
76
77   // close the streams
78   this->CloseFileStreams();
79 }
80
81
82
83 //----------------------------------------------------------------------------
84 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
85 {
86   std::vector<std::string> commands;
87
88   // Build list of dependencies.
89   std::vector<std::string> depends;
90   this->AppendLinkDepends(depends);
91
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,
99      this->ConfigName);
100
101   // Construct the full path version of the names.
102   std::string outpath = this->Target->GetDirectory(this->ConfigName);
103   if(this->Target->IsAppBundleOnApple())
104     {
105     this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
106     }
107   outpath += "/";
108   std::string outpathImp;
109   if(relink)
110     {
111     outpath = this->Makefile->GetStartOutputDirectory();
112     outpath += cmake::GetCMakeFilesDirectory();
113     outpath += "/CMakeRelink.dir";
114     cmSystemTools::MakeDirectory(outpath.c_str());
115     outpath += "/";
116     if(!targetNameImport.empty())
117       {
118       outpathImp = outpath;
119       }
120     }
121   else
122     {
123     cmSystemTools::MakeDirectory(outpath.c_str());
124     if(!targetNameImport.empty())
125       {
126       outpathImp = this->Target->GetDirectory(this->ConfigName, true);
127       cmSystemTools::MakeDirectory(outpathImp.c_str());
128       outpathImp += "/";
129       }
130     }
131
132   std::string pdbOutputPath = this->Target->GetPDBDirectory();
133   cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
134   pdbOutputPath += "/";
135
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);
157
158   // Get the language to use for linking this executable.
159   const char* linkLanguage =
160     this->Target->GetLinkerLanguage(this->ConfigName);
161
162   // Make sure we have a link language.
163   if(!linkLanguage)
164     {
165     cmSystemTools::Error("Cannot determine link language for target \"",
166                          this->Target->GetName(), "\".");
167     return;
168     }
169
170   if(!this->NoRuleMessages)
171     {
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);
179     }
180
181   // Build a list of compiler flags and linker flags.
182   std::string flags;
183   std::string linkFlags;
184
185   // Add flags to create an executable.
186   this->LocalGenerator->
187     AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",
188                            this->ConfigName);
189
190
191   if(this->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))
192     {
193     this->LocalGenerator->AppendFlags
194       (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
195     }
196   else
197     {
198     this->LocalGenerator->AppendFlags
199       (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
200     }
201
202   // Add symbol export flags if necessary.
203   if(this->Target->IsExecutableWithExports())
204     {
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()));
210     }
211
212   // Add language feature flags.
213   this->AddFeatureFlags(flags, linkLanguage);
214
215   this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
216                                              linkLanguage, this->ConfigName);
217
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()));
225
226   this->AddModuleDefinitionFlag(linkFlags);
227
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));
234 #ifdef _WIN32
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));
240 #endif
241   if(targetNameReal != targetName)
242     {
243     exeCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),
244                                           cmLocalGenerator::START_OUTPUT,
245                                           cmLocalGenerator::UNCHANGED));
246     }
247   if(!targetNameImport.empty())
248     {
249     exeCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),
250                                           cmLocalGenerator::START_OUTPUT,
251                                           cmLocalGenerator::UNCHANGED));
252     std::string implib;
253     if(this->Target->GetImplibGNUtoMS(targetFullPathImport, implib))
254       {
255       exeCleanFiles.push_back(this->Convert(implib.c_str(),
256                                             cmLocalGenerator::START_OUTPUT,
257                                             cmLocalGenerator::UNCHANGED));
258       }
259     }
260
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));
268
269   // Add the pre-build and pre-link rules building but not when relinking.
270   if(!relink)
271     {
272     this->LocalGenerator
273       ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands(),
274                              this->Target);
275     this->LocalGenerator
276       ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands(),
277                              this->Target);
278     }
279
280   // Determine whether a link script will be used.
281   bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
282
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())
292     {
293     // If a separate rule for creating an import library is specified
294     // add it now.
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()))
300       {
301       cmSystemTools::ExpandListArgument(rule, real_link_commands);
302       }
303     }
304
305   // Select whether to use a response file for objects.
306   bool useResponseFile = false;
307   {
308   std::string responseVar = "CMAKE_";
309   responseVar += linkLanguage;
310   responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
311   if(this->Makefile->IsOn(responseVar.c_str()))
312     {
313     useResponseFile = true;
314     }
315   }
316
317   // Expand the rule variables.
318   {
319   // Set path conversion for link script shells.
320   this->LocalGenerator->SetLinkScriptShell(useLinkScript);
321
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,
328                                             relink);
329   linkLibs = frameworkPath + linkPath + linkLibs;
330   // Construct object file lists that may be needed to expand the
331   // rule.
332   std::string buildObjs;
333   this->CreateObjectLists(useLinkScript, false, useResponseFile,
334                           buildObjs, depends);
335
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();
348
349   // Setup the target version.
350   std::string targetVersionMajor;
351   std::string targetVersionMinor;
352   {
353   cmOStringStream majorStream;
354   cmOStringStream minorStream;
355   int major;
356   int minor;
357   this->Target->GetTargetVersion(major, minor);
358   majorStream << major;
359   minorStream << minor;
360   targetVersionMajor = majorStream.str();
361   targetVersionMinor = minorStream.str();
362   }
363   vars.TargetVersionMajor = targetVersionMajor.c_str();
364   vars.TargetVersionMinor = targetVersionMinor.c_str();
365
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)
373     {
374     this->LocalGenerator->ExpandRuleVariables(*i, vars);
375     }
376   this->LocalGenerator->TargetImplib = "";
377
378   // Restore path conversion to normal shells.
379   this->LocalGenerator->SetLinkScriptShell(false);
380   }
381
382   // Optionally convert the build rule to use a script to avoid long
383   // command lines in the make shell.
384   if(useLinkScript)
385     {
386     // Use a link script.
387     const char* name = (relink? "relink.txt" : "link.txt");
388     this->CreateLinkScript(name, real_link_commands, commands1, depends);
389     }
390   else
391     {
392     // No link script.  Just use the link rule directly.
393     commands1 = real_link_commands;
394     }
395   this->LocalGenerator->CreateCDCommand
396     (commands1,
397      this->Makefile->GetStartOutputDirectory(),
398      cmLocalGenerator::HOME_OUTPUT);
399   commands.insert(commands.end(), commands1.begin(), commands1.end());
400   commands1.clear();
401
402   // Add a rule to create necessary symlinks for the library.
403   if(targetOutPath != targetOutPathReal)
404     {
405     std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
406     symlink += targetOutPathReal;
407     symlink += " ";
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());
414     commands1.clear();
415     }
416
417   // Add the post-build rules when building but not when relinking.
418   if(!relink)
419     {
420     this->LocalGenerator->
421       AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
422                            this->Target);
423     }
424
425   // Write the build rule.
426   this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,
427                                       0,
428                                       targetFullPathReal.c_str(),
429                                       depends, commands, false);
430
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
433   // symlink.
434   if(targetFullPath != targetFullPathReal)
435     {
436     depends.clear();
437     commands.clear();
438     depends.push_back(targetFullPathReal.c_str());
439     this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
440                                         targetFullPath.c_str(),
441                                         depends, commands, false);
442     }
443
444   // Write the main driver rule to build everything in this target.
445   this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
446
447   // Clean all the possible executable names and symlinks.
448   this->CleanFiles.insert(this->CleanFiles.end(),
449                           exeCleanFiles.begin(),
450                           exeCleanFiles.end());
451 }