/* 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 "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 "cmSystemTools.h" #include "cmTarget.h" #include "cmValue.h" bool cmAddLibraryCommand(std::vector 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 (mf.GetDefinition("BUILD_SHARED_LIBS").IsOff()) { 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; } ++s; type = cmStateEnums::INTERFACE_LIBRARY; haveSpecifiedType = true; } else if (*s == "EXCLUDE_FROM_ALL") { ++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 (importTarget && !importGlobal) { importGlobal = mf.IsImportedTargetGlobalScope(); } if (type == cmStateEnums::INTERFACE_LIBRARY) { 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")) { switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0164)) { case cmPolicies::WARN: 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.")); CM_FALLTHROUGH; case cmPolicies::OLD: type = cmStateEnums::STATIC_LIBRARY; break; case cmPolicies::NEW: case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: mf.IssueMessage( MessageType::FATAL_ERROR, cmStrCat( "ADD_LIBRARY called with ", (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"), " option but the target platform does not support dynamic " "linking.")); cmSystemTools::SetFatalErrorOccurred(); return false; default: break; } } // 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::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; } } 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; } } std::vector srcs(s, args.end()); mf.AddLibrary(libName, type, srcs, excludeFromAll); return true; }