cmAddLibraryCommand.cxx 12 KB

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