CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmAddLibraryCommand.cxx
blob9113dfd7a5b0fc13287655de8e8332f62764c7bb
1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmAddLibraryCommand.h"
5 #include "cmExecutionStatus.h"
6 #include "cmGeneratorExpression.h"
7 #include "cmGlobalGenerator.h"
8 #include "cmMakefile.h"
9 #include "cmMessageType.h"
10 #include "cmPolicies.h"
11 #include "cmState.h"
12 #include "cmStateTypes.h"
13 #include "cmStringAlgorithms.h"
14 #include "cmSystemTools.h"
15 #include "cmTarget.h"
16 #include "cmValue.h"
18 bool cmAddLibraryCommand(std::vector<std::string> const& args,
19 cmExecutionStatus& status)
21 if (args.empty()) {
22 status.SetError("called with incorrect number of arguments");
23 return false;
26 cmMakefile& mf = status.GetMakefile();
27 // Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
28 // otherwise it defaults to static library.
29 cmStateEnums::TargetType type = cmStateEnums::SHARED_LIBRARY;
30 if (mf.GetDefinition("BUILD_SHARED_LIBS").IsOff()) {
31 type = cmStateEnums::STATIC_LIBRARY;
33 bool excludeFromAll = false;
34 bool importTarget = false;
35 bool importGlobal = false;
37 auto s = args.begin();
39 std::string const& libName = *s;
41 ++s;
43 // If the second argument is "SHARED" or "STATIC", then it controls
44 // the type of library. Otherwise, it is treated as a source or
45 // source list name. There may be two keyword arguments, check for them
46 bool haveSpecifiedType = false;
47 bool isAlias = false;
48 while (s != args.end()) {
49 std::string libType = *s;
50 if (libType == "STATIC") {
51 if (type == cmStateEnums::INTERFACE_LIBRARY) {
52 status.SetError(
53 "INTERFACE library specified with conflicting STATIC type.");
54 return false;
56 ++s;
57 type = cmStateEnums::STATIC_LIBRARY;
58 haveSpecifiedType = true;
59 } else if (libType == "SHARED") {
60 if (type == cmStateEnums::INTERFACE_LIBRARY) {
61 status.SetError(
62 "INTERFACE library specified with conflicting SHARED type.");
63 return false;
65 ++s;
66 type = cmStateEnums::SHARED_LIBRARY;
67 haveSpecifiedType = true;
68 } else if (libType == "MODULE") {
69 if (type == cmStateEnums::INTERFACE_LIBRARY) {
70 status.SetError(
71 "INTERFACE library specified with conflicting MODULE type.");
72 return false;
74 ++s;
75 type = cmStateEnums::MODULE_LIBRARY;
76 haveSpecifiedType = true;
77 } else if (libType == "OBJECT") {
78 if (type == cmStateEnums::INTERFACE_LIBRARY) {
79 status.SetError(
80 "INTERFACE library specified with conflicting OBJECT type.");
81 return false;
83 ++s;
84 type = cmStateEnums::OBJECT_LIBRARY;
85 haveSpecifiedType = true;
86 } else if (libType == "UNKNOWN") {
87 if (type == cmStateEnums::INTERFACE_LIBRARY) {
88 status.SetError(
89 "INTERFACE library specified with conflicting UNKNOWN type.");
90 return false;
92 ++s;
93 type = cmStateEnums::UNKNOWN_LIBRARY;
94 haveSpecifiedType = true;
95 } else if (libType == "ALIAS") {
96 if (type == cmStateEnums::INTERFACE_LIBRARY) {
97 status.SetError(
98 "INTERFACE library specified with conflicting ALIAS type.");
99 return false;
101 ++s;
102 isAlias = true;
103 } else if (libType == "INTERFACE") {
104 if (haveSpecifiedType) {
105 status.SetError(
106 "INTERFACE library specified with conflicting/multiple types.");
107 return false;
109 if (isAlias) {
110 status.SetError(
111 "INTERFACE library specified with conflicting ALIAS type.");
112 return false;
114 ++s;
115 type = cmStateEnums::INTERFACE_LIBRARY;
116 haveSpecifiedType = true;
117 } else if (*s == "EXCLUDE_FROM_ALL") {
118 ++s;
119 excludeFromAll = true;
120 } else if (*s == "IMPORTED") {
121 ++s;
122 importTarget = true;
123 } else if (importTarget && *s == "GLOBAL") {
124 ++s;
125 importGlobal = true;
126 } else if (type == cmStateEnums::INTERFACE_LIBRARY && *s == "GLOBAL") {
127 status.SetError(
128 "GLOBAL option may only be used with IMPORTED libraries.");
129 return false;
130 } else {
131 break;
135 if (importTarget && !importGlobal) {
136 importGlobal = mf.IsImportedTargetGlobalScope();
139 if (type == cmStateEnums::INTERFACE_LIBRARY) {
140 if (importGlobal && !importTarget) {
141 status.SetError(
142 "INTERFACE library specified as GLOBAL, but not as IMPORTED.");
143 return false;
147 bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
148 !cmGlobalGenerator::IsReservedTarget(libName);
150 if (nameOk && !importTarget && !isAlias) {
151 nameOk = libName.find(':') == std::string::npos;
153 if (!nameOk && !mf.CheckCMP0037(libName, type)) {
154 return false;
157 if (isAlias) {
158 if (!cmGeneratorExpression::IsValidTargetName(libName)) {
159 status.SetError("Invalid name for ALIAS: " + libName);
160 return false;
162 if (excludeFromAll) {
163 status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
164 return false;
166 if (importTarget || importGlobal) {
167 status.SetError("IMPORTED with ALIAS is not allowed.");
168 return false;
170 if (args.size() != 3) {
171 status.SetError("ALIAS requires exactly one target argument.");
172 return false;
175 if (mf.GetPolicyStatus(cmPolicies::CMP0107) == cmPolicies::NEW) {
176 // Make sure the target does not already exist.
177 if (mf.FindTargetToUse(libName)) {
178 status.SetError(cmStrCat(
179 "cannot create ALIAS target \"", libName,
180 "\" because another target with the same name already exists."));
181 return false;
185 std::string const& aliasedName = *s;
186 if (mf.IsAlias(aliasedName)) {
187 status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
188 "\" because target \"", aliasedName,
189 "\" is itself an ALIAS."));
190 return false;
192 cmTarget* aliasedTarget = mf.FindTargetToUse(aliasedName, true);
193 if (!aliasedTarget) {
194 status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
195 "\" because target \"", aliasedName,
196 "\" does not already exist."));
197 return false;
199 cmStateEnums::TargetType aliasedType = aliasedTarget->GetType();
200 if (aliasedType != cmStateEnums::SHARED_LIBRARY &&
201 aliasedType != cmStateEnums::STATIC_LIBRARY &&
202 aliasedType != cmStateEnums::MODULE_LIBRARY &&
203 aliasedType != cmStateEnums::OBJECT_LIBRARY &&
204 aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
205 !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
206 aliasedTarget->IsImported())) {
207 status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
208 "\" because target \"", aliasedName,
209 "\" is not a library."));
210 return false;
212 mf.AddAlias(libName, aliasedName,
213 !aliasedTarget->IsImported() ||
214 aliasedTarget->IsImportedGloballyVisible());
215 return true;
218 if (importTarget && excludeFromAll) {
219 status.SetError("excludeFromAll with IMPORTED target makes no sense.");
220 return false;
223 /* ideally we should check whether for the linker language of the target
224 CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
225 STATIC. But at this point we know only the name of the target, but not
226 yet its linker language. */
227 if ((type == cmStateEnums::SHARED_LIBRARY ||
228 type == cmStateEnums::MODULE_LIBRARY) &&
229 !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
230 switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0164)) {
231 case cmPolicies::WARN:
232 mf.IssueMessage(
233 MessageType::AUTHOR_WARNING,
234 cmStrCat(
235 "ADD_LIBRARY called with ",
236 (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
237 " option but the target platform does not support dynamic "
238 "linking. ",
239 "Building a STATIC library instead. This may lead to problems."));
240 CM_FALLTHROUGH;
241 case cmPolicies::OLD:
242 type = cmStateEnums::STATIC_LIBRARY;
243 break;
244 case cmPolicies::NEW:
245 case cmPolicies::REQUIRED_IF_USED:
246 case cmPolicies::REQUIRED_ALWAYS:
247 mf.IssueMessage(
248 MessageType::FATAL_ERROR,
249 cmStrCat(
250 "ADD_LIBRARY called with ",
251 (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
252 " option but the target platform does not support dynamic "
253 "linking."));
254 cmSystemTools::SetFatalErrorOccurred();
255 return false;
256 default:
257 break;
261 // Handle imported target creation.
262 if (importTarget) {
263 // The IMPORTED signature requires a type to be specified explicitly.
264 if (!haveSpecifiedType) {
265 status.SetError("called with IMPORTED argument but no library type.");
266 return false;
268 if (type == cmStateEnums::INTERFACE_LIBRARY) {
269 if (!cmGeneratorExpression::IsValidTargetName(libName)) {
270 status.SetError(cmStrCat(
271 "Invalid name for IMPORTED INTERFACE library target: ", libName));
272 return false;
276 // Make sure the target does not already exist.
277 if (mf.FindTargetToUse(libName)) {
278 status.SetError(cmStrCat(
279 "cannot create imported target \"", libName,
280 "\" because another target with the same name already exists."));
281 return false;
284 // Create the imported target.
285 mf.AddImportedTarget(libName, type, importGlobal);
286 return true;
289 // A non-imported target may not have UNKNOWN type.
290 if (type == cmStateEnums::UNKNOWN_LIBRARY) {
291 mf.IssueMessage(
292 MessageType::FATAL_ERROR,
293 "The UNKNOWN library type may be used only for IMPORTED libraries.");
294 return true;
297 // Enforce name uniqueness.
299 std::string msg;
300 if (!mf.EnforceUniqueName(libName, msg)) {
301 status.SetError(msg);
302 return false;
306 if (type == cmStateEnums::INTERFACE_LIBRARY) {
307 if (!cmGeneratorExpression::IsValidTargetName(libName) ||
308 libName.find("::") != std::string::npos) {
309 status.SetError(
310 cmStrCat("Invalid name for INTERFACE library target: ", libName));
311 return false;
315 std::vector<std::string> srcs(s, args.end());
316 mf.AddLibrary(libName, type, srcs, excludeFromAll);
318 return true;