cmLinkLineComputer.cxx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmLinkLineComputer.h"
  4. #include <sstream>
  5. #include <utility>
  6. #include <vector>
  7. #include "cmComputeLinkInformation.h"
  8. #include "cmGeneratorTarget.h"
  9. #include "cmListFileCache.h"
  10. #include "cmOutputConverter.h"
  11. #include "cmStateDirectory.h"
  12. #include "cmStateTypes.h"
  13. #include "cmStringAlgorithms.h"
  14. #include "cmSystemTools.h"
  15. cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
  16. cmStateDirectory const& stateDir)
  17. : StateDir(stateDir)
  18. , OutputConverter(outputConverter)
  19. , ForResponse(false)
  20. , UseWatcomQuote(false)
  21. , Relink(false)
  22. {
  23. }
  24. cmLinkLineComputer::~cmLinkLineComputer() = default;
  25. void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote)
  26. {
  27. this->UseWatcomQuote = useWatcomQuote;
  28. }
  29. void cmLinkLineComputer::SetForResponse(bool forResponse)
  30. {
  31. this->ForResponse = forResponse;
  32. }
  33. void cmLinkLineComputer::SetRelink(bool relink)
  34. {
  35. this->Relink = relink;
  36. }
  37. std::string cmLinkLineComputer::ConvertToLinkReference(
  38. std::string const& lib) const
  39. {
  40. std::string relLib = lib;
  41. if (this->StateDir.ContainsBoth(this->StateDir.GetCurrentBinary(), lib)) {
  42. relLib = cmSystemTools::ForceToRelativePath(
  43. this->StateDir.GetCurrentBinary(), lib);
  44. }
  45. return relLib;
  46. }
  47. std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli)
  48. {
  49. std::string linkLibs;
  50. std::vector<BT<std::string>> linkLibsList;
  51. this->ComputeLinkLibs(cli, linkLibsList);
  52. cli.AppendValues(linkLibs, linkLibsList);
  53. return linkLibs;
  54. }
  55. void cmLinkLineComputer::ComputeLinkLibs(
  56. cmComputeLinkInformation& cli, std::vector<BT<std::string>>& linkLibraries)
  57. {
  58. using ItemVector = cmComputeLinkInformation::ItemVector;
  59. ItemVector const& items = cli.GetItems();
  60. for (auto const& item : items) {
  61. if (item.Target &&
  62. item.Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
  63. continue;
  64. }
  65. BT<std::string> linkLib;
  66. if (item.IsPath) {
  67. linkLib.Value += cli.GetLibLinkFileFlag();
  68. linkLib.Value += this->ConvertToOutputFormat(
  69. this->ConvertToLinkReference(item.Value.Value));
  70. linkLib.Backtrace = item.Value.Backtrace;
  71. } else {
  72. linkLib = item.Value;
  73. }
  74. linkLib.Value += " ";
  75. linkLibraries.emplace_back(linkLib);
  76. }
  77. }
  78. std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
  79. {
  80. cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
  81. ? cmOutputConverter::RESPONSE
  82. : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
  83. : cmOutputConverter::SHELL);
  84. return this->OutputConverter->ConvertToOutputFormat(input, shellFormat);
  85. }
  86. std::string cmLinkLineComputer::ConvertToOutputForExisting(
  87. std::string const& input)
  88. {
  89. cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
  90. ? cmOutputConverter::RESPONSE
  91. : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
  92. : cmOutputConverter::SHELL);
  93. return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat);
  94. }
  95. std::string cmLinkLineComputer::ComputeLinkPath(
  96. cmComputeLinkInformation& cli, std::string const& libPathFlag,
  97. std::string const& libPathTerminator)
  98. {
  99. std::string linkPath;
  100. std::vector<BT<std::string>> linkPathList;
  101. this->ComputeLinkPath(cli, libPathFlag, libPathTerminator, linkPathList);
  102. cli.AppendValues(linkPath, linkPathList);
  103. return linkPath;
  104. }
  105. void cmLinkLineComputer::ComputeLinkPath(
  106. cmComputeLinkInformation& cli, std::string const& libPathFlag,
  107. std::string const& libPathTerminator, std::vector<BT<std::string>>& linkPath)
  108. {
  109. if (cli.GetLinkLanguage() == "Swift") {
  110. std::string linkPathNoBT;
  111. for (const cmComputeLinkInformation::Item& item : cli.GetItems()) {
  112. const cmGeneratorTarget* target = item.Target;
  113. if (!target) {
  114. continue;
  115. }
  116. if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
  117. target->GetType() == cmStateEnums::SHARED_LIBRARY) {
  118. cmStateEnums::ArtifactType type = cmStateEnums::RuntimeBinaryArtifact;
  119. if (target->HasImportLibrary(cli.GetConfig())) {
  120. type = cmStateEnums::ImportLibraryArtifact;
  121. }
  122. linkPathNoBT += cmStrCat(
  123. " ", libPathFlag, item.Target->GetDirectory(cli.GetConfig(), type),
  124. libPathTerminator, " ");
  125. }
  126. }
  127. if (!linkPathNoBT.empty()) {
  128. linkPath.emplace_back(std::move(linkPathNoBT));
  129. }
  130. }
  131. for (BT<std::string> libDir : cli.GetDirectoriesWithBacktraces()) {
  132. libDir.Value = cmStrCat(" ", libPathFlag,
  133. this->ConvertToOutputForExisting(libDir.Value),
  134. libPathTerminator, " ");
  135. linkPath.emplace_back(libDir);
  136. }
  137. }
  138. std::string cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation& cli)
  139. {
  140. std::string rpath;
  141. // Check what kind of rpath flags to use.
  142. if (cli.GetRuntimeSep().empty()) {
  143. // Each rpath entry gets its own option ("-R a -R b -R c")
  144. std::vector<std::string> runtimeDirs;
  145. cli.GetRPath(runtimeDirs, this->Relink);
  146. for (std::string const& rd : runtimeDirs) {
  147. rpath += cli.GetRuntimeFlag();
  148. rpath += this->ConvertToOutputFormat(rd);
  149. rpath += " ";
  150. }
  151. } else {
  152. // All rpath entries are combined ("-Wl,-rpath,a:b:c").
  153. std::string rpathString = cli.GetRPathString(this->Relink);
  154. // Store the rpath option in the stream.
  155. if (!rpathString.empty()) {
  156. rpath += cli.GetRuntimeFlag();
  157. rpath +=
  158. this->OutputConverter->EscapeForShell(rpathString, !this->ForResponse);
  159. rpath += " ";
  160. }
  161. }
  162. return rpath;
  163. }
  164. std::string cmLinkLineComputer::ComputeFrameworkPath(
  165. cmComputeLinkInformation& cli, std::string const& fwSearchFlag)
  166. {
  167. std::string frameworkPath;
  168. if (!fwSearchFlag.empty()) {
  169. std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
  170. for (std::string const& fd : fwDirs) {
  171. frameworkPath += fwSearchFlag;
  172. frameworkPath += this->ConvertToOutputFormat(fd);
  173. frameworkPath += " ";
  174. }
  175. }
  176. return frameworkPath;
  177. }
  178. std::string cmLinkLineComputer::ComputeLinkLibraries(
  179. cmComputeLinkInformation& cli, std::string const& stdLibString)
  180. {
  181. std::string linkLibraries;
  182. std::vector<BT<std::string>> linkLibrariesList;
  183. this->ComputeLinkLibraries(cli, stdLibString, linkLibrariesList);
  184. cli.AppendValues(linkLibraries, linkLibrariesList);
  185. return linkLibraries;
  186. }
  187. void cmLinkLineComputer::ComputeLinkLibraries(
  188. cmComputeLinkInformation& cli, std::string const& stdLibString,
  189. std::vector<BT<std::string>>& linkLibraries)
  190. {
  191. std::ostringstream rpathOut;
  192. rpathOut << this->ComputeRPath(cli);
  193. std::string rpath = rpathOut.str();
  194. if (!rpath.empty()) {
  195. linkLibraries.emplace_back(std::move(rpath));
  196. }
  197. // Write the library flags to the build rule.
  198. this->ComputeLinkLibs(cli, linkLibraries);
  199. // Add the linker runtime search path if any.
  200. std::ostringstream fout;
  201. std::string rpath_link = cli.GetRPathLinkString();
  202. if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
  203. fout << cli.GetRPathLinkFlag();
  204. fout << this->OutputConverter->EscapeForShell(rpath_link,
  205. !this->ForResponse);
  206. fout << " ";
  207. }
  208. if (!stdLibString.empty()) {
  209. fout << stdLibString << " ";
  210. }
  211. std::string remainingLibs = fout.str();
  212. if (!remainingLibs.empty()) {
  213. linkLibraries.emplace_back(remainingLibs);
  214. }
  215. }
  216. std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target,
  217. std::string const& config)
  218. {
  219. return target->GetLinkerLanguage(config);
  220. }