cmLinkLineComputer.cxx 7.9 KB

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