cmLinkLineComputer.cxx 7.8 KB

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