cmLinkLineComputer.cxx 8.4 KB

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