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"
12 #include "cmListFileCache.h"
13 #include "cmOutputConverter.h"
14 #include "cmStateTypes.h"
15 #include "cmStringAlgorithms.h"
17 cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter
* outputConverter
,
18 cmStateDirectory
const& stateDir
)
20 , OutputConverter(outputConverter
)
24 cmLinkLineComputer::~cmLinkLineComputer() = default;
26 void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote
)
28 this->UseWatcomQuote
= useWatcomQuote
;
31 void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti
)
33 this->UseNinjaMulti
= useNinjaMulti
;
36 void cmLinkLineComputer::SetForResponse(bool forResponse
)
38 this->ForResponse
= forResponse
;
41 void cmLinkLineComputer::SetRelink(bool relink
)
43 this->Relink
= relink
;
46 std::string
cmLinkLineComputer::ConvertToLinkReference(
47 std::string
const& lib
) const
49 return this->OutputConverter
->MaybeRelativeToCurBinDir(lib
);
52 std::string
cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation
& cli
)
55 std::vector
<BT
<std::string
>> linkLibsList
;
56 this->ComputeLinkLibs(cli
, linkLibsList
);
57 cli
.AppendValues(linkLibs
, linkLibsList
);
61 void cmLinkLineComputer::ComputeLinkLibs(
62 cmComputeLinkInformation
& cli
, std::vector
<BT
<std::string
>>& linkLibraries
)
64 using ItemVector
= cmComputeLinkInformation::ItemVector
;
65 ItemVector
const& items
= cli
.GetItems();
66 for (auto const& item
: items
) {
68 (item
.Target
->GetType() == cmStateEnums::INTERFACE_LIBRARY
||
69 item
.Target
->GetType() == cmStateEnums::OBJECT_LIBRARY
)) {
73 BT
<std::string
> linkLib
;
74 if (item
.IsPath
== cmComputeLinkInformation::ItemIsPath::Yes
) {
75 linkLib
= item
.GetFormattedItem(this->ConvertToOutputFormat(
76 this->ConvertToLinkReference(item
.Value
.Value
)));
82 linkLibraries
.emplace_back(linkLib
);
86 std::string
cmLinkLineComputer::ConvertToOutputFormat(std::string
const& input
)
88 cmOutputConverter::OutputFormat shellFormat
= cmOutputConverter::SHELL
;
89 if (this->ForResponse
) {
90 shellFormat
= cmOutputConverter::RESPONSE
;
91 } else if (this->UseNinjaMulti
) {
92 shellFormat
= cmOutputConverter::NINJAMULTI
;
95 return this->OutputConverter
->ConvertToOutputFormat(input
, shellFormat
,
96 this->UseWatcomQuote
);
99 std::string
cmLinkLineComputer::ConvertToOutputForExisting(
100 std::string
const& input
)
102 cmOutputConverter::OutputFormat shellFormat
= cmOutputConverter::SHELL
;
103 if (this->ForResponse
) {
104 shellFormat
= cmOutputConverter::RESPONSE
;
105 } else if (this->UseNinjaMulti
) {
106 shellFormat
= cmOutputConverter::NINJAMULTI
;
109 return this->OutputConverter
->ConvertToOutputForExisting(
110 input
, shellFormat
, this->UseWatcomQuote
);
113 std::string
cmLinkLineComputer::ComputeLinkPath(
114 cmComputeLinkInformation
& cli
, std::string
const& libPathFlag
,
115 std::string
const& libPathTerminator
)
117 std::string linkPath
;
118 std::vector
<BT
<std::string
>> linkPathList
;
119 this->ComputeLinkPath(cli
, libPathFlag
, libPathTerminator
, linkPathList
);
120 cli
.AppendValues(linkPath
, linkPathList
);
124 void cmLinkLineComputer::ComputeLinkPath(
125 cmComputeLinkInformation
& cli
, std::string
const& libPathFlag
,
126 std::string
const& libPathTerminator
, std::vector
<BT
<std::string
>>& linkPath
)
128 if (cli
.GetLinkLanguage() == "Swift") {
129 std::string linkPathNoBT
;
131 for (const cmComputeLinkInformation::Item
& item
: cli
.GetItems()) {
132 const cmGeneratorTarget
* target
= item
.Target
;
137 if (target
->GetType() == cmStateEnums::STATIC_LIBRARY
||
138 target
->GetType() == cmStateEnums::SHARED_LIBRARY
) {
139 cmStateEnums::ArtifactType type
= cmStateEnums::RuntimeBinaryArtifact
;
140 if (target
->HasImportLibrary(cli
.GetConfig())) {
141 type
= cmStateEnums::ImportLibraryArtifact
;
145 cmStrCat(" ", libPathFlag
,
146 this->ConvertToOutputForExisting(
147 item
.Target
->GetDirectory(cli
.GetConfig(), type
)),
148 libPathTerminator
, " ");
152 if (!linkPathNoBT
.empty()) {
153 linkPath
.emplace_back(std::move(linkPathNoBT
));
157 for (BT
<std::string
> libDir
: cli
.GetDirectoriesWithBacktraces()) {
158 libDir
.Value
= cmStrCat(" ", libPathFlag
,
159 this->ConvertToOutputForExisting(libDir
.Value
),
160 libPathTerminator
, " ");
161 linkPath
.emplace_back(libDir
);
165 std::string
cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation
& cli
)
168 // Check what kind of rpath flags to use.
169 if (cli
.GetRuntimeSep().empty()) {
170 // Each rpath entry gets its own option ("-R a -R b -R c")
171 std::vector
<std::string
> runtimeDirs
;
172 cli
.GetRPath(runtimeDirs
, this->Relink
);
174 for (std::string
const& rd
: runtimeDirs
) {
175 rpath
+= cli
.GetRuntimeFlag();
176 rpath
+= this->ConvertToOutputFormat(rd
);
180 // All rpath entries are combined ("-Wl,-rpath,a:b:c").
181 std::string rpathString
= cli
.GetRPathString(this->Relink
);
183 // Store the rpath option in the stream.
184 if (!rpathString
.empty()) {
185 rpath
+= cli
.GetRuntimeFlag();
187 this->OutputConverter
->EscapeForShell(rpathString
, !this->ForResponse
);
194 std::string
cmLinkLineComputer::ComputeFrameworkPath(
195 cmComputeLinkInformation
& cli
, cmValue fwSearchFlag
)
198 return std::string
{};
201 std::string frameworkPath
;
202 for (auto const& fd
: cli
.GetFrameworkPaths()) {
204 cmStrCat(fwSearchFlag
, this->ConvertToOutputFormat(fd
), ' ');
206 return frameworkPath
;
209 std::string
cmLinkLineComputer::ComputeLinkLibraries(
210 cmComputeLinkInformation
& cli
, std::string
const& stdLibString
)
212 std::string linkLibraries
;
213 std::vector
<BT
<std::string
>> linkLibrariesList
;
214 this->ComputeLinkLibraries(cli
, stdLibString
, linkLibrariesList
);
215 cli
.AppendValues(linkLibraries
, linkLibrariesList
);
216 return linkLibraries
;
219 void cmLinkLineComputer::ComputeLinkLibraries(
220 cmComputeLinkInformation
& cli
, std::string
const& stdLibString
,
221 std::vector
<BT
<std::string
>>& linkLibraries
)
223 std::ostringstream rpathOut
;
224 rpathOut
<< this->ComputeRPath(cli
);
226 std::string rpath
= rpathOut
.str();
227 if (!rpath
.empty()) {
228 linkLibraries
.emplace_back(std::move(rpath
));
231 // Write the library flags to the build rule.
232 this->ComputeLinkLibs(cli
, linkLibraries
);
234 // Add the linker runtime search path if any.
235 std::ostringstream fout
;
236 std::string rpath_link
= cli
.GetRPathLinkString();
237 if (!cli
.GetRPathLinkFlag().empty() && !rpath_link
.empty()) {
238 fout
<< cli
.GetRPathLinkFlag();
239 fout
<< this->OutputConverter
->EscapeForShell(rpath_link
,
244 if (!stdLibString
.empty()) {
245 fout
<< stdLibString
<< " ";
248 std::string remainingLibs
= fout
.str();
249 if (!remainingLibs
.empty()) {
250 linkLibraries
.emplace_back(remainingLibs
);
254 std::string
cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget
* target
,
255 std::string
const& config
)
257 return target
->GetLinkerLanguage(config
);