cmLinkLineComputer.cxx 7.4 KB

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