Coverage Report

Created: 2026-07-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmExportBuildFileGenerator.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
#include "cmExportBuildFileGenerator.h"
4
5
#include <algorithm>
6
#include <memory>
7
#include <set>
8
#include <sstream>
9
#include <utility>
10
11
#include "cmExportSet.h"
12
#include "cmGeneratorExpression.h"
13
#include "cmGeneratorFileSet.h"
14
#include "cmGeneratorFileSets.h"
15
#include "cmGeneratorTarget.h"
16
#include "cmGlobalGenerator.h"
17
#include "cmList.h"
18
#include "cmLocalGenerator.h"
19
#include "cmMakefile.h"
20
#include "cmStateTypes.h"
21
#include "cmStringAlgorithms.h"
22
#include "cmTarget.h"
23
#include "cmTargetExport.h"
24
#include "cmValue.h"
25
26
class cmSourceFile;
27
28
cmExportBuildFileGenerator::cmExportBuildFileGenerator(
29
  cmDiagnosticContext context)
30
0
  : Context(std::move(context))
31
0
{
32
0
  this->LG = nullptr;
33
0
  this->ExportSet = nullptr;
34
0
}
35
36
cmDiagnosticContext cmExportBuildFileGenerator::CaptureContext(
37
  cmMakefile const& mf)
38
0
{
39
0
  cmDiagnosticContext context{ mf.GetBacktrace() };
40
0
  context.RecordDiagnostic(cmDiagnostics::CMD_AUTHOR, mf.GetStateSnapshot());
41
0
  return context;
42
0
}
43
44
void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
45
0
{
46
0
  this->LG = lg;
47
0
  if (this->ExportSet) {
48
0
    this->ExportSet->Compute(lg);
49
0
  }
50
0
}
51
52
cm::TargetType cmExportBuildFileGenerator::GetExportTargetType(
53
  cmGeneratorTarget const* target) const
54
0
{
55
0
  cm::TargetType targetType = target->GetType();
56
  // An object library exports as an interface library if we cannot
57
  // tell clients where to find the objects.  This is sufficient
58
  // to support transitive usage requirements on other targets that
59
  // use the object library.
60
0
  if (targetType == cm::TargetType::OBJECT_LIBRARY &&
61
0
      !target->Target->HasKnownObjectFileLocation(nullptr)) {
62
0
    targetType = cm::TargetType::INTERFACE_LIBRARY;
63
0
  }
64
0
  return targetType;
65
0
}
66
67
void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet)
68
0
{
69
0
  this->ExportSet = exportSet;
70
0
}
71
72
void cmExportBuildFileGenerator::SetImportLocationProperty(
73
  std::string const& config, std::string const& suffix,
74
  cmGeneratorTarget* target, ImportPropertyMap& properties)
75
0
{
76
  // Get the makefile in which to lookup target information.
77
0
  cmMakefile* mf = target->Makefile;
78
79
0
  if (target->GetType() == cm::TargetType::OBJECT_LIBRARY) {
80
0
    std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
81
82
    // Compute all the object files inside this target and setup
83
    // IMPORTED_OBJECTS as a list of object files
84
0
    std::vector<cmSourceFile const*> objectSources;
85
0
    target->GetObjectSources(objectSources, config);
86
0
    std::string const obj_dir = target->GetObjectDirectory(config);
87
0
    std::vector<std::string> objects;
88
0
    for (cmSourceFile const* sf : objectSources) {
89
0
      std::string const& obj = target->GetObjectName(sf);
90
0
      objects.push_back(obj_dir + obj);
91
0
    }
92
93
    // Store the property.
94
0
    properties[prop] = cmList::to_string(objects);
95
0
  } else {
96
    // Add the main target file.
97
0
    {
98
0
      std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
99
0
      std::string value;
100
0
      if (target->IsAppBundleOnApple()) {
101
0
        value =
102
0
          target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
103
0
      } else {
104
0
        value = target->GetFullPath(config,
105
0
                                    cmStateEnums::RuntimeBinaryArtifact, true);
106
0
      }
107
0
      properties[prop] = value;
108
0
    }
109
110
    // Add the import library for windows DLLs.
111
0
    if (target->HasImportLibrary(config)) {
112
0
      std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
113
0
      std::string value =
114
0
        target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true);
115
0
      if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
116
0
        target->GetImplibGNUtoMS(config, value, value,
117
0
                                 "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
118
0
      }
119
0
      properties[prop] = value;
120
0
    }
121
0
  }
122
0
}
123
124
bool cmExportBuildFileGenerator::CollectExports(
125
  std::function<void(cmGeneratorTarget const*)> visitor)
126
0
{
127
0
  auto pred = [&](cmExportBuildFileGenerator::TargetExport& tei) -> bool {
128
0
    cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name);
129
0
    if (this->ExportedTargets.insert(te).second) {
130
0
      this->Exports.emplace_back(te, tei.XcFrameworkLocation);
131
0
      visitor(te);
132
0
      return true;
133
0
    }
134
135
0
    this->ComplainAboutDuplicateTarget(te->GetName());
136
0
    return false;
137
0
  };
138
139
0
  std::vector<TargetExport> targets;
140
0
  this->GetTargets(targets);
141
0
  return std::all_of(targets.begin(), targets.end(), pred);
142
0
}
143
144
void cmExportBuildFileGenerator::HandleMissingTarget(
145
  std::string& link_libs, cmGeneratorTarget const* depender,
146
  cmGeneratorTarget* dependee)
147
0
{
148
  // The target is not in the export.
149
0
  if (!this->AppendMode) {
150
0
    auto const& exportInfo = this->FindExportInfo(dependee);
151
152
0
    if (exportInfo.Namespaces.size() == 1 && exportInfo.Sets.size() == 1) {
153
0
      std::string missingTarget = *exportInfo.Namespaces.begin();
154
155
0
      missingTarget += dependee->GetExportName();
156
0
      link_libs += missingTarget;
157
0
      this->MissingTargets.emplace_back(std::move(missingTarget));
158
0
      return;
159
0
    }
160
    // We are not appending, so all exported targets should be
161
    // known here.  This is probably user-error.
162
0
    this->ComplainAboutMissingTarget(depender, dependee, exportInfo);
163
0
  }
164
  // Assume the target will be exported by another command.
165
  // Append it with the export namespace.
166
0
  link_libs += this->Namespace;
167
0
  link_libs += dependee->GetExportName();
168
0
}
169
170
void cmExportBuildFileGenerator::GetTargets(
171
  std::vector<TargetExport>& targets) const
172
0
{
173
0
  if (this->ExportSet) {
174
0
    for (std::unique_ptr<cmTargetExport> const& te :
175
0
         this->ExportSet->GetTargetExports()) {
176
0
      if (te->NamelinkOnly) {
177
0
        continue;
178
0
      }
179
0
      targets.emplace_back(te->TargetName, te->XcFrameworkLocation);
180
0
    }
181
0
    return;
182
0
  }
183
0
  targets = this->Targets;
184
0
}
185
186
cmExportFileGenerator::ExportInfo cmExportBuildFileGenerator::FindExportInfo(
187
  cmGeneratorTarget const* target) const
188
0
{
189
0
  return target->GetLocalGenerator()
190
0
    ->GetGlobalGenerator()
191
0
    ->FindBuildExportInfo(target);
192
0
}
193
194
cm::optional<cmExportBuildFileGenerator::ExportRecord>
195
cmExportBuildFileGenerator::FindRecordForTarget(
196
  cmGeneratorTarget const* target) const
197
0
{
198
0
  auto const& name = target->GetName();
199
0
  std::vector<TargetExport> targets;
200
0
  this->GetTargets(targets);
201
0
  bool const contains =
202
0
    std::any_of(targets.begin(), targets.end(),
203
0
                [&name](TargetExport const& te) { return te.Name == name; });
204
0
  cm::optional<ExportRecord> result;
205
0
  if (contains) {
206
0
    ExportRecord rec;
207
0
    rec.Name = this->ExportSet ? this->ExportSet->GetName() : std::string{};
208
0
    rec.Namespace = this->GetNamespace();
209
0
    result = rec;
210
0
  }
211
0
  return result;
212
0
}
213
214
void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
215
  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
216
  ExportInfo const& exportInfo) const
217
0
{
218
0
  std::ostringstream e;
219
0
  e << "export called with target \"" << depender->GetName()
220
0
    << "\" which requires target \"" << dependee->GetName() << "\" ";
221
0
  if (exportInfo.Sets.empty()) {
222
0
    e << "that is not in any export set.";
223
0
  } else {
224
0
    if (exportInfo.Sets.size() == 1) {
225
0
      e << "that is not in this export set, but in another export set which "
226
0
           "is "
227
0
           "exported multiple times with different namespaces: ";
228
0
    } else {
229
0
      e << "that is not in this export set, but in multiple other export "
230
0
           "sets: ";
231
0
    }
232
0
    e << cmJoin(exportInfo.Files, ", ") << ".\n"
233
0
      << "An exported target cannot depend upon another target which is "
234
0
         "exported in more than one export set or with more than one "
235
0
         "namespace. Consider consolidating the exports of the \""
236
0
      << dependee->GetName() << "\" target to a single export.";
237
0
  }
238
239
0
  this->ReportError(e.str());
240
0
}
241
242
void cmExportBuildFileGenerator::ComplainAboutDuplicateTarget(
243
  std::string const& targetName) const
244
0
{
245
0
  std::ostringstream e;
246
0
  e << "given target \"" << targetName << "\" more than once.";
247
0
  this->ReportError(e.str());
248
0
}
249
250
void cmExportBuildFileGenerator::IssueMessage(MessageType type,
251
                                              std::string const& message) const
252
0
{
253
0
  this->LG->GetMakefile()->IssueMessage(type, message);
254
0
}
255
256
void cmExportBuildFileGenerator::IssueDiagnostic(
257
  cmDiagnosticCategory category, std::string const& message) const
258
0
{
259
0
  this->LG->GetMakefile()->IssueDiagnostic(category, message, this->Context);
260
0
}
261
262
std::string cmExportBuildFileGenerator::InstallNameDir(
263
  cmGeneratorTarget const* target, std::string const& config)
264
0
{
265
0
  std::string install_name_dir;
266
267
0
  cmMakefile* mf = target->Target->GetMakefile();
268
0
  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
269
0
    install_name_dir = target->GetInstallNameDirForBuildTree(config);
270
0
  }
271
272
0
  return install_name_dir;
273
0
}
274
275
bool cmExportBuildFileGenerator::PopulateInterfaceProperties(
276
  cmGeneratorTarget const* target, ImportPropertyMap& properties)
277
0
{
278
0
  this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", target,
279
0
                                  cmGeneratorExpression::BuildInterface,
280
0
                                  properties);
281
0
  this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", target,
282
0
                                  cmGeneratorExpression::BuildInterface,
283
0
                                  properties);
284
0
  this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", target,
285
0
                                  cmGeneratorExpression::BuildInterface,
286
0
                                  properties);
287
0
  this->PopulateInterfaceProperty("INTERFACE_SOURCES", target,
288
0
                                  cmGeneratorExpression::BuildInterface,
289
0
                                  properties);
290
291
0
  return this->PopulateInterfaceProperties(
292
0
    target, {}, cmGeneratorExpression::BuildInterface, properties);
293
0
}
294
295
bool cmExportBuildFileGenerator::PopulateFileSetInterfaceProperties(
296
  cmGeneratorTarget const* target, ImportFileSetPropertyMap& properties)
297
0
{
298
0
  cmGeneratorFileSets const* const gfs = target->GetGeneratorFileSets();
299
0
  bool result = true;
300
301
0
  for (auto const& type : gfs->GetInterfaceFileSetTypes()) {
302
0
    for (auto const* fileSet : gfs->GetInterfaceFileSets(type)) {
303
0
      ImportPropertyMap& fsProperties = properties[fileSet->GetName()];
304
0
      this->PopulateFileSetInterfaceProperty(
305
0
        "INTERFACE_INCLUDE_DIRECTORIES", target, fileSet,
306
0
        cmGeneratorExpression::BuildInterface, fsProperties);
307
0
      result = result &&
308
0
        this->PopulateFileSetInterfaceProperties(
309
0
          target, fileSet, cmGeneratorExpression::InstallInterface,
310
0
          fsProperties);
311
0
    }
312
0
  }
313
0
  return result;
314
0
}