1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmLinkLineComputer.h"
10 #include "cmComputeLinkInformation.h"
11 #include "cmGeneratorTarget.h"
13 #include "cmListFileCache.h"
14 #include "cmOutputConverter.h"
15 #include "cmStateTypes.h"
16 #include "cmStringAlgorithms.h"
18 cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter
* outputConverter
,
19 cmStateDirectory
const& stateDir
)
21 , OutputConverter(outputConverter
)
25 cmLinkLineComputer::~cmLinkLineComputer() = default;
27 void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote
)
29 this->UseWatcomQuote
= useWatcomQuote
;
32 void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti
)
34 this->UseNinjaMulti
= useNinjaMulti
;
37 void cmLinkLineComputer::SetForResponse(bool forResponse
)
39 this->ForResponse
= forResponse
;
42 void cmLinkLineComputer::SetRelink(bool relink
)
44 this->Relink
= relink
;
47 std::string
cmLinkLineComputer::ConvertToLinkReference(
48 std::string
const& lib
) const
50 return this->OutputConverter
->MaybeRelativeToCurBinDir(lib
);
53 std::string
cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation
& cli
)
56 std::vector
<BT
<std::string
>> linkLibsList
;
57 this->ComputeLinkLibs(cli
, linkLibsList
);
58 cli
.AppendValues(linkLibs
, linkLibsList
);
62 void cmLinkLineComputer::ComputeLinkLibs(
63 cmComputeLinkInformation
& cli
, std::vector
<BT
<std::string
>>& linkLibraries
)
65 using ItemVector
= cmComputeLinkInformation::ItemVector
;
66 ItemVector
const& items
= cli
.GetItems();
67 for (auto const& item
: items
) {
69 (item
.Target
->GetType() == cmStateEnums::INTERFACE_LIBRARY
||
70 item
.Target
->GetType() == cmStateEnums::OBJECT_LIBRARY
)) {
74 BT
<std::string
> linkLib
;
75 if (item
.IsPath
== cmComputeLinkInformation::ItemIsPath::Yes
) {
76 linkLib
= item
.GetFormattedItem(this->ConvertToOutputFormat(
77 this->ConvertToLinkReference(item
.Value
.Value
)));
83 linkLibraries
.emplace_back(linkLib
);
87 std::string
cmLinkLineComputer::ConvertToOutputFormat(std::string
const& input
)
89 cmOutputConverter::OutputFormat shellFormat
= cmOutputConverter::SHELL
;
90 if (this->ForResponse
) {
91 shellFormat
= cmOutputConverter::RESPONSE
;
92 } else if (this->UseNinjaMulti
) {
93 shellFormat
= cmOutputConverter::NINJAMULTI
;
96 return this->OutputConverter
->ConvertToOutputFormat(input
, shellFormat
,
97 this->UseWatcomQuote
);
100 std::string
cmLinkLineComputer::ConvertToOutputForExisting(
101 std::string
const& input
)
103 cmOutputConverter::OutputFormat shellFormat
= cmOutputConverter::SHELL
;
104 if (this->ForResponse
) {
105 shellFormat
= cmOutputConverter::RESPONSE
;
106 } else if (this->UseNinjaMulti
) {
107 shellFormat
= cmOutputConverter::NINJAMULTI
;
110 return this->OutputConverter
->ConvertToOutputForExisting(
111 input
, shellFormat
, this->UseWatcomQuote
);
114 std::string
cmLinkLineComputer::ComputeLinkPath(
115 cmComputeLinkInformation
& cli
, std::string
const& libPathFlag
,
116 std::string
const& libPathTerminator
, std::string
const& stdLinkDirString
)
118 std::string linkPath
;
119 std::vector
<BT
<std::string
>> linkPathList
;
120 this->ComputeLinkPath(cli
, libPathFlag
, libPathTerminator
, stdLinkDirString
,
122 cli
.AppendValues(linkPath
, linkPathList
);
126 void cmLinkLineComputer::ComputeLinkPath(
127 cmComputeLinkInformation
& cli
, std::string
const& libPathFlag
,
128 std::string
const& libPathTerminator
, std::string
const& stdLinkDirString
,
129 std::vector
<BT
<std::string
>>& linkPath
)
131 if (cli
.GetLinkLanguage() == "Swift") {
132 std::string linkPathNoBT
;
134 for (const cmComputeLinkInformation::Item
& item
: cli
.GetItems()) {
135 const cmGeneratorTarget
* target
= item
.Target
;
140 if (target
->GetType() == cmStateEnums::STATIC_LIBRARY
||
141 target
->GetType() == cmStateEnums::SHARED_LIBRARY
) {
142 cmStateEnums::ArtifactType type
= cmStateEnums::RuntimeBinaryArtifact
;
143 if (target
->HasImportLibrary(cli
.GetConfig())) {
144 type
= cmStateEnums::ImportLibraryArtifact
;
148 cmStrCat(" ", libPathFlag
,
149 this->ConvertToOutputForExisting(
150 item
.Target
->GetDirectory(cli
.GetConfig(), type
)),
151 libPathTerminator
, " ");
155 if (!linkPathNoBT
.empty()) {
156 linkPath
.emplace_back(std::move(linkPathNoBT
));
160 for (BT
<std::string
> libDir
: cli
.GetDirectoriesWithBacktraces()) {
161 libDir
.Value
= cmStrCat(" ", libPathFlag
,
162 this->ConvertToOutputForExisting(libDir
.Value
),
163 libPathTerminator
, " ");
164 linkPath
.emplace_back(libDir
);
167 for (auto& linkDir
: cmList(stdLinkDirString
)) {
168 linkPath
.emplace_back(cmStrCat(' ', libPathFlag
,
169 this->ConvertToOutputForExisting(linkDir
),
170 libPathTerminator
, ' '));
174 std::string
cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation
& cli
)
177 // Check what kind of rpath flags to use.
178 if (cli
.GetRuntimeSep().empty()) {
179 // Each rpath entry gets its own option ("-R a -R b -R c")
180 std::vector
<std::string
> runtimeDirs
;
181 cli
.GetRPath(runtimeDirs
, this->Relink
);
183 for (std::string
const& rd
: runtimeDirs
) {
184 rpath
+= cli
.GetRuntimeFlag();
185 rpath
+= this->ConvertToOutputFormat(rd
);
189 // All rpath entries are combined ("-Wl,-rpath,a:b:c").
190 std::string rpathString
= cli
.GetRPathString(this->Relink
);
192 // Store the rpath option in the stream.
193 if (!rpathString
.empty()) {
194 rpath
+= cli
.GetRuntimeFlag();
196 this->OutputConverter
->EscapeForShell(rpathString
, !this->ForResponse
);
203 std::string
cmLinkLineComputer::ComputeFrameworkPath(
204 cmComputeLinkInformation
& cli
, cmValue fwSearchFlag
)
207 return std::string
{};
210 std::string frameworkPath
;
211 for (auto const& fd
: cli
.GetFrameworkPaths()) {
213 cmStrCat(fwSearchFlag
, this->ConvertToOutputFormat(fd
), ' ');
215 return frameworkPath
;
218 std::string
cmLinkLineComputer::ComputeLinkLibraries(
219 cmComputeLinkInformation
& cli
, std::string
const& stdLibString
)
221 std::string linkLibraries
;
222 std::vector
<BT
<std::string
>> linkLibrariesList
;
223 this->ComputeLinkLibraries(cli
, stdLibString
, linkLibrariesList
);
224 cli
.AppendValues(linkLibraries
, linkLibrariesList
);
225 return linkLibraries
;
228 void cmLinkLineComputer::ComputeLinkLibraries(
229 cmComputeLinkInformation
& cli
, std::string
const& stdLibString
,
230 std::vector
<BT
<std::string
>>& linkLibraries
)
232 std::ostringstream rpathOut
;
233 rpathOut
<< this->ComputeRPath(cli
);
235 std::string rpath
= rpathOut
.str();
236 if (!rpath
.empty()) {
237 linkLibraries
.emplace_back(std::move(rpath
));
240 // Write the library flags to the build rule.
241 this->ComputeLinkLibs(cli
, linkLibraries
);
243 // Add the linker runtime search path if any.
244 std::ostringstream fout
;
245 std::string rpath_link
= cli
.GetRPathLinkString();
246 if (!cli
.GetRPathLinkFlag().empty() && !rpath_link
.empty()) {
247 fout
<< cli
.GetRPathLinkFlag();
248 fout
<< this->OutputConverter
->EscapeForShell(rpath_link
,
253 if (!stdLibString
.empty()) {
254 fout
<< stdLibString
<< " ";
257 std::string remainingLibs
= fout
.str();
258 if (!remainingLibs
.empty()) {
259 linkLibraries
.emplace_back(remainingLibs
);
263 std::string
cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget
* target
,
264 std::string
const& config
)
266 return target
->GetLinkerLanguage(config
);