1
0

cmMakefileLibraryTargetGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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 "cmMakefileLibraryTargetGenerator.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. //----------------------------------------------------------------------------
  21. void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
  22. {
  23. // create the build.make file and directory, put in the common blocks
  24. this->CreateRuleFile();
  25. // write rules used to help build object files
  26. this->WriteCommonCodeRules();
  27. // write in rules for object files and custom commands
  28. this->WriteTargetBuildRules();
  29. // write the per-target per-language flags
  30. this->WriteTargetLanguageFlags();
  31. // Write the dependency generation rule.
  32. this->WriteTargetDependRules();
  33. // write the link rules
  34. // Write the rule for this target type.
  35. switch(this->Target->GetType())
  36. {
  37. case cmTarget::STATIC_LIBRARY:
  38. this->WriteStaticLibraryRules();
  39. break;
  40. case cmTarget::SHARED_LIBRARY:
  41. this->WriteSharedLibraryRules(false);
  42. if(this->Target->NeedRelinkBeforeInstall())
  43. {
  44. // Write rules to link an installable version of the target.
  45. this->WriteSharedLibraryRules(true);
  46. }
  47. break;
  48. case cmTarget::MODULE_LIBRARY:
  49. this->WriteModuleLibraryRules(false);
  50. if(this->Target->NeedRelinkBeforeInstall())
  51. {
  52. // Write rules to link an installable version of the target.
  53. this->WriteModuleLibraryRules(true);
  54. }
  55. break;
  56. default:
  57. // If language is not known, this is an error.
  58. cmSystemTools::Error("Unknown Library Type");
  59. break;
  60. }
  61. // Write the requires target.
  62. this->WriteTargetRequiresRules();
  63. // Write clean target
  64. this->WriteTargetCleanRules();
  65. // close the streams
  66. this->CloseFileStreams();
  67. }
  68. //----------------------------------------------------------------------------
  69. void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
  70. {
  71. const char* linkLanguage =
  72. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  73. std::string linkRuleVar = "CMAKE_";
  74. if (linkLanguage)
  75. {
  76. linkRuleVar += linkLanguage;
  77. }
  78. linkRuleVar += "_CREATE_STATIC_LIBRARY";
  79. std::string extraFlags;
  80. this->LocalGenerator->AppendFlags
  81. (extraFlags,this->Target->GetProperty("STATIC_LIBRARY_FLAGS"));
  82. this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false);
  83. }
  84. //----------------------------------------------------------------------------
  85. void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
  86. {
  87. const char* linkLanguage =
  88. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  89. std::string linkRuleVar = "CMAKE_";
  90. if (linkLanguage)
  91. {
  92. linkRuleVar += linkLanguage;
  93. }
  94. linkRuleVar += "_CREATE_SHARED_LIBRARY";
  95. std::string extraFlags;
  96. this->LocalGenerator->AppendFlags
  97. (extraFlags, this->Target->GetProperty("LINK_FLAGS"));
  98. std::string linkFlagsConfig = "LINK_FLAGS_";
  99. linkFlagsConfig +=
  100. cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
  101. this->LocalGenerator->AppendFlags
  102. (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
  103. this->LocalGenerator->AddConfigVariableFlags
  104. (extraFlags, "CMAKE_SHARED_LINKER_FLAGS",
  105. this->LocalGenerator->ConfigurationName.c_str());
  106. if(this->Makefile->IsOn("WIN32") && !(this->Makefile->IsOn("CYGWIN")
  107. || this->Makefile->IsOn("MINGW")))
  108. {
  109. const std::vector<cmSourceFile*>& sources =
  110. this->Target->GetSourceFiles();
  111. for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
  112. i != sources.end(); ++i)
  113. {
  114. if((*i)->GetSourceExtension() == "def")
  115. {
  116. extraFlags += " ";
  117. extraFlags +=
  118. this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
  119. extraFlags +=
  120. this->Convert((*i)->GetFullPath().c_str(),
  121. cmLocalGenerator::START_OUTPUT,
  122. cmLocalGenerator::MAKEFILE);
  123. }
  124. }
  125. }
  126. this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
  127. }
  128. //----------------------------------------------------------------------------
  129. void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
  130. {
  131. const char* linkLanguage =
  132. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  133. std::string linkRuleVar = "CMAKE_";
  134. if (linkLanguage)
  135. {
  136. linkRuleVar += linkLanguage;
  137. }
  138. linkRuleVar += "_CREATE_SHARED_MODULE";
  139. std::string extraFlags;
  140. this->LocalGenerator->AppendFlags(extraFlags,
  141. this->Target->GetProperty("LINK_FLAGS"));
  142. std::string linkFlagsConfig = "LINK_FLAGS_";
  143. linkFlagsConfig +=
  144. cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
  145. this->LocalGenerator->AppendFlags
  146. (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
  147. this->LocalGenerator->AddConfigVariableFlags
  148. (extraFlags, "CMAKE_MODULE_LINKER_FLAGS",
  149. this->LocalGenerator->ConfigurationName.c_str());
  150. // TODO: .def files should be supported here also.
  151. this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
  152. }
  153. //----------------------------------------------------------------------------
  154. void cmMakefileLibraryTargetGenerator::WriteLibraryRules
  155. (const char* linkRuleVar, const char* extraFlags, bool relink)
  156. {
  157. // TODO: Merge the methods that call this method to avoid
  158. // code duplication.
  159. std::vector<std::string> commands;
  160. std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
  161. std::string objTarget;
  162. // Build list of dependencies.
  163. std::vector<std::string> depends;
  164. for(std::vector<std::string>::const_iterator obj = this->Objects.begin();
  165. obj != this->Objects.end(); ++obj)
  166. {
  167. objTarget = relPath;
  168. objTarget += *obj;
  169. depends.push_back(objTarget);
  170. }
  171. // Add dependencies on targets that must be built first.
  172. this->AppendTargetDepends(depends);
  173. // Add a dependency on the rule file itself.
  174. this->LocalGenerator->AppendRuleDepend(depends,
  175. this->BuildFileNameFull.c_str());
  176. for(std::vector<std::string>::const_iterator obj
  177. = this->ExternalObjects.begin();
  178. obj != this->ExternalObjects.end(); ++obj)
  179. {
  180. depends.push_back(*obj);
  181. }
  182. // Get the language to use for linking this library.
  183. const char* linkLanguage =
  184. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  185. // Make sure we have a link language.
  186. if(!linkLanguage)
  187. {
  188. cmSystemTools::Error("Cannot determine link language for target \"",
  189. this->Target->GetName(), "\".");
  190. return;
  191. }
  192. // Create set of linking flags.
  193. std::string linkFlags;
  194. this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
  195. // Construct the name of the library.
  196. std::string targetName;
  197. std::string targetNameSO;
  198. std::string targetNameReal;
  199. std::string targetNameImport;
  200. this->Target->GetLibraryNames(
  201. targetName, targetNameSO, targetNameReal, targetNameImport,
  202. this->LocalGenerator->ConfigurationName.c_str());
  203. // Construct the full path version of the names.
  204. std::string outpath = this->LocalGenerator->LibraryOutputPath;
  205. if(outpath.length() == 0)
  206. {
  207. outpath = this->Makefile->GetStartOutputDirectory();
  208. outpath += "/";
  209. }
  210. if(relink)
  211. {
  212. outpath = this->Makefile->GetStartOutputDirectory();
  213. outpath += "/CMakeFiles/CMakeRelink.dir";
  214. cmSystemTools::MakeDirectory(outpath.c_str());
  215. outpath += "/";
  216. }
  217. std::string targetFullPath = outpath + targetName;
  218. std::string targetFullPathPDB =
  219. outpath + this->Target->GetName() + std::string(".pdb");
  220. std::string targetFullPathSO = outpath + targetNameSO;
  221. std::string targetFullPathReal = outpath + targetNameReal;
  222. std::string targetFullPathImport = outpath + targetNameImport;
  223. // Construct the output path version of the names for use in command
  224. // arguments.
  225. std::string targetOutPathPDB =
  226. this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::FULL,
  227. cmLocalGenerator::MAKEFILE);
  228. std::string targetOutPath =
  229. this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT,
  230. cmLocalGenerator::MAKEFILE);
  231. std::string targetOutPathSO =
  232. this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT,
  233. cmLocalGenerator::MAKEFILE);
  234. std::string targetOutPathReal =
  235. this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT,
  236. cmLocalGenerator::MAKEFILE);
  237. std::string targetOutPathImport =
  238. this->Convert(targetFullPathImport.c_str(),cmLocalGenerator::START_OUTPUT,
  239. cmLocalGenerator::MAKEFILE);
  240. // Add the link message.
  241. std::string buildEcho = "Linking ";
  242. buildEcho += linkLanguage;
  243. const char* forbiddenFlagVar = 0;
  244. switch(this->Target->GetType())
  245. {
  246. case cmTarget::STATIC_LIBRARY:
  247. buildEcho += " static library ";
  248. break;
  249. case cmTarget::SHARED_LIBRARY:
  250. forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
  251. buildEcho += " shared library ";
  252. break;
  253. case cmTarget::MODULE_LIBRARY:
  254. forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
  255. buildEcho += " shared module ";
  256. break;
  257. default:
  258. buildEcho += " library ";
  259. break;
  260. }
  261. buildEcho += targetOutPath.c_str();
  262. this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
  263. cmLocalUnixMakefileGenerator3::EchoLink);
  264. // Construct a list of files associated with this library that may
  265. // need to be cleaned.
  266. std::vector<std::string> libCleanFiles;
  267. {
  268. std::string cleanStaticName;
  269. std::string cleanSharedName;
  270. std::string cleanSharedSOName;
  271. std::string cleanSharedRealName;
  272. std::string cleanImportName;
  273. this->Target->GetLibraryCleanNames(
  274. cleanStaticName,
  275. cleanSharedName,
  276. cleanSharedSOName,
  277. cleanSharedRealName,
  278. cleanImportName,
  279. this->LocalGenerator->ConfigurationName.c_str());
  280. std::string cleanFullStaticName = outpath + cleanStaticName;
  281. std::string cleanFullSharedName = outpath + cleanSharedName;
  282. std::string cleanFullSharedSOName = outpath + cleanSharedSOName;
  283. std::string cleanFullSharedRealName = outpath + cleanSharedRealName;
  284. std::string cleanFullImportName = outpath + cleanImportName;
  285. libCleanFiles.push_back
  286. (this->Convert(cleanFullStaticName.c_str(),cmLocalGenerator::START_OUTPUT,
  287. cmLocalGenerator::UNCHANGED));
  288. if(cleanSharedRealName != cleanStaticName)
  289. {
  290. libCleanFiles.push_back(this->Convert(cleanFullSharedRealName.c_str(),
  291. cmLocalGenerator::START_OUTPUT,
  292. cmLocalGenerator::UNCHANGED));
  293. }
  294. if(cleanSharedSOName != cleanStaticName &&
  295. cleanSharedSOName != cleanSharedRealName)
  296. {
  297. libCleanFiles.push_back(this->Convert(cleanFullSharedSOName.c_str(),
  298. cmLocalGenerator::START_OUTPUT,
  299. cmLocalGenerator::UNCHANGED));
  300. }
  301. if(cleanSharedName != cleanStaticName &&
  302. cleanSharedName != cleanSharedSOName &&
  303. cleanSharedName != cleanSharedRealName)
  304. {
  305. libCleanFiles.push_back(this->Convert(cleanFullSharedName.c_str(),
  306. cmLocalGenerator::START_OUTPUT,
  307. cmLocalGenerator::UNCHANGED));
  308. }
  309. if(!cleanImportName.empty() &&
  310. cleanImportName != cleanStaticName &&
  311. cleanImportName != cleanSharedSOName &&
  312. cleanImportName != cleanSharedRealName &&
  313. cleanImportName != cleanSharedName)
  314. {
  315. libCleanFiles.push_back(this->Convert(cleanFullImportName.c_str(),
  316. cmLocalGenerator::START_OUTPUT,
  317. cmLocalGenerator::UNCHANGED));
  318. }
  319. }
  320. // Add a command to remove any existing files for this library.
  321. std::vector<std::string> commands1;
  322. this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
  323. *this->Target, "target");
  324. this->LocalGenerator->CreateCDCommand
  325. (commands1,
  326. this->Makefile->GetStartOutputDirectory(),
  327. this->Makefile->GetHomeOutputDirectory());
  328. commands.insert(commands.end(), commands1.begin(), commands1.end());
  329. commands1.clear();
  330. // Add the pre-build and pre-link rules building but not when relinking.
  331. if(!relink)
  332. {
  333. this->LocalGenerator
  334. ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
  335. this->LocalGenerator
  336. ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
  337. }
  338. // Construct the main link rule.
  339. std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
  340. cmSystemTools::ExpandListArgument(linkRule, commands1);
  341. this->LocalGenerator->CreateCDCommand
  342. (commands1,
  343. this->Makefile->GetStartOutputDirectory(),
  344. this->Makefile->GetHomeOutputDirectory());
  345. commands.insert(commands.end(), commands1.begin(), commands1.end());
  346. // Add a rule to create necessary symlinks for the library.
  347. if(targetOutPath != targetOutPathReal)
  348. {
  349. std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
  350. symlink += targetOutPathReal;
  351. symlink += " ";
  352. symlink += targetOutPathSO;
  353. symlink += " ";
  354. symlink += targetOutPath;
  355. commands1.clear();
  356. commands1.push_back(symlink);
  357. this->LocalGenerator->CreateCDCommand(commands1,
  358. this->Makefile->GetStartOutputDirectory(),
  359. this->Makefile->GetHomeOutputDirectory());
  360. commands.insert(commands.end(), commands1.begin(), commands1.end());
  361. }
  362. // Add the post-build rules when building but not when relinking.
  363. if(!relink)
  364. {
  365. this->LocalGenerator->
  366. AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
  367. }
  368. // Collect up flags to link in needed libraries.
  369. cmOStringStream linklibs;
  370. this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
  371. // Construct object file lists that may be needed to expand the
  372. // rule.
  373. std::string variableName;
  374. std::string variableNameExternal;
  375. this->WriteObjectsVariable(variableName, variableNameExternal);
  376. std::string buildObjs = "$(";
  377. buildObjs += variableName;
  378. buildObjs += ") $(";
  379. buildObjs += variableNameExternal;
  380. buildObjs += ")";
  381. std::string cleanObjs = "$(";
  382. cleanObjs += variableName;
  383. cleanObjs += ")";
  384. cmLocalGenerator::RuleVariables vars;
  385. vars.TargetPDB = targetOutPathPDB.c_str();
  386. vars.Language = linkLanguage;
  387. vars.Objects = buildObjs.c_str();
  388. std::string objdir = "CMakeFiles/";
  389. objdir += this->Target->GetName();
  390. objdir += ".dir";
  391. vars.ObjectDir = objdir.c_str();
  392. vars.Target = targetOutPathReal.c_str();
  393. std::string linkString = linklibs.str();
  394. vars.LinkLibraries = linkString.c_str();
  395. vars.ObjectsQuoted = buildObjs.c_str();
  396. vars.TargetSOName= targetNameSO.c_str();
  397. vars.LinkFlags = linkFlags.c_str();
  398. // Compute the directory portion of the install_name setting.
  399. std::string install_name_dir;
  400. if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
  401. {
  402. // Select whether to generate an install_name directory for the
  403. // install tree or the build tree.
  404. const char* config = this->LocalGenerator->ConfigurationName.c_str();
  405. if(this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
  406. {
  407. install_name_dir =
  408. this->Target->GetInstallNameDirForInstallTree(config);
  409. }
  410. else
  411. {
  412. install_name_dir =
  413. this->Target->GetInstallNameDirForBuildTree(config);
  414. }
  415. // Set the rule variable replacement value.
  416. if(install_name_dir.empty())
  417. {
  418. vars.TargetInstallNameDir = "";
  419. }
  420. else
  421. {
  422. // Convert to a path for the native build tool.
  423. install_name_dir =
  424. this->LocalGenerator->Convert(install_name_dir.c_str(),
  425. cmLocalGenerator::FULL,
  426. cmLocalGenerator::SHELL, false);
  427. // The Convert method seems to strip trailing slashes, which should
  428. // probably be fixed. Since the only platform supporting install_name
  429. // right now uses forward slashes just add one.
  430. install_name_dir += "/";
  431. vars.TargetInstallNameDir = install_name_dir.c_str();
  432. }
  433. }
  434. std::string langFlags;
  435. this->LocalGenerator
  436. ->AddLanguageFlags(langFlags, linkLanguage,
  437. this->LocalGenerator->ConfigurationName.c_str());
  438. // remove any language flags that might not work with the
  439. // particular os
  440. if(forbiddenFlagVar)
  441. {
  442. this->RemoveForbiddenFlags(forbiddenFlagVar,
  443. linkLanguage, langFlags);
  444. }
  445. vars.LanguageCompileFlags = langFlags.c_str();
  446. // Expand placeholders in the commands.
  447. this->LocalGenerator->TargetImplib = targetOutPathImport;
  448. for(std::vector<std::string>::iterator i = commands.begin();
  449. i != commands.end(); ++i)
  450. {
  451. this->LocalGenerator->ExpandRuleVariables(*i, vars);
  452. }
  453. this->LocalGenerator->TargetImplib = "";
  454. // Write the build rule.
  455. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
  456. targetFullPathReal.c_str(),
  457. depends, commands, false);
  458. // The symlink names for the target should depend on the real target
  459. // so if the target version changes it rebuilds and recreates the
  460. // symlinks.
  461. if(targetFullPathSO != targetFullPathReal)
  462. {
  463. depends.clear();
  464. commands.clear();
  465. depends.push_back(targetFullPathReal.c_str());
  466. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
  467. targetFullPathSO.c_str(),
  468. depends, commands, false);
  469. }
  470. if(targetFullPath != targetFullPathSO)
  471. {
  472. depends.clear();
  473. commands.clear();
  474. depends.push_back(targetFullPathSO.c_str());
  475. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
  476. targetFullPath.c_str(),
  477. depends, commands, false);
  478. }
  479. // Write the main driver rule to build everything in this target.
  480. this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
  481. // Clean all the possible library names and symlinks and object files.
  482. this->CleanFiles.insert(this->CleanFiles.end(),
  483. libCleanFiles.begin(),libCleanFiles.end());
  484. this->CleanFiles.insert(this->CleanFiles.end(),
  485. this->Objects.begin(),
  486. this->Objects.end());
  487. }