Coverage Report

Created: 2026-02-09 06:05

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