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"
12 #include "cmStateTypes.h"
13 #include "cmStringAlgorithms.h"
14 #include "cmSystemTools.h"
18 bool cmAddLibraryCommand(std::vector
<std::string
> const& args
,
19 cmExecutionStatus
& status
)
22 status
.SetError("called with incorrect number of arguments");
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
;
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;
48 while (s
!= args
.end()) {
49 std::string libType
= *s
;
50 if (libType
== "STATIC") {
51 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
53 "INTERFACE library specified with conflicting STATIC type.");
57 type
= cmStateEnums::STATIC_LIBRARY
;
58 haveSpecifiedType
= true;
59 } else if (libType
== "SHARED") {
60 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
62 "INTERFACE library specified with conflicting SHARED type.");
66 type
= cmStateEnums::SHARED_LIBRARY
;
67 haveSpecifiedType
= true;
68 } else if (libType
== "MODULE") {
69 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
71 "INTERFACE library specified with conflicting MODULE type.");
75 type
= cmStateEnums::MODULE_LIBRARY
;
76 haveSpecifiedType
= true;
77 } else if (libType
== "OBJECT") {
78 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
80 "INTERFACE library specified with conflicting OBJECT type.");
84 type
= cmStateEnums::OBJECT_LIBRARY
;
85 haveSpecifiedType
= true;
86 } else if (libType
== "UNKNOWN") {
87 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
89 "INTERFACE library specified with conflicting UNKNOWN type.");
93 type
= cmStateEnums::UNKNOWN_LIBRARY
;
94 haveSpecifiedType
= true;
95 } else if (libType
== "ALIAS") {
96 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
98 "INTERFACE library specified with conflicting ALIAS type.");
103 } else if (libType
== "INTERFACE") {
104 if (haveSpecifiedType
) {
106 "INTERFACE library specified with conflicting/multiple types.");
111 "INTERFACE library specified with conflicting ALIAS type.");
115 type
= cmStateEnums::INTERFACE_LIBRARY
;
116 haveSpecifiedType
= true;
117 } else if (*s
== "EXCLUDE_FROM_ALL") {
119 excludeFromAll
= true;
120 } else if (*s
== "IMPORTED") {
123 } else if (importTarget
&& *s
== "GLOBAL") {
126 } else if (type
== cmStateEnums::INTERFACE_LIBRARY
&& *s
== "GLOBAL") {
128 "GLOBAL option may only be used with IMPORTED libraries.");
135 if (importTarget
&& !importGlobal
) {
136 importGlobal
= mf
.IsImportedTargetGlobalScope();
139 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
140 if (importGlobal
&& !importTarget
) {
142 "INTERFACE library specified as GLOBAL, but not as IMPORTED.");
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
)) {
158 if (!cmGeneratorExpression::IsValidTargetName(libName
)) {
159 status
.SetError("Invalid name for ALIAS: " + libName
);
162 if (excludeFromAll
) {
163 status
.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
166 if (importTarget
|| importGlobal
) {
167 status
.SetError("IMPORTED with ALIAS is not allowed.");
170 if (args
.size() != 3) {
171 status
.SetError("ALIAS requires exactly one target argument.");
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."));
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."));
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."));
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."));
212 mf
.AddAlias(libName
, aliasedName
,
213 !aliasedTarget
->IsImported() ||
214 aliasedTarget
->IsImportedGloballyVisible());
218 if (importTarget
&& excludeFromAll
) {
219 status
.SetError("excludeFromAll with IMPORTED target makes no sense.");
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
:
233 MessageType::AUTHOR_WARNING
,
235 "ADD_LIBRARY called with ",
236 (type
== cmStateEnums::SHARED_LIBRARY
? "SHARED" : "MODULE"),
237 " option but the target platform does not support dynamic "
239 "Building a STATIC library instead. This may lead to problems."));
241 case cmPolicies::OLD
:
242 type
= cmStateEnums::STATIC_LIBRARY
;
244 case cmPolicies::NEW
:
245 case cmPolicies::REQUIRED_IF_USED
:
246 case cmPolicies::REQUIRED_ALWAYS
:
248 MessageType::FATAL_ERROR
,
250 "ADD_LIBRARY called with ",
251 (type
== cmStateEnums::SHARED_LIBRARY
? "SHARED" : "MODULE"),
252 " option but the target platform does not support dynamic "
254 cmSystemTools::SetFatalErrorOccurred();
261 // Handle imported target creation.
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.");
268 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
269 if (!cmGeneratorExpression::IsValidTargetName(libName
)) {
270 status
.SetError(cmStrCat(
271 "Invalid name for IMPORTED INTERFACE library target: ", libName
));
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."));
284 // Create the imported target.
285 mf
.AddImportedTarget(libName
, type
, importGlobal
);
289 // A non-imported target may not have UNKNOWN type.
290 if (type
== cmStateEnums::UNKNOWN_LIBRARY
) {
292 MessageType::FATAL_ERROR
,
293 "The UNKNOWN library type may be used only for IMPORTED libraries.");
297 // Enforce name uniqueness.
300 if (!mf
.EnforceUniqueName(libName
, msg
)) {
301 status
.SetError(msg
);
306 if (type
== cmStateEnums::INTERFACE_LIBRARY
) {
307 if (!cmGeneratorExpression::IsValidTargetName(libName
) ||
308 libName
.find("::") != std::string::npos
) {
310 cmStrCat("Invalid name for INTERFACE library target: ", libName
));
315 std::vector
<std::string
> srcs(s
, args
.end());
316 mf
.AddLibrary(libName
, type
, srcs
, excludeFromAll
);