diff options
Diffstat (limited to 'Source/cmAddLibraryCommand.cxx')
| -rw-r--r-- | Source/cmAddLibraryCommand.cxx | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx new file mode 100644 index 0000000..3e5d764 --- /dev/null +++ b/Source/cmAddLibraryCommand.cxx @@ -0,0 +1,324 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAddLibraryCommand.h" + +#include <cmext/algorithm> + +#include "cmExecutionStatus.h" +#include "cmGeneratorExpression.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmPolicies.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmTarget.h" + +bool cmAddLibraryCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.empty()) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + cmMakefile& mf = status.GetMakefile(); + // Library type defaults to value of BUILD_SHARED_LIBS, if it exists, + // otherwise it defaults to static library. + cmStateEnums::TargetType type = cmStateEnums::SHARED_LIBRARY; + if (cmIsOff(mf.GetDefinition("BUILD_SHARED_LIBS"))) { + type = cmStateEnums::STATIC_LIBRARY; + } + bool excludeFromAll = false; + bool importTarget = false; + bool importGlobal = false; + + auto s = args.begin(); + + std::string const& libName = *s; + + ++s; + + // If the second argument is "SHARED" or "STATIC", then it controls + // the type of library. Otherwise, it is treated as a source or + // source list name. There may be two keyword arguments, check for them + bool haveSpecifiedType = false; + bool isAlias = false; + while (s != args.end()) { + std::string libType = *s; + if (libType == "STATIC") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting STATIC type."); + return false; + } + ++s; + type = cmStateEnums::STATIC_LIBRARY; + haveSpecifiedType = true; + } else if (libType == "SHARED") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting SHARED type."); + return false; + } + ++s; + type = cmStateEnums::SHARED_LIBRARY; + haveSpecifiedType = true; + } else if (libType == "MODULE") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting MODULE type."); + return false; + } + ++s; + type = cmStateEnums::MODULE_LIBRARY; + haveSpecifiedType = true; + } else if (libType == "OBJECT") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting OBJECT type."); + return false; + } + ++s; + type = cmStateEnums::OBJECT_LIBRARY; + haveSpecifiedType = true; + } else if (libType == "UNKNOWN") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting UNKNOWN type."); + return false; + } + ++s; + type = cmStateEnums::UNKNOWN_LIBRARY; + haveSpecifiedType = true; + } else if (libType == "ALIAS") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library specified with conflicting ALIAS type."); + return false; + } + ++s; + isAlias = true; + } else if (libType == "INTERFACE") { + if (haveSpecifiedType) { + status.SetError( + "INTERFACE library specified with conflicting/multiple types."); + return false; + } + if (isAlias) { + status.SetError( + "INTERFACE library specified with conflicting ALIAS type."); + return false; + } + if (excludeFromAll) { + status.SetError( + "INTERFACE library may not be used with EXCLUDE_FROM_ALL."); + return false; + } + ++s; + type = cmStateEnums::INTERFACE_LIBRARY; + haveSpecifiedType = true; + } else if (*s == "EXCLUDE_FROM_ALL") { + if (type == cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "INTERFACE library may not be used with EXCLUDE_FROM_ALL."); + return false; + } + ++s; + excludeFromAll = true; + } else if (*s == "IMPORTED") { + ++s; + importTarget = true; + } else if (importTarget && *s == "GLOBAL") { + ++s; + importGlobal = true; + } else if (type == cmStateEnums::INTERFACE_LIBRARY && *s == "GLOBAL") { + status.SetError( + "GLOBAL option may only be used with IMPORTED libraries."); + return false; + } else { + break; + } + } + + if (type == cmStateEnums::INTERFACE_LIBRARY) { + if (s != args.end()) { + status.SetError("INTERFACE library requires no source arguments."); + return false; + } + if (importGlobal && !importTarget) { + status.SetError( + "INTERFACE library specified as GLOBAL, but not as IMPORTED."); + return false; + } + } + + bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) && + !cmGlobalGenerator::IsReservedTarget(libName); + + if (nameOk && !importTarget && !isAlias) { + nameOk = libName.find(':') == std::string::npos; + } + if (!nameOk && !mf.CheckCMP0037(libName, type)) { + return false; + } + + if (isAlias) { + if (!cmGeneratorExpression::IsValidTargetName(libName)) { + status.SetError("Invalid name for ALIAS: " + libName); + return false; + } + if (excludeFromAll) { + status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense."); + return false; + } + if (importTarget || importGlobal) { + status.SetError("IMPORTED with ALIAS is not allowed."); + return false; + } + if (args.size() != 3) { + status.SetError("ALIAS requires exactly one target argument."); + return false; + } + + if (mf.GetPolicyStatus(cmPolicies::CMP0107) == cmPolicies::NEW) { + // Make sure the target does not already exist. + if (mf.FindTargetToUse(libName)) { + status.SetError(cmStrCat( + "cannot create ALIAS target \"", libName, + "\" because another target with the same name already exists.")); + return false; + } + } + + std::string const& aliasedName = *s; + if (mf.IsAlias(aliasedName)) { + status.SetError(cmStrCat("cannot create ALIAS target \"", libName, + "\" because target \"", aliasedName, + "\" is itself an ALIAS.")); + return false; + } + cmTarget* aliasedTarget = mf.FindTargetToUse(aliasedName, true); + if (!aliasedTarget) { + status.SetError(cmStrCat("cannot create ALIAS target \"", libName, + "\" because target \"", aliasedName, + "\" does not already exist.")); + return false; + } + cmStateEnums::TargetType aliasedType = aliasedTarget->GetType(); + if (aliasedType != cmStateEnums::SHARED_LIBRARY && + aliasedType != cmStateEnums::STATIC_LIBRARY && + aliasedType != cmStateEnums::MODULE_LIBRARY && + aliasedType != cmStateEnums::OBJECT_LIBRARY && + aliasedType != cmStateEnums::INTERFACE_LIBRARY && + !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY && + aliasedTarget->IsImported())) { + status.SetError(cmStrCat("cannot create ALIAS target \"", libName, + "\" because target \"", aliasedName, + "\" is not a library.")); + return false; + } + mf.AddAlias(libName, aliasedName, + !aliasedTarget->IsImported() || + aliasedTarget->IsImportedGloballyVisible()); + return true; + } + + if (importTarget && excludeFromAll) { + status.SetError("excludeFromAll with IMPORTED target makes no sense."); + return false; + } + + /* ideally we should check whether for the linker language of the target + CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to + STATIC. But at this point we know only the name of the target, but not + yet its linker language. */ + if ((type == cmStateEnums::SHARED_LIBRARY || + type == cmStateEnums::MODULE_LIBRARY) && + !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat( + "ADD_LIBRARY called with ", + (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"), + " option but the target platform does not support dynamic linking. ", + "Building a STATIC library instead. This may lead to problems.")); + type = cmStateEnums::STATIC_LIBRARY; + } + + // Handle imported target creation. + if (importTarget) { + // The IMPORTED signature requires a type to be specified explicitly. + if (!haveSpecifiedType) { + status.SetError("called with IMPORTED argument but no library type."); + return false; + } + if (type == cmStateEnums::OBJECT_LIBRARY) { + std::string reason; + if (!mf.GetGlobalGenerator()->HasKnownObjectFileLocation(&reason)) { + mf.IssueMessage( + MessageType::FATAL_ERROR, + "The OBJECT library type may not be used for IMPORTED libraries" + + reason + "."); + return true; + } + } + if (type == cmStateEnums::INTERFACE_LIBRARY) { + if (!cmGeneratorExpression::IsValidTargetName(libName)) { + status.SetError(cmStrCat( + "Invalid name for IMPORTED INTERFACE library target: ", libName)); + return false; + } + } + + // Make sure the target does not already exist. + if (mf.FindTargetToUse(libName)) { + status.SetError(cmStrCat( + "cannot create imported target \"", libName, + "\" because another target with the same name already exists.")); + return false; + } + + // Create the imported target. + mf.AddImportedTarget(libName, type, importGlobal); + return true; + } + + // A non-imported target may not have UNKNOWN type. + if (type == cmStateEnums::UNKNOWN_LIBRARY) { + mf.IssueMessage( + MessageType::FATAL_ERROR, + "The UNKNOWN library type may be used only for IMPORTED libraries."); + return true; + } + + // Enforce name uniqueness. + { + std::string msg; + if (!mf.EnforceUniqueName(libName, msg)) { + status.SetError(msg); + return false; + } + } + + std::vector<std::string> srclists; + + if (type == cmStateEnums::INTERFACE_LIBRARY) { + if (!cmGeneratorExpression::IsValidTargetName(libName) || + libName.find("::") != std::string::npos) { + status.SetError( + cmStrCat("Invalid name for INTERFACE library target: ", libName)); + return false; + } + + mf.AddLibrary(libName, type, srclists, excludeFromAll); + return true; + } + + cm::append(srclists, s, args.end()); + + mf.AddLibrary(libName, type, srclists, excludeFromAll); + + return true; +} |
