Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmAddExecutableCommand.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 "cmAddExecutableCommand.h"
4
5
#include "cmExecutionStatus.h"
6
#include "cmGeneratorExpression.h"
7
#include "cmGlobalGenerator.h"
8
#include "cmMakefile.h"
9
#include "cmStateTypes.h"
10
#include "cmStringAlgorithms.h"
11
#include "cmTarget.h"
12
13
bool cmAddExecutableCommand(std::vector<std::string> const& args,
14
                            cmExecutionStatus& status)
15
0
{
16
0
  if (args.empty()) {
17
0
    status.SetError("called with incorrect number of arguments");
18
0
    return false;
19
0
  }
20
21
0
  cmMakefile& mf = status.GetMakefile();
22
0
  auto s = args.begin();
23
24
0
  std::string const& exename = *s;
25
26
0
  ++s;
27
0
  bool use_win32 = false;
28
0
  bool use_macbundle = false;
29
0
  bool excludeFromAll = false;
30
0
  bool importTarget = false;
31
0
  bool importGlobal = false;
32
0
  bool isAlias = false;
33
0
  while (s != args.end()) {
34
0
    if (*s == "WIN32") {
35
0
      ++s;
36
0
      use_win32 = true;
37
0
    } else if (*s == "MACOSX_BUNDLE") {
38
0
      ++s;
39
0
      use_macbundle = true;
40
0
    } else if (*s == "EXCLUDE_FROM_ALL") {
41
0
      ++s;
42
0
      excludeFromAll = true;
43
0
    } else if (*s == "IMPORTED") {
44
0
      ++s;
45
0
      importTarget = true;
46
0
    } else if (importTarget && *s == "GLOBAL") {
47
0
      ++s;
48
0
      importGlobal = true;
49
0
    } else if (*s == "ALIAS") {
50
0
      ++s;
51
0
      isAlias = true;
52
0
    } else {
53
0
      break;
54
0
    }
55
0
  }
56
57
0
  if (importTarget && !importGlobal) {
58
0
    importGlobal = mf.IsImportedTargetGlobalScope();
59
0
  }
60
61
0
  bool nameOk = cmGeneratorExpression::IsValidTargetName(exename) &&
62
0
    !cmGlobalGenerator::IsReservedTarget(exename);
63
64
0
  if (nameOk && !importTarget && !isAlias) {
65
0
    nameOk = exename.find(':') == std::string::npos;
66
0
  }
67
0
  if (!nameOk) {
68
0
    mf.IssueInvalidTargetNameError(exename);
69
0
    return false;
70
0
  }
71
72
  // Special modifiers are not allowed with IMPORTED signature.
73
0
  if (importTarget && (use_win32 || use_macbundle || excludeFromAll)) {
74
0
    if (use_win32) {
75
0
      status.SetError("may not be given WIN32 for an IMPORTED target.");
76
0
    } else if (use_macbundle) {
77
0
      status.SetError(
78
0
        "may not be given MACOSX_BUNDLE for an IMPORTED target.");
79
0
    } else // if(excludeFromAll)
80
0
    {
81
0
      status.SetError(
82
0
        "may not be given EXCLUDE_FROM_ALL for an IMPORTED target.");
83
0
    }
84
0
    return false;
85
0
  }
86
0
  if (isAlias) {
87
0
    if (!cmGeneratorExpression::IsValidTargetName(exename)) {
88
0
      status.SetError("Invalid name for ALIAS: " + exename);
89
0
      return false;
90
0
    }
91
0
    if (excludeFromAll) {
92
0
      status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
93
0
      return false;
94
0
    }
95
0
    if (importTarget || importGlobal) {
96
0
      status.SetError("IMPORTED with ALIAS is not allowed.");
97
0
      return false;
98
0
    }
99
0
    if (args.size() != 3) {
100
0
      status.SetError("ALIAS requires exactly one target argument.");
101
0
      return false;
102
0
    }
103
104
0
    std::string const& aliasedName = *s;
105
0
    if (mf.IsAlias(aliasedName)) {
106
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
107
0
                               "\" because target \"", aliasedName,
108
0
                               "\" is itself an ALIAS."));
109
0
      return false;
110
0
    }
111
0
    cmTarget* aliasedTarget =
112
0
      mf.FindTargetToUse(aliasedName, { cmStateEnums::TargetDomain::NATIVE });
113
0
    if (!aliasedTarget) {
114
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
115
0
                               "\" because target \"", aliasedName,
116
0
                               "\" does not already exist."));
117
0
      return false;
118
0
    }
119
0
    cmStateEnums::TargetType type = aliasedTarget->GetType();
120
0
    if (type != cmStateEnums::EXECUTABLE) {
121
0
      status.SetError(cmStrCat("cannot create ALIAS target \"", exename,
122
0
                               "\" because target \"", aliasedName,
123
0
                               "\" is not an executable."));
124
0
      return false;
125
0
    }
126
0
    mf.AddAlias(exename, aliasedName,
127
0
                !aliasedTarget->IsImported() ||
128
0
                  aliasedTarget->IsImportedGloballyVisible());
129
0
    return true;
130
0
  }
131
132
  // Handle imported target creation.
133
0
  if (importTarget) {
134
    // Make sure the target does not already exist.
135
0
    if (mf.FindTargetToUse(exename)) {
136
0
      status.SetError(cmStrCat(
137
0
        "cannot create imported target \"", exename,
138
0
        "\" because another target with the same name already exists."));
139
0
      return false;
140
0
    }
141
142
    // Create the imported target.
143
0
    mf.AddImportedTarget(exename, cmStateEnums::EXECUTABLE, importGlobal);
144
0
    return true;
145
0
  }
146
147
  // Enforce name uniqueness.
148
0
  {
149
0
    std::string msg;
150
0
    if (!mf.EnforceUniqueName(exename, msg)) {
151
0
      status.SetError(msg);
152
0
      return false;
153
0
    }
154
0
  }
155
156
0
  std::vector<std::string> srclists(s, args.end());
157
0
  cmTarget* tgt = mf.AddExecutable(exename, srclists, excludeFromAll);
158
0
  if (use_win32) {
159
0
    tgt->SetProperty("WIN32_EXECUTABLE", "ON");
160
0
  }
161
0
  if (use_macbundle) {
162
0
    tgt->SetProperty("MACOSX_BUNDLE", "ON");
163
0
  }
164
165
0
  return true;
166
0
}