Coverage Report

Created: 2026-07-14 07:09

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