cmAddLibraryCommand.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 "cmGeneratorExpression.h"
  6. #include "cmGlobalGenerator.h"
  7. #include "cmMakefile.h"
  8. #include "cmPolicies.h"
  9. #include "cmState.h"
  10. #include "cmStateTypes.h"
  11. #include "cmSystemTools.h"
  12. #include "cmTarget.h"
  13. #include "cmake.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) {
  168. cmake::MessageType messageType = cmake::AUTHOR_WARNING;
  169. std::ostringstream e;
  170. bool issueMessage = false;
  171. switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) {
  172. case cmPolicies::WARN:
  173. if (type != cmStateEnums::INTERFACE_LIBRARY) {
  174. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
  175. issueMessage = true;
  176. }
  177. case cmPolicies::OLD:
  178. break;
  179. case cmPolicies::NEW:
  180. case cmPolicies::REQUIRED_IF_USED:
  181. case cmPolicies::REQUIRED_ALWAYS:
  182. issueMessage = true;
  183. messageType = cmake::FATAL_ERROR;
  184. }
  185. if (issueMessage) {
  186. e << "The target name \"" << libName
  187. << "\" is reserved or not valid for certain "
  188. "CMake features, such as generator expressions, and may result "
  189. "in undefined behavior.";
  190. this->Makefile->IssueMessage(messageType, e.str());
  191. if (messageType == cmake::FATAL_ERROR) {
  192. return false;
  193. }
  194. }
  195. }
  196. if (isAlias) {
  197. if (!cmGeneratorExpression::IsValidTargetName(libName)) {
  198. this->SetError("Invalid name for ALIAS: " + libName);
  199. return false;
  200. }
  201. if (excludeFromAll) {
  202. this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
  203. return false;
  204. }
  205. if (importTarget || importGlobal) {
  206. this->SetError("IMPORTED with ALIAS is not allowed.");
  207. return false;
  208. }
  209. if (args.size() != 3) {
  210. std::ostringstream e;
  211. e << "ALIAS requires exactly one target argument.";
  212. this->SetError(e.str());
  213. return false;
  214. }
  215. const char* aliasedName = s->c_str();
  216. if (this->Makefile->IsAlias(aliasedName)) {
  217. std::ostringstream e;
  218. e << "cannot create ALIAS target \"" << libName << "\" because target \""
  219. << aliasedName << "\" is itself an ALIAS.";
  220. this->SetError(e.str());
  221. return false;
  222. }
  223. cmTarget* aliasedTarget =
  224. this->Makefile->FindTargetToUse(aliasedName, true);
  225. if (!aliasedTarget) {
  226. std::ostringstream e;
  227. e << "cannot create ALIAS target \"" << libName << "\" because target \""
  228. << aliasedName << "\" does not already "
  229. "exist.";
  230. this->SetError(e.str());
  231. return false;
  232. }
  233. cmStateEnums::TargetType aliasedType = aliasedTarget->GetType();
  234. if (aliasedType != cmStateEnums::SHARED_LIBRARY &&
  235. aliasedType != cmStateEnums::STATIC_LIBRARY &&
  236. aliasedType != cmStateEnums::MODULE_LIBRARY &&
  237. aliasedType != cmStateEnums::OBJECT_LIBRARY &&
  238. aliasedType != cmStateEnums::INTERFACE_LIBRARY) {
  239. std::ostringstream e;
  240. e << "cannot create ALIAS target \"" << libName << "\" because target \""
  241. << aliasedName << "\" is not a library.";
  242. this->SetError(e.str());
  243. return false;
  244. }
  245. this->Makefile->AddAlias(libName, aliasedName);
  246. return true;
  247. }
  248. if (importTarget && excludeFromAll) {
  249. this->SetError("excludeFromAll with IMPORTED target makes no sense.");
  250. return false;
  251. }
  252. /* ideally we should check whether for the linker language of the target
  253. CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
  254. STATIC. But at this point we know only the name of the target, but not
  255. yet its linker language. */
  256. if ((type == cmStateEnums::SHARED_LIBRARY ||
  257. type == cmStateEnums::MODULE_LIBRARY) &&
  258. !this->Makefile->GetState()->GetGlobalPropertyAsBool(
  259. "TARGET_SUPPORTS_SHARED_LIBS")) {
  260. std::ostringstream w;
  261. w << "ADD_LIBRARY called with "
  262. << (type == cmStateEnums::SHARED_LIBRARY ? "SHARED" : "MODULE")
  263. << " option but the target platform does not support dynamic linking. "
  264. "Building a STATIC library instead. This may lead to problems.";
  265. this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
  266. type = cmStateEnums::STATIC_LIBRARY;
  267. }
  268. // Handle imported target creation.
  269. if (importTarget) {
  270. // The IMPORTED signature requires a type to be specified explicitly.
  271. if (!haveSpecifiedType) {
  272. this->SetError("called with IMPORTED argument but no library type.");
  273. return false;
  274. }
  275. if (type == cmStateEnums::OBJECT_LIBRARY) {
  276. std::string reason;
  277. if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation(
  278. &reason)) {
  279. this->Makefile->IssueMessage(
  280. cmake::FATAL_ERROR,
  281. "The OBJECT library type may not be used for IMPORTED libraries" +
  282. reason + ".");
  283. return true;
  284. }
  285. }
  286. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  287. if (!cmGeneratorExpression::IsValidTargetName(libName)) {
  288. std::ostringstream e;
  289. e << "Invalid name for IMPORTED INTERFACE library target: " << libName;
  290. this->SetError(e.str());
  291. return false;
  292. }
  293. }
  294. // Make sure the target does not already exist.
  295. if (this->Makefile->FindTargetToUse(libName)) {
  296. std::ostringstream e;
  297. e << "cannot create imported target \"" << libName
  298. << "\" because another target with the same name already exists.";
  299. this->SetError(e.str());
  300. return false;
  301. }
  302. // Create the imported target.
  303. this->Makefile->AddImportedTarget(libName, type, importGlobal);
  304. return true;
  305. }
  306. // A non-imported target may not have UNKNOWN type.
  307. if (type == cmStateEnums::UNKNOWN_LIBRARY) {
  308. this->Makefile->IssueMessage(
  309. cmake::FATAL_ERROR,
  310. "The UNKNOWN library type may be used only for IMPORTED libraries.");
  311. return true;
  312. }
  313. // Enforce name uniqueness.
  314. {
  315. std::string msg;
  316. if (!this->Makefile->EnforceUniqueName(libName, msg)) {
  317. this->SetError(msg);
  318. return false;
  319. }
  320. }
  321. std::vector<std::string> srclists;
  322. if (type == cmStateEnums::INTERFACE_LIBRARY) {
  323. if (!cmGeneratorExpression::IsValidTargetName(libName) ||
  324. libName.find("::") != std::string::npos) {
  325. std::ostringstream e;
  326. e << "Invalid name for INTERFACE library target: " << libName;
  327. this->SetError(e.str());
  328. return false;
  329. }
  330. this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
  331. return true;
  332. }
  333. srclists.insert(srclists.end(), s, args.end());
  334. this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
  335. return true;
  336. }