cmAddLibraryCommand.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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"
  4. #include <cmext/algorithm>
  5. #include "cmExecutionStatus.h"
  6. #include "cmGeneratorExpression.h"
  7. #include "cmGlobalGenerator.h"
  8. #include "cmMakefile.h"
  9. #include "cmMessageType.h"
  10. #include "cmState.h"
  11. #include "cmStateTypes.h"
  12. #include "cmStringAlgorithms.h"
  13. #include "cmTarget.h"
  14. bool cmAddLibraryCommand(std::vector<std::string> const& args,
  15. cmExecutionStatus& status)
  16. {
  17. if (args.empty()) {
  18. status.SetError("called with incorrect number of arguments");
  19. return false;
  20. }
  21. cmMakefile& mf = status.GetMakefile();
  22. // Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
  23. // otherwise it defaults to static library.
  24. cmStateEnums::TargetType type = cmStateEnums::SHARED_LIBRARY;
  25. if (cmIsOff(mf.GetDefinition("BUILD_SHARED_LIBS"))) {
  26. type = cmStateEnums::STATIC_LIBRARY;
  27. }
  28. bool excludeFromAll = false;
  29. bool importTarget = false;
  30. bool importGlobal = false;
  31. auto s = args.begin();
  32. std::string const& libName = *s;
  33. ++s;
  34. // If the second argument is "SHARED" or "STATIC", then it controls
  35. // the type of library. Otherwise, it is treated as a source or
  36. // source list name. There may be two keyword arguments, check for them
  37. bool haveSpecifiedType = false;
  38. bool isAlias = false;
  39. while (s != args.end()) {
  40. std::string libType = *s;
  41. if (libType == "STATIC") {
  42. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  43. status.SetError(
  44. "INTERFACE library specified with conflicting STATIC type.");
  45. return false;
  46. }
  47. ++s;
  48. type = cmStateEnums::STATIC_LIBRARY;
  49. haveSpecifiedType = true;
  50. } else if (libType == "SHARED") {
  51. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  52. status.SetError(
  53. "INTERFACE library specified with conflicting SHARED type.");
  54. return false;
  55. }
  56. ++s;
  57. type = cmStateEnums::SHARED_LIBRARY;
  58. haveSpecifiedType = true;
  59. } else if (libType == "MODULE") {
  60. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  61. status.SetError(
  62. "INTERFACE library specified with conflicting MODULE type.");
  63. return false;
  64. }
  65. ++s;
  66. type = cmStateEnums::MODULE_LIBRARY;
  67. haveSpecifiedType = true;
  68. } else if (libType == "OBJECT") {
  69. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  70. status.SetError(
  71. "INTERFACE library specified with conflicting OBJECT type.");
  72. return false;
  73. }
  74. ++s;
  75. type = cmStateEnums::OBJECT_LIBRARY;
  76. haveSpecifiedType = true;
  77. } else if (libType == "UNKNOWN") {
  78. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  79. status.SetError(
  80. "INTERFACE library specified with conflicting UNKNOWN type.");
  81. return false;
  82. }
  83. ++s;
  84. type = cmStateEnums::UNKNOWN_LIBRARY;
  85. haveSpecifiedType = true;
  86. } else if (libType == "ALIAS") {
  87. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  88. status.SetError(
  89. "INTERFACE library specified with conflicting ALIAS type.");
  90. return false;
  91. }
  92. ++s;
  93. isAlias = true;
  94. } else if (libType == "INTERFACE") {
  95. if (haveSpecifiedType) {
  96. status.SetError(
  97. "INTERFACE library specified with conflicting/multiple types.");
  98. return false;
  99. }
  100. if (isAlias) {
  101. status.SetError(
  102. "INTERFACE library specified with conflicting ALIAS type.");
  103. return false;
  104. }
  105. if (excludeFromAll) {
  106. status.SetError(
  107. "INTERFACE library may not be used with EXCLUDE_FROM_ALL.");
  108. return false;
  109. }
  110. ++s;
  111. type = cmStateEnums::INTERFACE_LIBRARY;
  112. haveSpecifiedType = true;
  113. } else if (*s == "EXCLUDE_FROM_ALL") {
  114. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  115. status.SetError(
  116. "INTERFACE library may not be used with EXCLUDE_FROM_ALL.");
  117. return false;
  118. }
  119. ++s;
  120. excludeFromAll = true;
  121. } else if (*s == "IMPORTED") {
  122. ++s;
  123. importTarget = true;
  124. } else if (importTarget && *s == "GLOBAL") {
  125. ++s;
  126. importGlobal = true;
  127. } else if (type == cmStateEnums::INTERFACE_LIBRARY && *s == "GLOBAL") {
  128. status.SetError(
  129. "GLOBAL option may only be used with IMPORTED libraries.");
  130. return false;
  131. } else {
  132. break;
  133. }
  134. }
  135. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  136. if (s != args.end()) {
  137. status.SetError("INTERFACE library requires no source arguments.");
  138. return false;
  139. }
  140. if (importGlobal && !importTarget) {
  141. status.SetError(
  142. "INTERFACE library specified as GLOBAL, but not as IMPORTED.");
  143. return false;
  144. }
  145. }
  146. bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) &&
  147. !cmGlobalGenerator::IsReservedTarget(libName);
  148. if (nameOk && !importTarget && !isAlias) {
  149. nameOk = libName.find(':') == std::string::npos;
  150. }
  151. if (!nameOk && !mf.CheckCMP0037(libName, type)) {
  152. return false;
  153. }
  154. if (isAlias) {
  155. if (!cmGeneratorExpression::IsValidTargetName(libName)) {
  156. status.SetError("Invalid name for ALIAS: " + libName);
  157. return false;
  158. }
  159. if (excludeFromAll) {
  160. status.SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
  161. return false;
  162. }
  163. if (importTarget || importGlobal) {
  164. status.SetError("IMPORTED with ALIAS is not allowed.");
  165. return false;
  166. }
  167. if (args.size() != 3) {
  168. status.SetError("ALIAS requires exactly one target argument.");
  169. return false;
  170. }
  171. std::string const& aliasedName = *s;
  172. if (mf.IsAlias(aliasedName)) {
  173. status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
  174. "\" because target \"", aliasedName,
  175. "\" is itself an ALIAS."));
  176. return false;
  177. }
  178. cmTarget* aliasedTarget = mf.FindTargetToUse(aliasedName, true);
  179. if (!aliasedTarget) {
  180. status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
  181. "\" because target \"", aliasedName,
  182. "\" does not already exist."));
  183. return false;
  184. }
  185. cmStateEnums::TargetType aliasedType = aliasedTarget->GetType();
  186. if (aliasedType != cmStateEnums::SHARED_LIBRARY &&
  187. aliasedType != cmStateEnums::STATIC_LIBRARY &&
  188. aliasedType != cmStateEnums::MODULE_LIBRARY &&
  189. aliasedType != cmStateEnums::OBJECT_LIBRARY &&
  190. aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
  191. !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
  192. aliasedTarget->IsImported())) {
  193. status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
  194. "\" because target \"", aliasedName,
  195. "\" is not a library."));
  196. return false;
  197. }
  198. if (aliasedTarget->IsImported() &&
  199. !aliasedTarget->IsImportedGloballyVisible()) {
  200. status.SetError(cmStrCat("cannot create ALIAS target \"", libName,
  201. "\" because target \"", aliasedName,
  202. "\" is imported but not globally visible."));
  203. return false;
  204. }
  205. mf.AddAlias(libName, aliasedName);
  206. return true;
  207. }
  208. if (importTarget && excludeFromAll) {
  209. status.SetError("excludeFromAll with IMPORTED target makes no sense.");
  210. return false;
  211. }
  212. /* ideally we should check whether for the linker language of the target
  213. CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
  214. STATIC. But at this point we know only the name of the target, but not
  215. yet its linker language. */
  216. if ((type == cmStateEnums::SHARED_LIBRARY ||
  217. type == cmStateEnums::MODULE_LIBRARY) &&
  218. !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
  219. mf.IssueMessage(
  220. MessageType::AUTHOR_WARNING,
  221. cmStrCat(
  222. "ADD_LIBRARY called with ",
  223. (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE"),
  224. " option but the target platform does not support dynamic linking. ",
  225. "Building a STATIC library instead. This may lead to problems."));
  226. type = cmStateEnums::STATIC_LIBRARY;
  227. }
  228. // Handle imported target creation.
  229. if (importTarget) {
  230. // The IMPORTED signature requires a type to be specified explicitly.
  231. if (!haveSpecifiedType) {
  232. status.SetError("called with IMPORTED argument but no library type.");
  233. return false;
  234. }
  235. if (type == cmStateEnums::OBJECT_LIBRARY) {
  236. std::string reason;
  237. if (!mf.GetGlobalGenerator()->HasKnownObjectFileLocation(&reason)) {
  238. mf.IssueMessage(
  239. MessageType::FATAL_ERROR,
  240. "The OBJECT library type may not be used for IMPORTED libraries" +
  241. reason + ".");
  242. return true;
  243. }
  244. }
  245. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  246. if (!cmGeneratorExpression::IsValidTargetName(libName)) {
  247. status.SetError(cmStrCat(
  248. "Invalid name for IMPORTED INTERFACE library target: ", libName));
  249. return false;
  250. }
  251. }
  252. // Make sure the target does not already exist.
  253. if (mf.FindTargetToUse(libName)) {
  254. status.SetError(cmStrCat(
  255. "cannot create imported target \"", libName,
  256. "\" because another target with the same name already exists."));
  257. return false;
  258. }
  259. // Create the imported target.
  260. mf.AddImportedTarget(libName, type, importGlobal);
  261. return true;
  262. }
  263. // A non-imported target may not have UNKNOWN type.
  264. if (type == cmStateEnums::UNKNOWN_LIBRARY) {
  265. mf.IssueMessage(
  266. MessageType::FATAL_ERROR,
  267. "The UNKNOWN library type may be used only for IMPORTED libraries.");
  268. return true;
  269. }
  270. // Enforce name uniqueness.
  271. {
  272. std::string msg;
  273. if (!mf.EnforceUniqueName(libName, msg)) {
  274. status.SetError(msg);
  275. return false;
  276. }
  277. }
  278. std::vector<std::string> srclists;
  279. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  280. if (!cmGeneratorExpression::IsValidTargetName(libName) ||
  281. libName.find("::") != std::string::npos) {
  282. status.SetError(
  283. cmStrCat("Invalid name for INTERFACE library target: ", libName));
  284. return false;
  285. }
  286. mf.AddLibrary(libName, type, srclists, excludeFromAll);
  287. return true;
  288. }
  289. cm::append(srclists, s, args.end());
  290. mf.AddLibrary(libName, type, srclists, excludeFromAll);
  291. return true;
  292. }