cmRulePlaceholderExpander.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 "cmRulePlaceholderExpander.h"
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include <utility>
  7. #include "cmOutputConverter.h"
  8. #include "cmSystemTools.h"
  9. cmRulePlaceholderExpander::cmRulePlaceholderExpander(
  10. std::map<std::string, std::string> compilers,
  11. std::map<std::string, std::string> variableMappings,
  12. std::string compilerSysroot, std::string linkerSysroot)
  13. : Compilers(std::move(compilers))
  14. , VariableMappings(std::move(variableMappings))
  15. , CompilerSysroot(std::move(compilerSysroot))
  16. , LinkerSysroot(std::move(linkerSysroot))
  17. {
  18. }
  19. cmRulePlaceholderExpander::RuleVariables::RuleVariables()
  20. {
  21. memset(this, 0, sizeof(*this));
  22. }
  23. std::string cmRulePlaceholderExpander::ExpandRuleVariable(
  24. cmOutputConverter* outputConverter, std::string const& variable,
  25. const RuleVariables& replaceValues)
  26. {
  27. if (replaceValues.LinkFlags) {
  28. if (variable == "LINK_FLAGS") {
  29. return replaceValues.LinkFlags;
  30. }
  31. }
  32. if (replaceValues.Manifests) {
  33. if (variable == "MANIFESTS") {
  34. return replaceValues.Manifests;
  35. }
  36. }
  37. if (replaceValues.Flags) {
  38. if (variable == "FLAGS") {
  39. return replaceValues.Flags;
  40. }
  41. }
  42. if (replaceValues.Source) {
  43. if (variable == "SOURCE") {
  44. return replaceValues.Source;
  45. }
  46. }
  47. if (replaceValues.PreprocessedSource) {
  48. if (variable == "PREPROCESSED_SOURCE") {
  49. return replaceValues.PreprocessedSource;
  50. }
  51. }
  52. if (replaceValues.AssemblySource) {
  53. if (variable == "ASSEMBLY_SOURCE") {
  54. return replaceValues.AssemblySource;
  55. }
  56. }
  57. if (replaceValues.Object) {
  58. if (variable == "OBJECT") {
  59. return replaceValues.Object;
  60. }
  61. }
  62. if (replaceValues.ObjectDir) {
  63. if (variable == "OBJECT_DIR") {
  64. return replaceValues.ObjectDir;
  65. }
  66. }
  67. if (replaceValues.ObjectFileDir) {
  68. if (variable == "OBJECT_FILE_DIR") {
  69. return replaceValues.ObjectFileDir;
  70. }
  71. }
  72. if (replaceValues.Objects) {
  73. if (variable == "OBJECTS") {
  74. return replaceValues.Objects;
  75. }
  76. }
  77. if (replaceValues.ObjectsQuoted) {
  78. if (variable == "OBJECTS_QUOTED") {
  79. return replaceValues.ObjectsQuoted;
  80. }
  81. }
  82. if (replaceValues.Defines && variable == "DEFINES") {
  83. return replaceValues.Defines;
  84. }
  85. if (replaceValues.Includes && variable == "INCLUDES") {
  86. return replaceValues.Includes;
  87. }
  88. if (replaceValues.TargetPDB) {
  89. if (variable == "TARGET_PDB") {
  90. return replaceValues.TargetPDB;
  91. }
  92. }
  93. if (replaceValues.TargetCompilePDB) {
  94. if (variable == "TARGET_COMPILE_PDB") {
  95. return replaceValues.TargetCompilePDB;
  96. }
  97. }
  98. if (replaceValues.DependencyFile) {
  99. if (variable == "DEP_FILE") {
  100. return replaceValues.DependencyFile;
  101. }
  102. }
  103. if (replaceValues.Target) {
  104. if (variable == "TARGET_QUOTED") {
  105. std::string targetQuoted = replaceValues.Target;
  106. if (!targetQuoted.empty() && targetQuoted.front() != '\"') {
  107. targetQuoted = '\"';
  108. targetQuoted += replaceValues.Target;
  109. targetQuoted += '\"';
  110. }
  111. return targetQuoted;
  112. }
  113. if (variable == "TARGET_UNQUOTED") {
  114. std::string unquoted = replaceValues.Target;
  115. std::string::size_type sz = unquoted.size();
  116. if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') {
  117. unquoted = unquoted.substr(1, sz - 2);
  118. }
  119. return unquoted;
  120. }
  121. if (replaceValues.LanguageCompileFlags) {
  122. if (variable == "LANGUAGE_COMPILE_FLAGS") {
  123. return replaceValues.LanguageCompileFlags;
  124. }
  125. }
  126. if (replaceValues.Target) {
  127. if (variable == "TARGET") {
  128. return replaceValues.Target;
  129. }
  130. }
  131. if (variable == "TARGET_IMPLIB") {
  132. return this->TargetImpLib;
  133. }
  134. if (variable == "TARGET_VERSION_MAJOR") {
  135. if (replaceValues.TargetVersionMajor) {
  136. return replaceValues.TargetVersionMajor;
  137. }
  138. return "0";
  139. }
  140. if (variable == "TARGET_VERSION_MINOR") {
  141. if (replaceValues.TargetVersionMinor) {
  142. return replaceValues.TargetVersionMinor;
  143. }
  144. return "0";
  145. }
  146. if (replaceValues.Target) {
  147. if (variable == "TARGET_BASE") {
  148. // Strip the last extension off the target name.
  149. std::string targetBase = replaceValues.Target;
  150. std::string::size_type pos = targetBase.rfind('.');
  151. if (pos != std::string::npos) {
  152. return targetBase.substr(0, pos);
  153. }
  154. return targetBase;
  155. }
  156. }
  157. }
  158. if (replaceValues.SwiftAuxiliarySources) {
  159. if (variable == "SWIFT_AUXILIARY_SOURCES") {
  160. return replaceValues.SwiftAuxiliarySources;
  161. }
  162. }
  163. if (replaceValues.SwiftModuleName) {
  164. if (variable == "SWIFT_MODULE_NAME") {
  165. return replaceValues.SwiftModuleName;
  166. }
  167. }
  168. if (replaceValues.SwiftLibraryName) {
  169. if (variable == "SWIFT_LIBRARY_NAME") {
  170. return replaceValues.SwiftLibraryName;
  171. }
  172. }
  173. if (replaceValues.SwiftPartialDoc) {
  174. if (variable == "SWIFT_PARTIAL_DOC") {
  175. return replaceValues.SwiftPartialDoc;
  176. }
  177. }
  178. if (replaceValues.SwiftPartialModule) {
  179. if (variable == "SWIFT_PARTIAL_MODULE") {
  180. return replaceValues.SwiftPartialModule;
  181. }
  182. }
  183. if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
  184. variable == "TARGET_INSTALLNAME_DIR") {
  185. // All these variables depend on TargetSOName
  186. if (replaceValues.TargetSOName) {
  187. if (variable == "TARGET_SONAME") {
  188. return replaceValues.TargetSOName;
  189. }
  190. if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) {
  191. return replaceValues.SONameFlag;
  192. }
  193. if (replaceValues.TargetInstallNameDir &&
  194. variable == "TARGET_INSTALLNAME_DIR") {
  195. return replaceValues.TargetInstallNameDir;
  196. }
  197. }
  198. return "";
  199. }
  200. if (replaceValues.LinkLibraries) {
  201. if (variable == "LINK_LIBRARIES") {
  202. return replaceValues.LinkLibraries;
  203. }
  204. }
  205. if (replaceValues.Language) {
  206. if (variable == "LANGUAGE") {
  207. return replaceValues.Language;
  208. }
  209. }
  210. if (replaceValues.CMTargetName) {
  211. if (variable == "TARGET_NAME") {
  212. return replaceValues.CMTargetName;
  213. }
  214. }
  215. if (replaceValues.CMTargetType) {
  216. if (variable == "TARGET_TYPE") {
  217. return replaceValues.CMTargetType;
  218. }
  219. }
  220. if (replaceValues.Output) {
  221. if (variable == "OUTPUT") {
  222. return replaceValues.Output;
  223. }
  224. }
  225. if (variable == "CMAKE_COMMAND") {
  226. return outputConverter->ConvertToOutputFormat(
  227. cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
  228. cmOutputConverter::SHELL);
  229. }
  230. std::map<std::string, std::string>::iterator compIt =
  231. this->Compilers.find(variable);
  232. if (compIt != this->Compilers.end()) {
  233. std::string ret = outputConverter->ConvertToOutputForExisting(
  234. this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]);
  235. std::string const& compilerArg1 =
  236. this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"];
  237. std::string const& compilerTarget =
  238. this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_TARGET"];
  239. std::string const& compilerOptionTarget =
  240. this->VariableMappings["CMAKE_" + compIt->second +
  241. "_COMPILE_OPTIONS_TARGET"];
  242. std::string const& compilerExternalToolchain =
  243. this->VariableMappings["CMAKE_" + compIt->second +
  244. "_COMPILER_EXTERNAL_TOOLCHAIN"];
  245. std::string const& compilerOptionExternalToolchain =
  246. this->VariableMappings["CMAKE_" + compIt->second +
  247. "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN"];
  248. std::string const& compilerOptionSysroot =
  249. this->VariableMappings["CMAKE_" + compIt->second +
  250. "_COMPILE_OPTIONS_SYSROOT"];
  251. // if there is a required first argument to the compiler add it
  252. // to the compiler string
  253. if (!compilerArg1.empty()) {
  254. ret += " ";
  255. ret += compilerArg1;
  256. }
  257. if (!compilerTarget.empty() && !compilerOptionTarget.empty()) {
  258. ret += " ";
  259. ret += compilerOptionTarget;
  260. ret += compilerTarget;
  261. }
  262. if (!compilerExternalToolchain.empty() &&
  263. !compilerOptionExternalToolchain.empty()) {
  264. ret += " ";
  265. ret += compilerOptionExternalToolchain;
  266. ret += outputConverter->EscapeForShell(compilerExternalToolchain, true);
  267. }
  268. std::string sysroot;
  269. // Some platforms may use separate sysroots for compiling and linking.
  270. // If we detect link flags, then we pass the link sysroot instead.
  271. // FIXME: Use a more robust way to detect link line expansion.
  272. if (replaceValues.LinkFlags) {
  273. sysroot = this->LinkerSysroot;
  274. } else {
  275. sysroot = this->CompilerSysroot;
  276. }
  277. if (!sysroot.empty() && !compilerOptionSysroot.empty()) {
  278. ret += " ";
  279. ret += compilerOptionSysroot;
  280. ret += outputConverter->EscapeForShell(sysroot, true);
  281. }
  282. return ret;
  283. }
  284. std::map<std::string, std::string>::iterator mapIt =
  285. this->VariableMappings.find(variable);
  286. if (mapIt != this->VariableMappings.end()) {
  287. if (variable.find("_FLAG") == std::string::npos) {
  288. return outputConverter->ConvertToOutputForExisting(mapIt->second);
  289. }
  290. return mapIt->second;
  291. }
  292. return variable;
  293. }
  294. void cmRulePlaceholderExpander::ExpandRuleVariables(
  295. cmOutputConverter* outputConverter, std::string& s,
  296. const RuleVariables& replaceValues)
  297. {
  298. std::string::size_type start = s.find('<');
  299. // no variables to expand
  300. if (start == std::string::npos) {
  301. return;
  302. }
  303. std::string::size_type pos = 0;
  304. std::string expandedInput;
  305. while (start != std::string::npos && start < s.size() - 2) {
  306. std::string::size_type end = s.find('>', start);
  307. // if we find a < with no > we are done
  308. if (end == std::string::npos) {
  309. return;
  310. }
  311. char c = s[start + 1];
  312. // if the next char after the < is not A-Za-z then
  313. // skip it and try to find the next < in the string
  314. if (!isalpha(c)) {
  315. start = s.find('<', start + 1);
  316. } else {
  317. // extract the var
  318. std::string var = s.substr(start + 1, end - start - 1);
  319. std::string replace =
  320. this->ExpandRuleVariable(outputConverter, var, replaceValues);
  321. expandedInput += s.substr(pos, start - pos);
  322. expandedInput += replace;
  323. // move to next one
  324. start = s.find('<', start + var.size() + 2);
  325. pos = end + 1;
  326. }
  327. }
  328. // add the rest of the input
  329. expandedInput += s.substr(pos, s.size() - pos);
  330. s = expandedInput;
  331. }