resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmLinkLineComputer.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3
4 #include "cmLinkLineComputer.h"
5
6 #include <sstream>
7 #include <utility>
8 #include <vector>
9
10 #include "cmComputeLinkInformation.h"
11 #include "cmGeneratorTarget.h"
12 #include "cmListFileCache.h"
13 #include "cmOutputConverter.h"
14 #include "cmStateTypes.h"
15 #include "cmStringAlgorithms.h"
16
17 cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
18                                        cmStateDirectory const& stateDir)
19   : StateDir(stateDir)
20   , OutputConverter(outputConverter)
21 {
22 }
23
24 cmLinkLineComputer::~cmLinkLineComputer() = default;
25
26 void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote)
27 {
28   this->UseWatcomQuote = useWatcomQuote;
29 }
30
31 void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti)
32 {
33   this->UseNinjaMulti = useNinjaMulti;
34 }
35
36 void cmLinkLineComputer::SetForResponse(bool forResponse)
37 {
38   this->ForResponse = forResponse;
39 }
40
41 void cmLinkLineComputer::SetRelink(bool relink)
42 {
43   this->Relink = relink;
44 }
45
46 std::string cmLinkLineComputer::ConvertToLinkReference(
47   std::string const& lib) const
48 {
49   return this->OutputConverter->MaybeRelativeToCurBinDir(lib);
50 }
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
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
72     BT<std::string> linkLib;
73     if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
74       linkLib = item.GetFormattedItem(this->ConvertToOutputFormat(
75         this->ConvertToLinkReference(item.Value.Value)));
76     } else {
77       linkLib = item.Value;
78     }
79     linkLib.Value += " ";
80
81     linkLibraries.emplace_back(linkLib);
82   }
83 }
84
85 std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
86 {
87   cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
88   if (this->ForResponse) {
89     shellFormat = cmOutputConverter::RESPONSE;
90   } else if (this->UseWatcomQuote) {
91     shellFormat = cmOutputConverter::WATCOMQUOTE;
92   } else if (this->UseNinjaMulti) {
93     shellFormat = cmOutputConverter::NINJAMULTI;
94   }
95
96   return this->OutputConverter->ConvertToOutputFormat(input, shellFormat);
97 }
98
99 std::string cmLinkLineComputer::ConvertToOutputForExisting(
100   std::string const& input)
101 {
102   cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
103   if (this->ForResponse) {
104     shellFormat = cmOutputConverter::RESPONSE;
105   } else if (this->UseWatcomQuote) {
106     shellFormat = cmOutputConverter::WATCOMQUOTE;
107   } else if (this->UseNinjaMulti) {
108     shellFormat = cmOutputConverter::NINJAMULTI;
109   }
110
111   return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat);
112 }
113
114 std::string cmLinkLineComputer::ComputeLinkPath(
115   cmComputeLinkInformation& cli, std::string const& libPathFlag,
116   std::string const& libPathTerminator)
117 {
118   std::string linkPath;
119   std::vector<BT<std::string>> linkPathList;
120   this->ComputeLinkPath(cli, libPathFlag, libPathTerminator, linkPathList);
121   cli.AppendValues(linkPath, linkPathList);
122   return linkPath;
123 }
124
125 void cmLinkLineComputer::ComputeLinkPath(
126   cmComputeLinkInformation& cli, std::string const& libPathFlag,
127   std::string const& libPathTerminator, std::vector<BT<std::string>>& linkPath)
128 {
129   if (cli.GetLinkLanguage() == "Swift") {
130     std::string linkPathNoBT;
131
132     for (const cmComputeLinkInformation::Item& item : cli.GetItems()) {
133       const cmGeneratorTarget* target = item.Target;
134       if (!target) {
135         continue;
136       }
137
138       if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
139           target->GetType() == cmStateEnums::SHARED_LIBRARY) {
140         cmStateEnums::ArtifactType type = cmStateEnums::RuntimeBinaryArtifact;
141         if (target->HasImportLibrary(cli.GetConfig())) {
142           type = cmStateEnums::ImportLibraryArtifact;
143         }
144
145         linkPathNoBT +=
146           cmStrCat(" ", libPathFlag,
147                    this->ConvertToOutputForExisting(
148                      item.Target->GetDirectory(cli.GetConfig(), type)),
149                    libPathTerminator, " ");
150       }
151     }
152
153     if (!linkPathNoBT.empty()) {
154       linkPath.emplace_back(std::move(linkPathNoBT));
155     }
156   }
157
158   for (BT<std::string> libDir : cli.GetDirectoriesWithBacktraces()) {
159     libDir.Value = cmStrCat(" ", libPathFlag,
160                             this->ConvertToOutputForExisting(libDir.Value),
161                             libPathTerminator, " ");
162     linkPath.emplace_back(libDir);
163   }
164 }
165
166 std::string cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation& cli)
167 {
168   std::string rpath;
169   // Check what kind of rpath flags to use.
170   if (cli.GetRuntimeSep().empty()) {
171     // Each rpath entry gets its own option ("-R a -R b -R c")
172     std::vector<std::string> runtimeDirs;
173     cli.GetRPath(runtimeDirs, this->Relink);
174
175     for (std::string const& rd : runtimeDirs) {
176       rpath += cli.GetRuntimeFlag();
177       rpath += this->ConvertToOutputFormat(rd);
178       rpath += " ";
179     }
180   } else {
181     // All rpath entries are combined ("-Wl,-rpath,a:b:c").
182     std::string rpathString = cli.GetRPathString(this->Relink);
183
184     // Store the rpath option in the stream.
185     if (!rpathString.empty()) {
186       rpath += cli.GetRuntimeFlag();
187       rpath +=
188         this->OutputConverter->EscapeForShell(rpathString, !this->ForResponse);
189       rpath += " ";
190     }
191   }
192   return rpath;
193 }
194
195 std::string cmLinkLineComputer::ComputeFrameworkPath(
196   cmComputeLinkInformation& cli, std::string const& fwSearchFlag)
197 {
198   std::string frameworkPath;
199   if (!fwSearchFlag.empty()) {
200     std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
201     for (std::string const& fd : fwDirs) {
202       frameworkPath += fwSearchFlag;
203       frameworkPath += this->ConvertToOutputFormat(fd);
204       frameworkPath += " ";
205     }
206   }
207   return frameworkPath;
208 }
209
210 std::string cmLinkLineComputer::ComputeLinkLibraries(
211   cmComputeLinkInformation& cli, std::string const& stdLibString)
212 {
213   std::string linkLibraries;
214   std::vector<BT<std::string>> linkLibrariesList;
215   this->ComputeLinkLibraries(cli, stdLibString, linkLibrariesList);
216   cli.AppendValues(linkLibraries, linkLibrariesList);
217   return linkLibraries;
218 }
219
220 void cmLinkLineComputer::ComputeLinkLibraries(
221   cmComputeLinkInformation& cli, std::string const& stdLibString,
222   std::vector<BT<std::string>>& linkLibraries)
223 {
224   std::ostringstream rpathOut;
225   rpathOut << this->ComputeRPath(cli);
226
227   std::string rpath = rpathOut.str();
228   if (!rpath.empty()) {
229     linkLibraries.emplace_back(std::move(rpath));
230   }
231
232   // Write the library flags to the build rule.
233   this->ComputeLinkLibs(cli, linkLibraries);
234
235   // Add the linker runtime search path if any.
236   std::ostringstream fout;
237   std::string rpath_link = cli.GetRPathLinkString();
238   if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
239     fout << cli.GetRPathLinkFlag();
240     fout << this->OutputConverter->EscapeForShell(rpath_link,
241                                                   !this->ForResponse);
242     fout << " ";
243   }
244
245   if (!stdLibString.empty()) {
246     fout << stdLibString << " ";
247   }
248
249   std::string remainingLibs = fout.str();
250   if (!remainingLibs.empty()) {
251     linkLibraries.emplace_back(remainingLibs);
252   }
253 }
254
255 std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target,
256                                                   std::string const& config)
257 {
258   return target->GetLinkerLanguage(config);
259 }