cmMakefileExecutableTargetGenerator.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmMakefileExecutableTargetGenerator.h"
  14. #include "cmGeneratedFileStream.h"
  15. #include "cmGlobalGenerator.h"
  16. #include "cmLocalUnixMakefileGenerator3.h"
  17. #include "cmMakefile.h"
  18. #include "cmSourceFile.h"
  19. #include "cmTarget.h"
  20. #include "cmake.h"
  21. //----------------------------------------------------------------------------
  22. void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
  23. {
  24. // create the build.make file and directory, put in the common blocks
  25. this->CreateRuleFile();
  26. // write rules used to help build object files
  27. this->WriteCommonCodeRules();
  28. // write in rules for object files and custom commands
  29. this->WriteTargetBuildRules();
  30. // write the per-target per-language flags
  31. this->WriteTargetLanguageFlags();
  32. // Write the dependency generation rule.
  33. this->WriteTargetDependRules();
  34. // write the link rules
  35. this->WriteExecutableRule(false);
  36. if(this->Target->NeedRelinkBeforeInstall())
  37. {
  38. // Write rules to link an installable version of the target.
  39. this->WriteExecutableRule(true);
  40. }
  41. // Write the requires target.
  42. this->WriteTargetRequiresRules();
  43. // Write clean target
  44. this->WriteTargetCleanRules();
  45. // close the streams
  46. this->CloseFileStreams();
  47. }
  48. //----------------------------------------------------------------------------
  49. void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
  50. {
  51. std::vector<std::string> commands;
  52. std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
  53. std::string objTarget;
  54. // Build list of dependencies.
  55. std::vector<std::string> depends;
  56. for(std::vector<std::string>::const_iterator obj = this->Objects.begin();
  57. obj != this->Objects.end(); ++obj)
  58. {
  59. objTarget = relPath;
  60. // Handle extra content on Mac bundles
  61. if ( this->ExtraContent.find(*obj) != this->ExtraContent.end() )
  62. {
  63. objTarget = "";
  64. }
  65. objTarget += *obj;
  66. depends.push_back(objTarget);
  67. }
  68. // Add dependencies on targets that must be built first.
  69. this->AppendTargetDepends(depends);
  70. // Add a dependency on the rule file itself.
  71. this->LocalGenerator->AppendRuleDepend(depends,
  72. this->BuildFileNameFull.c_str());
  73. for(std::vector<std::string>::const_iterator obj =
  74. this->ExternalObjects.begin();
  75. obj != this->ExternalObjects.end(); ++obj)
  76. {
  77. depends.push_back(*obj);
  78. }
  79. // from here up is the same for exe or lib
  80. // Get the name of the executable to generate.
  81. std::string targetName;
  82. std::string targetNameReal;
  83. this->Target->GetExecutableNames
  84. (targetName, targetNameReal,
  85. this->LocalGenerator->ConfigurationName.c_str());
  86. // Construct the full path version of the names.
  87. std::string outpath = this->LocalGenerator->ExecutableOutputPath;
  88. if(outpath.length() == 0)
  89. {
  90. outpath = this->Makefile->GetStartOutputDirectory();
  91. outpath += "/";
  92. }
  93. #ifdef __APPLE__
  94. if(this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
  95. {
  96. // Make bundle directories
  97. outpath += targetName;
  98. outpath += ".app/Contents/MacOS/";
  99. std::string f1 =
  100. this->Makefile->GetModulesFile("MacOSXBundleInfo.plist.in");
  101. if ( f1.size() == 0 )
  102. {
  103. cmSystemTools::Error("could not find Mac OSX bundle template file.");
  104. }
  105. std::string macdir =
  106. this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
  107. if ( macdir.size() == 0 )
  108. {
  109. macdir = this->Makefile->GetCurrentOutputDirectory();
  110. }
  111. if(macdir.size() && macdir[macdir.size()-1] != '/')
  112. {
  113. macdir += "/";
  114. }
  115. macdir += targetName;
  116. macdir += ".app/Contents/";
  117. std::vector<cmSourceFile*>::iterator sourceIt;
  118. for ( sourceIt = this->Target->GetSourceFiles().begin();
  119. sourceIt != this->Target->GetSourceFiles().end();
  120. ++ sourceIt )
  121. {
  122. const char* subDir =
  123. (*sourceIt)->GetProperty("MACOSX_PACKAGE_LOCATION");
  124. if ( subDir )
  125. {
  126. std::string newDir = macdir;
  127. newDir += subDir;
  128. if ( !cmSystemTools::MakeDirectory(newDir.c_str()) )
  129. {
  130. cmSystemTools::Error("Cannot create a subdirectory for \"",
  131. newDir.c_str(), "\".");
  132. return;
  133. }
  134. }
  135. }
  136. // Configure the Info.plist file. Note that it needs the executable name
  137. // to be set.
  138. std::string f2 = macdir + "Info.plist";
  139. macdir += "MacOS";
  140. cmSystemTools::MakeDirectory(macdir.c_str());
  141. this->Makefile->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME",
  142. targetName.c_str());
  143. this->Makefile->ConfigureFile(f1.c_str(), f2.c_str(),
  144. false, false, false);
  145. }
  146. #endif
  147. if(relink)
  148. {
  149. outpath = this->Makefile->GetStartOutputDirectory();
  150. outpath += cmake::GetCMakeFilesDirectory();
  151. outpath += "/CMakeRelink.dir";
  152. cmSystemTools::MakeDirectory(outpath.c_str());
  153. outpath += "/";
  154. }
  155. std::string targetFullPath = outpath + targetName;
  156. std::string targetFullPathReal = outpath + targetNameReal;
  157. std::string targetFullPathPDB = outpath + this->Target->GetName();
  158. targetFullPathPDB += ".pdb";
  159. std::string targetOutPathPDB =
  160. this->Convert(targetFullPathPDB.c_str(),
  161. cmLocalGenerator::FULL,
  162. cmLocalGenerator::MAKEFILE);
  163. // Convert to the output path to use in constructing commands.
  164. std::string targetOutPath =
  165. this->Convert(targetFullPath.c_str(),
  166. cmLocalGenerator::START_OUTPUT,
  167. cmLocalGenerator::MAKEFILE);
  168. std::string targetOutPathReal =
  169. this->Convert(targetFullPathReal.c_str(),
  170. cmLocalGenerator::START_OUTPUT,
  171. cmLocalGenerator::MAKEFILE);
  172. // Get the language to use for linking this executable.
  173. const char* linkLanguage =
  174. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  175. // Make sure we have a link language.
  176. if(!linkLanguage)
  177. {
  178. cmSystemTools::Error("Cannot determine link language for target \"",
  179. this->Target->GetName(), "\".");
  180. return;
  181. }
  182. // Add the link message.
  183. std::string buildEcho = "Linking ";
  184. buildEcho += linkLanguage;
  185. buildEcho += " executable ";
  186. buildEcho += targetOutPath;
  187. this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
  188. cmLocalUnixMakefileGenerator3::EchoLink);
  189. // Build a list of compiler flags and linker flags.
  190. std::string flags;
  191. std::string linkFlags;
  192. // Add flags to deal with shared libraries. Any library being
  193. // linked in might be shared, so always use shared flags for an
  194. // executable.
  195. this->LocalGenerator->AddSharedFlags(linkFlags, linkLanguage, true);
  196. // Add flags to create an executable.
  197. this->LocalGenerator->
  198. AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",
  199. this->LocalGenerator->ConfigurationName.c_str());
  200. if(this->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))
  201. {
  202. this->LocalGenerator->AppendFlags
  203. (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));
  204. }
  205. else
  206. {
  207. this->LocalGenerator->AppendFlags
  208. (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));
  209. }
  210. // Add language-specific flags.
  211. this->LocalGenerator
  212. ->AddLanguageFlags(flags, linkLanguage,
  213. this->LocalGenerator->ConfigurationName.c_str());
  214. // Add target-specific linker flags.
  215. this->LocalGenerator->AppendFlags
  216. (linkFlags, this->Target->GetProperty("LINK_FLAGS"));
  217. std::string linkFlagsConfig = "LINK_FLAGS_";
  218. linkFlagsConfig +=
  219. cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
  220. this->LocalGenerator->AppendFlags
  221. (linkFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
  222. // Construct a list of files associated with this executable that
  223. // may need to be cleaned.
  224. std::vector<std::string> exeCleanFiles;
  225. {
  226. std::string cleanName;
  227. std::string cleanRealName;
  228. this->Target->GetExecutableCleanNames
  229. (cleanName, cleanRealName,
  230. this->LocalGenerator->ConfigurationName.c_str());
  231. std::string cleanFullName = outpath + cleanName;
  232. std::string cleanFullRealName = outpath + cleanRealName;
  233. exeCleanFiles.push_back(this->Convert(cleanFullName.c_str(),
  234. cmLocalGenerator::START_OUTPUT,
  235. cmLocalGenerator::UNCHANGED));
  236. #ifdef _WIN32
  237. // There may be a manifest file for this target. Add it to the
  238. // clean set just in case.
  239. exeCleanFiles.push_back(this->Convert((cleanFullName+".manifest").c_str(),
  240. cmLocalGenerator::START_OUTPUT,
  241. cmLocalGenerator::UNCHANGED));
  242. #endif
  243. if(cleanRealName != cleanName)
  244. {
  245. exeCleanFiles.push_back(this->Convert(cleanFullRealName.c_str(),
  246. cmLocalGenerator::START_OUTPUT,
  247. cmLocalGenerator::UNCHANGED));
  248. }
  249. }
  250. // Add a command to remove any existing files for this executable.
  251. std::vector<std::string> commands1;
  252. this->LocalGenerator->AppendCleanCommand(commands1, exeCleanFiles,
  253. *this->Target, "target");
  254. this->LocalGenerator->CreateCDCommand
  255. (commands1,
  256. this->Makefile->GetStartOutputDirectory(),
  257. this->Makefile->GetHomeOutputDirectory());
  258. commands.insert(commands.end(), commands1.begin(), commands1.end());
  259. commands1.clear();
  260. // Add the pre-build and pre-link rules building but not when relinking.
  261. if(!relink)
  262. {
  263. this->LocalGenerator
  264. ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
  265. this->LocalGenerator
  266. ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
  267. }
  268. // Construct the main link rule.
  269. std::string linkRuleVar = "CMAKE_";
  270. linkRuleVar += linkLanguage;
  271. linkRuleVar += "_LINK_EXECUTABLE";
  272. std::string linkRule =
  273. this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
  274. cmSystemTools::ExpandListArgument(linkRule, commands1);
  275. this->LocalGenerator->CreateCDCommand
  276. (commands1,
  277. this->Makefile->GetStartOutputDirectory(),
  278. this->Makefile->GetHomeOutputDirectory());
  279. commands.insert(commands.end(), commands1.begin(), commands1.end());
  280. // Add a rule to create necessary symlinks for the library.
  281. if(targetOutPath != targetOutPathReal)
  282. {
  283. std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
  284. symlink += targetOutPathReal;
  285. symlink += " ";
  286. symlink += targetOutPath;
  287. commands1.clear();
  288. commands1.push_back(symlink);
  289. this->LocalGenerator->CreateCDCommand(commands1,
  290. this->Makefile->GetStartOutputDirectory(),
  291. this->Makefile->GetHomeOutputDirectory());
  292. commands.insert(commands.end(), commands1.begin(), commands1.end());
  293. }
  294. // Add the post-build rules when building but not when relinking.
  295. if(!relink)
  296. {
  297. this->LocalGenerator->
  298. AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
  299. }
  300. // Collect up flags to link in needed libraries.
  301. cmOStringStream linklibs;
  302. this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
  303. // Construct object file lists that may be needed to expand the
  304. // rule.
  305. std::string variableName;
  306. std::string variableNameExternal;
  307. this->WriteObjectsVariable(variableName, variableNameExternal);
  308. std::string buildObjs = "$(";
  309. buildObjs += variableName;
  310. buildObjs += ") $(";
  311. buildObjs += variableNameExternal;
  312. buildObjs += ")";
  313. std::string cleanObjs = "$(";
  314. cleanObjs += variableName;
  315. cleanObjs += ")";
  316. cmLocalGenerator::RuleVariables vars;
  317. vars.Language = linkLanguage;
  318. vars.Objects = buildObjs.c_str();
  319. vars.Target = targetOutPathReal.c_str();
  320. vars.TargetPDB = targetOutPathPDB.c_str();
  321. std::string linkString = linklibs.str();
  322. vars.LinkLibraries = linkString.c_str();
  323. vars.Flags = flags.c_str();
  324. vars.LinkFlags = linkFlags.c_str();
  325. // Expand placeholders in the commands.
  326. for(std::vector<std::string>::iterator i = commands.begin();
  327. i != commands.end(); ++i)
  328. {
  329. this->LocalGenerator->ExpandRuleVariables(*i, vars);
  330. }
  331. // Write the build rule.
  332. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,
  333. 0,
  334. targetFullPathReal.c_str(),
  335. depends, commands, false);
  336. // The symlink name for the target should depend on the real target
  337. // so if the target version changes it rebuilds and recreates the
  338. // symlink.
  339. if(targetFullPath != targetFullPathReal)
  340. {
  341. depends.clear();
  342. commands.clear();
  343. depends.push_back(targetFullPathReal.c_str());
  344. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
  345. targetFullPath.c_str(),
  346. depends, commands, false);
  347. }
  348. // Write the main driver rule to build everything in this target.
  349. this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
  350. // Clean all the possible executable names and symlinks and object files.
  351. this->CleanFiles.insert(this->CleanFiles.end(),
  352. exeCleanFiles.begin(),
  353. exeCleanFiles.end());
  354. this->CleanFiles.insert(this->CleanFiles.end(),
  355. this->Objects.begin(),
  356. this->Objects.end());
  357. }