Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmAddLibraryCommand.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 "cmAddLibraryCommand.h"
4
5
#include "cmDiagnostics.h"
6
#include "cmExecutionStatus.h"
7
#include "cmGeneratorExpression.h"
8
#include "cmGlobalGenerator.h"
9
#include "cmMakefile.h"
10
#include "cmMessageType.h"
11
#include "cmPolicies.h"
12
#include "cmState.h"
13
#include "cmStateTypes.h"
14
#include "cmStringAlgorithms.h"
15
#include "cmSystemTools.h"
16
#include "cmTarget.h"
17
#include "cmValue.h"
18
19
bool cmAddLibraryCommand(std::vector<std::string> const& args,
20
                         cmExecutionStatus& status)
21
0
{
22
0
  if (args.empty()) {
23
0
    status.SetError("called with incorrect number of arguments");
24
0
    return false;
25
0
  }
26
27
0
  cmMakefile& mf = status.GetMakefile();
28
  // Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
29
  // otherwise it defaults to static library.
30
0
  cmStateEnums::TargetType type = cmStateEnums::SHARED_LIBRARY;
31
0
  if (mf.GetDefinition("BUILD_SHARED_LIBS").IsOff()) {
32
0
    type = cmStateEnums::STATIC_LIBRARY;
33
0
  }
34
0
  bool excludeFromAll = false;
35
0
  bool importTarget = false;
36
0
  bool importGlobal = false;
37
0
  bool symbolicTarget = false;
38
39
0
  auto s = args.begin();
40
41
0
  std::string const& libName = *s;
42
43
0
  ++s;
44
45
  // If the second argument is "SHARED" or "STATIC", then it controls
46
  // the type of library.  Otherwise, it is treated as a source or
47
  // source list name. There may be two keyword arguments, check for them
48
0
  bool haveSpecifiedType = false;
49
0
  bool isAlias = false;
50
0
  while (s != args.end()) {
51
0
    std::string libType = *s;
52
0
    if (libType == "STATIC") {
53
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
54
0
        status.SetError(
55
0
          "INTERFACE library specified with conflicting STATIC type.");
56
0
        return false;
57
0
      }
58
0
      ++s;
59
0
      type = cmStateEnums::STATIC_LIBRARY;
60
0
      haveSpecifiedType = true;
61
0
    } else if (libType == "SHARED") {
62
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
63
0
        status.SetError(
64
0
          "INTERFACE library specified with conflicting SHARED type.");
65
0
        return false;
66
0
      }
67
0
      ++s;
68
0
      type = cmStateEnums::SHARED_LIBRARY;
69
0
      haveSpecifiedType = true;
70
0
    } else if (libType == "MODULE") {
71
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
72
0
        status.SetError(
73
0
          "INTERFACE library specified with conflicting MODULE type.");
74
0
        return false;
75
0
      }
76
0
      ++s;
77
0
      type = cmStateEnums::MODULE_LIBRARY;
78
0
      haveSpecifiedType = true;
79
0
    } else if (libType == "OBJECT") {
80
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
81
0
        status.SetError(
82
0
          "INTERFACE library specified with conflicting OBJECT type.");
83
0
        return false;
84
0
      }
85
0
      ++s;
86
0
      type = cmStateEnums::OBJECT_LIBRARY;
87
0
      haveSpecifiedType = true;
88
0
    } else if (libType == "UNKNOWN") {
89
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
90
0
        status.SetError(
91
0
          "INTERFACE library specified with conflicting UNKNOWN type.");
92
0
        return false;
93
0
      }
94
0
      ++s;
95
0
      type = cmStateEnums::UNKNOWN_LIBRARY;
96
0
      haveSpecifiedType = true;
97
0
    } else if (libType == "ALIAS") {
98
0
      if (type == cmStateEnums::INTERFACE_LIBRARY) {
99
0
        status.SetError(
100
0
          "INTERFACE library specified with conflicting ALIAS type.");
101
0
        return false;
102
0
      }
103
0
      ++s;
104
0
      isAlias = true;
105
0
    } else if (libType == "INTERFACE") {
106
0
      if (haveSpecifiedType) {
107
0
        status.SetError(
108
0
          "INTERFACE library specified with conflicting/multiple types.");
109
0
        return false;
110
0
      }
111
0
      if (isAlias) {
112
0
        status.SetError(
113
0
          "INTERFACE library specified with conflicting ALIAS type.");
114
0
        return false;
115
0
      }
116
0
      ++s;
117
0
      type = cmStateEnums::INTERFACE_LIBRARY;
118
0
      haveSpecifiedType = true;
119
0
    } else if (*s == "EXCLUDE_FROM_ALL") {
120
0
      ++s;
121
0
      excludeFromAll = true;
122
0
    } else if (*s == "SYMBOLIC") {
123
0
      ++s;
124
0
      symbolicTarget = true;
125
0
    } else if (*s == "IMPORTED") {
126
0
      ++s;
127
0
      importTarget = true;
128
0
    } else if (importTarget && *s == "GLOBAL") {
129
0
      ++s;
130
0
      importGlobal = true;
131
0
    } else if (type == cmStateEnums::INTERFACE_LIBRARY && *s == "GLOBAL") {
132
0
      status.SetError(
133
0
        "GLOBAL option may only be used with IMPORTED libraries.");
134
0
      return false;
135
0
    } else {
136
0
      break;
137
0
    }
138
0
  }
139
140
0
  if (importTarget && !importGlobal) {
141
0
    importGlobal = mf.IsImportedTargetGlobalScope();
142
0
  }
143
144
0
  if (type == cmStateEnums::INTERFACE_LIBRARY) {
145
0
    if (importGlobal && !importTarget) {
146
0
      status.SetError(
147
0
        "INTERFACE library specified as GLOBAL, but not as IMPORTED.");
148
0
      return false;
149
0
    }
150
0
  }
151
152
0
  bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
153
0
    !cmGlobalGenerator::IsReservedTarget(libName);
154
155
0
  if (nameOk && !importTarget && !isAlias) {
156
0
    nameOk = libName.find(':') == std::string::npos;
157
0
  }
158
0
  if (!nameOk) {
159
0
    mf.IssueInvalidTargetNameError(libName);
160
0
    return false;
161
0
  }
162
163
0
  if (isAlias) {
164
0
    if (!cmGeneratorExpression::IsValidTargetName(libName)) {
165
0
      status.SetError("Invalid name for ALIAS: " + libName);
166
0
      return false;
167
0
    }
168
0
    if (excludeFromAll) {
169
0
      status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
170
0
      return false;
171
0
    }
172
0
    if (importTarget || importGlobal) {
173
0
      status.SetError("IMPORTED with ALIAS is not allowed.");
174
0
      return false;
175
0
    }
176
0
    if (args.size() != 3) {
177
0
      status.SetError("ALIAS requires exactly one target argument.");
178
0
      return false;
179
0
    }
180
181
0
    if (mf.GetPolicyStatus(cmPolicies::CMP0107) == cmPolicies::NEW) {
182
      // Make sure the target does not already exist.
183
0
      if (mf.FindTargetToUse(libName)) {
184
0
        status.SetError(cmStrCat(
185
0
          "cannot create ALIAS target \"", libName,
186
0
          "\" because another target with the same name already exists."));
187
0
        return false;
188
0
      }
189
0
    }
190
191
0
    std::string const& aliasedName = *s;
192
0
    if (mf.IsAlias(aliasedName)) {
193
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
194
0
                               "\" because target \"", aliasedName,
195
0
                               "\" is itself an ALIAS."));
196
0
      return false;
197
0
    }
198
0
    cmTarget* aliasedTarget =
199
0
      mf.FindTargetToUse(aliasedName, { cmStateEnums::TargetDomain::NATIVE });
200
0
    if (!aliasedTarget) {
201
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
202
0
                               "\" because target \"", aliasedName,
203
0
                               "\" does not already exist."));
204
0
      return false;
205
0
    }
206
0
    cmStateEnums::TargetType aliasedType = aliasedTarget->GetType();
207
0
    if (aliasedType != cmStateEnums::SHARED_LIBRARY &&
208
0
        aliasedType != cmStateEnums::STATIC_LIBRARY &&
209
0
        aliasedType != cmStateEnums::MODULE_LIBRARY &&
210
0
        aliasedType != cmStateEnums::OBJECT_LIBRARY &&
211
0
        aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
212
0
        !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
213
0
          aliasedTarget->IsImported())) {
214
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
215
0
                               "\" because target \"", aliasedName,
216
0
                               "\" is not a library."));
217
0
      return false;
218
0
    }
219
0
    mf.AddAlias(libName, aliasedName,
220
0
                !aliasedTarget->IsImported() ||
221
0
                  aliasedTarget->IsImportedGloballyVisible());
222
0
    return true;
223
0
  }
224
225
0
  if (importTarget && excludeFromAll) {
226
0
    status.SetError("excludeFromAll with IMPORTED target makes no sense.");
227
0
    return false;
228
0
  }
229
230
  /* ideally we should check whether for the linker language of the target
231
     CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
232
     STATIC. But at this point we know only the name of the target, but not
233
     yet its linker language. */
234
0
  if ((type == cmStateEnums::SHARED_LIBRARY ||
235
0
       type == cmStateEnums::MODULE_LIBRARY) &&
236
0
      !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
237
0
    switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0164)) {
238
0
      case cmPolicies::WARN:
239
0
        mf.IssueDiagnostic(
240
0
          cmDiagnostics::CMD_AUTHOR,
241
0
          cmStrCat(
242
0
            "ADD_LIBRARY called with ",
243
0
            (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
244
0
            " option but the target platform does not support dynamic "
245
0
            "linking. "
246
0
            "Building a STATIC library instead. This may lead to problems."));
247
0
        CM_FALLTHROUGH;
248
0
      case cmPolicies::OLD:
249
0
        type = cmStateEnums::STATIC_LIBRARY;
250
0
        break;
251
0
      case cmPolicies::NEW:
252
0
        mf.IssueMessage(
253
0
          MessageType::FATAL_ERROR,
254
0
          cmStrCat(
255
0
            "ADD_LIBRARY called with ",
256
0
            (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
257
0
            " option but the target platform does not support dynamic "
258
0
            "linking."));
259
0
        cmSystemTools::SetFatalErrorOccurred();
260
0
        return false;
261
0
      default:
262
0
        break;
263
0
    }
264
0
  }
265
266
  // Handle imported target creation.
267
0
  if (importTarget) {
268
    // The IMPORTED signature requires a type to be specified explicitly.
269
0
    if (!haveSpecifiedType) {
270
0
      status.SetError("called with IMPORTED argument but no library type.");
271
0
      return false;
272
0
    }
273
0
    if (type == cmStateEnums::INTERFACE_LIBRARY) {
274
0
      if (!cmGeneratorExpression::IsValidTargetName(libName)) {
275
0
        status.SetError(cmStrCat(
276
0
          "Invalid name for IMPORTED INTERFACE library target: ", libName));
277
0
        return false;
278
0
      }
279
0
    }
280
281
    // Make sure the target does not already exist.
282
0
    if (mf.FindTargetToUse(libName)) {
283
0
      status.SetError(cmStrCat(
284
0
        "cannot create imported target \"", libName,
285
0
        "\" because another target with the same name already exists."));
286
0
      return false;
287
0
    }
288
289
    // Create the imported target.
290
0
    cmTarget* target = mf.AddImportedTarget(libName, type, importGlobal);
291
0
    target->SetSymbolic(symbolicTarget);
292
0
    return true;
293
0
  }
294
295
  // A non-imported target may not have UNKNOWN type.
296
0
  if (type == cmStateEnums::UNKNOWN_LIBRARY) {
297
0
    mf.IssueMessage(
298
0
      MessageType::FATAL_ERROR,
299
0
      "The UNKNOWN library type may be used only for IMPORTED libraries.");
300
0
    return true;
301
0
  }
302
303
  // Enforce name uniqueness.
304
0
  {
305
0
    std::string msg;
306
0
    if (!mf.EnforceUniqueName(libName, msg)) {
307
0
      status.SetError(msg);
308
0
      return false;
309
0
    }
310
0
  }
311
312
0
  if (type == cmStateEnums::INTERFACE_LIBRARY) {
313
0
    if (!cmGeneratorExpression::IsValidTargetName(libName) ||
314
0
        libName.find("::") != std::string::npos) {
315
0
      status.SetError(
316
0
        cmStrCat("Invalid name for INTERFACE library target: ", libName));
317
0
      return false;
318
0
    }
319
0
  }
320
321
0
  if (symbolicTarget && type != cmStateEnums::INTERFACE_LIBRARY) {
322
0
    status.SetError(
323
0
      "SYMBOLIC option may only be used with INTERFACE libraries");
324
0
    return false;
325
0
  }
326
327
0
  std::vector<std::string> srcs(s, args.end());
328
0
  cmTarget* target = mf.AddLibrary(libName, type, srcs, excludeFromAll);
329
0
  target->SetSymbolic(symbolicTarget);
330
331
0
  return true;
332
0
}