cmMakefileLibraryTargetGenerator.cxx 19 KB

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