cmLinkLineComputer.cxx 8.0 KB

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