cmAddLibraryCommand.cxx 11 KB

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