cmTargetPropertyComputer.cxx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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 "cmTargetPropertyComputer.h"
  4. #include "cmGeneratorTarget.h"
  5. #include "cmGlobalGenerator.h"
  6. #include "cmMakefile.h"
  7. #include "cmMessenger.h"
  8. #include "cmSourceFile.h"
  9. #include "cmSourceFileLocation.h"
  10. #include "cmSystemTools.h"
  11. #include "cmTarget.h"
  12. #if defined(CMake_HAVE_CXX_UNORDERED_SET)
  13. #include <unordered_set>
  14. #define UNORDERED_SET std::unordered_set
  15. #elif defined(CMAKE_BUILD_WITH_CMAKE)
  16. #include <cmsys/hash_set.hxx>
  17. #define UNORDERED_SET cmsys::hash_set
  18. #else
  19. #define UNORDERED_SET std::set
  20. #endif
  21. bool cmTargetPropertyComputer::HandleLocationPropertyPolicy(
  22. std::string const& tgtName, cmMessenger* messenger,
  23. cmListFileBacktrace const& context)
  24. {
  25. std::ostringstream e;
  26. const char* modal = CM_NULLPTR;
  27. cmake::MessageType messageType = cmake::AUTHOR_WARNING;
  28. switch (context.GetBottom().GetPolicy(cmPolicies::CMP0026)) {
  29. case cmPolicies::WARN:
  30. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n";
  31. modal = "should";
  32. case cmPolicies::OLD:
  33. break;
  34. case cmPolicies::REQUIRED_ALWAYS:
  35. case cmPolicies::REQUIRED_IF_USED:
  36. case cmPolicies::NEW:
  37. modal = "may";
  38. messageType = cmake::FATAL_ERROR;
  39. }
  40. if (modal) {
  41. e << "The LOCATION property " << modal << " not be read from target \""
  42. << tgtName
  43. << "\". Use the target name directly with "
  44. "add_custom_command, or use the generator expression $<TARGET_FILE>, "
  45. "as appropriate.\n";
  46. messenger->IssueMessage(messageType, e.str(), context);
  47. }
  48. return messageType != cmake::FATAL_ERROR;
  49. }
  50. const char* cmTargetPropertyComputer::ComputeLocationForBuild(
  51. cmTarget const* tgt)
  52. {
  53. static std::string loc;
  54. if (tgt->IsImported()) {
  55. loc = tgt->ImportedGetFullPath("", false);
  56. return loc.c_str();
  57. }
  58. cmGlobalGenerator* gg = tgt->GetMakefile()->GetGlobalGenerator();
  59. if (!gg->GetConfigureDoneCMP0026()) {
  60. gg->CreateGenerationObjects();
  61. }
  62. cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
  63. loc = gt->GetLocationForBuild();
  64. return loc.c_str();
  65. }
  66. const char* cmTargetPropertyComputer::ComputeLocation(
  67. cmTarget const* tgt, std::string const& config)
  68. {
  69. static std::string loc;
  70. if (tgt->IsImported()) {
  71. loc = tgt->ImportedGetFullPath(config, false);
  72. return loc.c_str();
  73. }
  74. cmGlobalGenerator* gg = tgt->GetMakefile()->GetGlobalGenerator();
  75. if (!gg->GetConfigureDoneCMP0026()) {
  76. gg->CreateGenerationObjects();
  77. }
  78. cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
  79. loc = gt->GetFullPath(config, false);
  80. return loc.c_str();
  81. }
  82. const char* cmTargetPropertyComputer::GetProperty(
  83. cmTarget const* tgt, const std::string& prop, cmMessenger* messenger,
  84. cmListFileBacktrace const& context)
  85. {
  86. if (const char* loc = GetLocation(tgt, prop, messenger, context)) {
  87. return loc;
  88. }
  89. if (cmSystemTools::GetFatalErrorOccured()) {
  90. return CM_NULLPTR;
  91. }
  92. if (prop == "SOURCES") {
  93. return GetSources(tgt, messenger, context);
  94. }
  95. return CM_NULLPTR;
  96. }
  97. const char* cmTargetPropertyComputer::GetLocation(
  98. cmTarget const* tgt, const std::string& prop, cmMessenger* messenger,
  99. cmListFileBacktrace const& context)
  100. {
  101. // Watch for special "computed" properties that are dependent on
  102. // other properties or variables. Always recompute them.
  103. if (tgt->GetType() == cmState::EXECUTABLE ||
  104. tgt->GetType() == cmState::STATIC_LIBRARY ||
  105. tgt->GetType() == cmState::SHARED_LIBRARY ||
  106. tgt->GetType() == cmState::MODULE_LIBRARY ||
  107. tgt->GetType() == cmState::UNKNOWN_LIBRARY) {
  108. static const std::string propLOCATION = "LOCATION";
  109. if (prop == propLOCATION) {
  110. if (!tgt->IsImported() &&
  111. !HandleLocationPropertyPolicy(tgt->GetName(), messenger, context)) {
  112. return CM_NULLPTR;
  113. }
  114. return ComputeLocationForBuild(tgt);
  115. }
  116. // Support "LOCATION_<CONFIG>".
  117. else if (cmHasLiteralPrefix(prop, "LOCATION_")) {
  118. if (!tgt->IsImported() &&
  119. !HandleLocationPropertyPolicy(tgt->GetName(), messenger, context)) {
  120. return CM_NULLPTR;
  121. }
  122. const char* configName = prop.c_str() + 9;
  123. return ComputeLocation(tgt, configName);
  124. }
  125. // Support "<CONFIG>_LOCATION".
  126. else if (cmHasLiteralSuffix(prop, "_LOCATION") &&
  127. !cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
  128. std::string configName(prop.c_str(), prop.size() - 9);
  129. if (configName != "IMPORTED") {
  130. if (!tgt->IsImported() &&
  131. !HandleLocationPropertyPolicy(tgt->GetName(), messenger,
  132. context)) {
  133. return CM_NULLPTR;
  134. }
  135. return ComputeLocation(tgt, configName);
  136. }
  137. }
  138. }
  139. return CM_NULLPTR;
  140. }
  141. const char* cmTargetPropertyComputer::GetSources(
  142. cmTarget const* tgt, cmMessenger* messenger,
  143. cmListFileBacktrace const& context)
  144. {
  145. cmStringRange entries = tgt->GetSourceEntries();
  146. if (entries.empty()) {
  147. return CM_NULLPTR;
  148. }
  149. std::ostringstream ss;
  150. const char* sep = "";
  151. for (std::vector<std::string>::const_iterator i = entries.begin();
  152. i != entries.end(); ++i) {
  153. std::string const& entry = *i;
  154. std::vector<std::string> files;
  155. cmSystemTools::ExpandListArgument(entry, files);
  156. for (std::vector<std::string>::const_iterator li = files.begin();
  157. li != files.end(); ++li) {
  158. if (cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
  159. (*li)[li->size() - 1] == '>') {
  160. std::string objLibName = li->substr(17, li->size() - 18);
  161. if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
  162. ss << sep;
  163. sep = ";";
  164. ss << *li;
  165. continue;
  166. }
  167. bool addContent = false;
  168. bool noMessage = true;
  169. std::ostringstream e;
  170. cmake::MessageType messageType = cmake::AUTHOR_WARNING;
  171. switch (context.GetBottom().GetPolicy(cmPolicies::CMP0051)) {
  172. case cmPolicies::WARN:
  173. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
  174. noMessage = false;
  175. case cmPolicies::OLD:
  176. break;
  177. case cmPolicies::REQUIRED_ALWAYS:
  178. case cmPolicies::REQUIRED_IF_USED:
  179. case cmPolicies::NEW:
  180. addContent = true;
  181. }
  182. if (!noMessage) {
  183. e << "Target \"" << tgt->GetName()
  184. << "\" contains "
  185. "$<TARGET_OBJECTS> generator expression in its sources "
  186. "list. "
  187. "This content was not previously part of the SOURCES "
  188. "property "
  189. "when that property was read at configure time. Code "
  190. "reading "
  191. "that property needs to be adapted to ignore the generator "
  192. "expression using the string(GENEX_STRIP) command.";
  193. messenger->IssueMessage(messageType, e.str(), context);
  194. }
  195. if (addContent) {
  196. ss << sep;
  197. sep = ";";
  198. ss << *li;
  199. }
  200. } else if (cmGeneratorExpression::Find(*li) == std::string::npos) {
  201. ss << sep;
  202. sep = ";";
  203. ss << *li;
  204. } else {
  205. cmSourceFile* sf = tgt->GetMakefile()->GetOrCreateSource(*li);
  206. // Construct what is known about this source file location.
  207. cmSourceFileLocation const& location = sf->GetLocation();
  208. std::string sname = location.GetDirectory();
  209. if (!sname.empty()) {
  210. sname += "/";
  211. }
  212. sname += location.GetName();
  213. ss << sep;
  214. sep = ";";
  215. // Append this list entry.
  216. ss << sname;
  217. }
  218. }
  219. }
  220. static std::string srcs;
  221. srcs = ss.str();
  222. return srcs.c_str();
  223. }
  224. bool cmTargetPropertyComputer::WhiteListedInterfaceProperty(
  225. const std::string& prop)
  226. {
  227. if (cmHasLiteralPrefix(prop, "INTERFACE_")) {
  228. return true;
  229. }
  230. static UNORDERED_SET<std::string> builtIns;
  231. if (builtIns.empty()) {
  232. builtIns.insert("COMPATIBLE_INTERFACE_BOOL");
  233. builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MAX");
  234. builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
  235. builtIns.insert("COMPATIBLE_INTERFACE_STRING");
  236. builtIns.insert("EXPORT_NAME");
  237. builtIns.insert("IMPORTED");
  238. builtIns.insert("NAME");
  239. builtIns.insert("TYPE");
  240. }
  241. if (builtIns.count(prop)) {
  242. return true;
  243. }
  244. if (cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_")) {
  245. return true;
  246. }
  247. return false;
  248. }