1
0

cmQtAutoGeneratorInitializer.cxx 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  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 "cmQtAutoGen.h"
  4. #include "cmQtAutoGeneratorInitializer.h"
  5. #include "cmAlgorithms.h"
  6. #include "cmCustomCommand.h"
  7. #include "cmCustomCommandLines.h"
  8. #include "cmFilePathChecksum.h"
  9. #include "cmGeneratorTarget.h"
  10. #include "cmGlobalGenerator.h"
  11. #include "cmLinkItem.h"
  12. #include "cmLocalGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmOutputConverter.h"
  15. #include "cmPolicies.h"
  16. #include "cmSourceFile.h"
  17. #include "cmSourceGroup.h"
  18. #include "cmState.h"
  19. #include "cmStateTypes.h"
  20. #include "cmSystemTools.h"
  21. #include "cmTarget.h"
  22. #include "cm_sys_stat.h"
  23. #include "cmake.h"
  24. #include "cmsys/FStream.hxx"
  25. #include <algorithm>
  26. #include <array>
  27. #include <deque>
  28. #include <map>
  29. #include <set>
  30. #include <sstream>
  31. #include <string>
  32. #include <utility>
  33. #include <vector>
  34. inline static const char* SafeString(const char* value)
  35. {
  36. return (value != nullptr) ? value : "";
  37. }
  38. inline static std::string GetSafeProperty(cmGeneratorTarget const* target,
  39. const char* key)
  40. {
  41. return std::string(SafeString(target->GetProperty(key)));
  42. }
  43. inline static std::string GetSafeProperty(cmSourceFile const* sf,
  44. const char* key)
  45. {
  46. return std::string(SafeString(sf->GetProperty(key)));
  47. }
  48. static cmQtAutoGen::MultiConfig AutogenMultiConfig(
  49. cmGlobalGenerator* globalGen)
  50. {
  51. if (!globalGen->IsMultiConfig()) {
  52. return cmQtAutoGen::SINGLE;
  53. }
  54. // FIXME: Xcode does not support per-config sources, yet.
  55. // (EXCLUDED_SOURCE_FILE_NAMES)
  56. // if (globalGen->GetName().find("Xcode") != std::string::npos) {
  57. // return cmQtAutoGen::FULL;
  58. //}
  59. // FIXME: Visual Studio does not support per-config sources, yet.
  60. // (EXCLUDED_SOURCE_FILE_NAMES)
  61. // if (globalGen->GetName().find("Visual Studio") != std::string::npos) {
  62. // return cmQtAutoGen::FULL;
  63. //}
  64. return cmQtAutoGen::WRAP;
  65. }
  66. static std::string GetAutogenTargetName(cmGeneratorTarget const* target)
  67. {
  68. std::string autogenTargetName = target->GetName();
  69. autogenTargetName += "_autogen";
  70. return autogenTargetName;
  71. }
  72. static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target)
  73. {
  74. cmMakefile* makefile = target->Target->GetMakefile();
  75. std::string targetDir = makefile->GetCurrentBinaryDirectory();
  76. targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
  77. targetDir += "/";
  78. targetDir += GetAutogenTargetName(target);
  79. targetDir += ".dir";
  80. return targetDir;
  81. }
  82. static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target)
  83. {
  84. std::string targetDir = GetSafeProperty(target, "AUTOGEN_BUILD_DIR");
  85. if (targetDir.empty()) {
  86. cmMakefile* makefile = target->Target->GetMakefile();
  87. targetDir = makefile->GetCurrentBinaryDirectory();
  88. targetDir += "/";
  89. targetDir += GetAutogenTargetName(target);
  90. }
  91. return targetDir;
  92. }
  93. std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion(
  94. cmGeneratorTarget const* target)
  95. {
  96. cmMakefile* makefile = target->Target->GetMakefile();
  97. std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
  98. if (qtMajor.empty()) {
  99. qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
  100. }
  101. const char* targetQtVersion =
  102. target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "");
  103. if (targetQtVersion != nullptr) {
  104. qtMajor = targetQtVersion;
  105. }
  106. return qtMajor;
  107. }
  108. std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion(
  109. cmGeneratorTarget const* target, std::string const& qtVersionMajor)
  110. {
  111. cmMakefile* makefile = target->Target->GetMakefile();
  112. std::string qtMinor;
  113. if (qtVersionMajor == "5") {
  114. qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR");
  115. }
  116. if (qtMinor.empty()) {
  117. qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR");
  118. }
  119. const char* targetQtVersion =
  120. target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", "");
  121. if (targetQtVersion != nullptr) {
  122. qtMinor = targetQtVersion;
  123. }
  124. return qtMinor;
  125. }
  126. static bool QtVersionGreaterOrEqual(std::string const& major,
  127. std::string const& minor,
  128. unsigned long requestMajor,
  129. unsigned long requestMinor)
  130. {
  131. unsigned long majorUL(0);
  132. unsigned long minorUL(0);
  133. if (cmSystemTools::StringToULong(major.c_str(), &majorUL) &&
  134. cmSystemTools::StringToULong(minor.c_str(), &minorUL)) {
  135. return (majorUL > requestMajor) ||
  136. (majorUL == requestMajor && minorUL >= requestMinor);
  137. }
  138. return false;
  139. }
  140. static void GetConfigs(cmMakefile* makefile, std::string& configDefault,
  141. std::vector<std::string>& configsList)
  142. {
  143. configDefault = makefile->GetConfigurations(configsList);
  144. if (configsList.empty()) {
  145. configsList.push_back(configDefault);
  146. }
  147. }
  148. static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
  149. std::string const& value)
  150. {
  151. makefile->AddDefinition(key,
  152. cmOutputConverter::EscapeForCMake(value).c_str());
  153. }
  154. static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
  155. const std::vector<std::string>& values)
  156. {
  157. makefile->AddDefinition(
  158. key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str());
  159. }
  160. static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
  161. const std::set<std::string>& values)
  162. {
  163. makefile->AddDefinition(
  164. key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str());
  165. }
  166. static void AddDefinitionEscaped(
  167. cmMakefile* makefile, const char* key,
  168. const std::vector<std::vector<std::string>>& lists)
  169. {
  170. std::vector<std::string> seplist;
  171. for (const std::vector<std::string>& list : lists) {
  172. std::string blist = "{";
  173. blist += cmJoin(list, ";");
  174. blist += "}";
  175. seplist.push_back(std::move(blist));
  176. }
  177. makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake(
  178. cmJoin(seplist, cmQtAutoGen::listSep))
  179. .c_str());
  180. }
  181. static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
  182. cmQtAutoGen::Generator genType)
  183. {
  184. cmSourceGroup* sourceGroup = nullptr;
  185. // Acquire source group
  186. {
  187. std::string property;
  188. std::string groupName;
  189. {
  190. std::array<std::string, 2> props;
  191. // Use generator specific group name
  192. switch (genType) {
  193. case cmQtAutoGen::MOC:
  194. props[0] = "AUTOMOC_SOURCE_GROUP";
  195. break;
  196. case cmQtAutoGen::RCC:
  197. props[0] = "AUTORCC_SOURCE_GROUP";
  198. break;
  199. default:
  200. props[0] = "AUTOGEN_SOURCE_GROUP";
  201. break;
  202. }
  203. props[1] = "AUTOGEN_SOURCE_GROUP";
  204. for (std::string& prop : props) {
  205. const char* propName = makefile->GetState()->GetGlobalProperty(prop);
  206. if ((propName != nullptr) && (*propName != '\0')) {
  207. groupName = propName;
  208. property = std::move(prop);
  209. break;
  210. }
  211. }
  212. }
  213. // Generate a source group on demand
  214. if (!groupName.empty()) {
  215. sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
  216. if (sourceGroup == nullptr) {
  217. std::ostringstream ost;
  218. ost << cmQtAutoGen::GeneratorNameUpper(genType);
  219. ost << ": " << property;
  220. ost << ": Could not find or create the source group ";
  221. ost << cmQtAutoGen::Quoted(groupName);
  222. cmSystemTools::Error(ost.str().c_str());
  223. return false;
  224. }
  225. }
  226. }
  227. if (sourceGroup != nullptr) {
  228. sourceGroup->AddGroupFile(fileName);
  229. }
  230. return true;
  231. }
  232. static void AddCleanFile(cmMakefile* makefile, std::string const& fileName)
  233. {
  234. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(),
  235. false);
  236. }
  237. static std::vector<std::string> AddGeneratedSource(
  238. cmGeneratorTarget* target, std::string const& filename,
  239. cmQtAutoGen::MultiConfig multiConfig,
  240. const std::vector<std::string>& configsList, cmQtAutoGen::Generator genType)
  241. {
  242. std::vector<std::string> genFiles;
  243. // Register source file in makefile and source group
  244. if (multiConfig != cmQtAutoGen::FULL) {
  245. genFiles.push_back(filename);
  246. } else {
  247. for (std::string const& cfg : configsList) {
  248. genFiles.push_back(
  249. cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg));
  250. }
  251. }
  252. {
  253. cmMakefile* makefile = target->Target->GetMakefile();
  254. for (std::string const& genFile : genFiles) {
  255. {
  256. cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true);
  257. gFile->SetProperty("GENERATED", "1");
  258. gFile->SetProperty("SKIP_AUTOGEN", "On");
  259. }
  260. AddToSourceGroup(makefile, genFile, genType);
  261. }
  262. }
  263. // Add source file to target
  264. if (multiConfig != cmQtAutoGen::FULL) {
  265. target->AddSource(filename);
  266. } else {
  267. for (std::string const& cfg : configsList) {
  268. std::string src = "$<$<CONFIG:";
  269. src += cfg;
  270. src += ">:";
  271. src += cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg);
  272. src += ">";
  273. target->AddSource(src);
  274. }
  275. }
  276. return genFiles;
  277. }
  278. /* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its
  279. * recursive STATIC_LIBRARY dependencies depends on targetOrigin
  280. * (STATIC_LIBRARY cycle).
  281. */
  282. static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
  283. cmGeneratorTarget const* targetDepend,
  284. std::string const& config)
  285. {
  286. bool cycle = false;
  287. if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) &&
  288. (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) {
  289. std::set<cmGeneratorTarget const*> knownLibs;
  290. std::deque<cmGeneratorTarget const*> testLibs;
  291. // Insert initial static_library dependency
  292. knownLibs.insert(targetDepend);
  293. testLibs.push_back(targetDepend);
  294. while (!testLibs.empty()) {
  295. cmGeneratorTarget const* testTarget = testLibs.front();
  296. testLibs.pop_front();
  297. // Check if the test target is the origin target (cycle)
  298. if (testTarget == targetOrigin) {
  299. cycle = true;
  300. break;
  301. }
  302. // Collect all static_library dependencies from the test target
  303. cmLinkImplementationLibraries const* libs =
  304. testTarget->GetLinkImplementationLibraries(config);
  305. if (libs != nullptr) {
  306. for (cmLinkItem const& item : libs->Libraries) {
  307. cmGeneratorTarget const* depTarget = item.Target;
  308. if ((depTarget != nullptr) &&
  309. (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) &&
  310. knownLibs.insert(depTarget).second) {
  311. testLibs.push_back(depTarget);
  312. }
  313. }
  314. }
  315. }
  316. }
  317. return cycle;
  318. }
  319. struct cmQtAutoGenSetup
  320. {
  321. std::set<std::string> MocSkip;
  322. std::set<std::string> UicSkip;
  323. std::map<std::string, std::string> ConfigMocIncludes;
  324. std::map<std::string, std::string> ConfigMocDefines;
  325. std::map<std::string, std::string> ConfigUicOptions;
  326. };
  327. static void SetupAcquireSkipFiles(cmQtAutoGenDigest const& digest,
  328. cmQtAutoGenSetup& setup)
  329. {
  330. // Read skip files from makefile sources
  331. {
  332. const std::vector<cmSourceFile*>& allSources =
  333. digest.Target->Makefile->GetSourceFiles();
  334. for (cmSourceFile* sf : allSources) {
  335. // sf->GetExtension() is only valid after sf->GetFullPath() ...
  336. std::string const& fPath = sf->GetFullPath();
  337. cmSystemTools::FileFormat const fileType =
  338. cmSystemTools::GetFileFormat(sf->GetExtension().c_str());
  339. if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) &&
  340. !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
  341. continue;
  342. }
  343. const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN");
  344. const bool mocSkip = digest.MocEnabled &&
  345. (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC"));
  346. const bool uicSkip = digest.UicEnabled &&
  347. (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC"));
  348. if (mocSkip || uicSkip) {
  349. std::string const absFile = cmSystemTools::GetRealPath(fPath);
  350. if (mocSkip) {
  351. setup.MocSkip.insert(absFile);
  352. }
  353. if (uicSkip) {
  354. setup.UicSkip.insert(absFile);
  355. }
  356. }
  357. }
  358. }
  359. }
  360. static void SetupAutoTargetMoc(cmQtAutoGenDigest const& digest,
  361. std::string const& configDefault,
  362. std::vector<std::string> const& configsList,
  363. cmQtAutoGenSetup& setup)
  364. {
  365. cmGeneratorTarget const* target = digest.Target;
  366. cmLocalGenerator* localGen = target->GetLocalGenerator();
  367. cmMakefile* makefile = target->Target->GetMakefile();
  368. AddDefinitionEscaped(makefile, "_moc_skip", setup.MocSkip);
  369. AddDefinitionEscaped(makefile, "_moc_options",
  370. GetSafeProperty(target, "AUTOMOC_MOC_OPTIONS"));
  371. AddDefinitionEscaped(makefile, "_moc_relaxed_mode",
  372. makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE"
  373. : "FALSE");
  374. AddDefinitionEscaped(makefile, "_moc_macro_names",
  375. GetSafeProperty(target, "AUTOMOC_MACRO_NAMES"));
  376. AddDefinitionEscaped(makefile, "_moc_depend_filters",
  377. GetSafeProperty(target, "AUTOMOC_DEPEND_FILTERS"));
  378. // Compiler predefines
  379. if (target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES")) {
  380. if (QtVersionGreaterOrEqual(digest.QtVersionMajor, digest.QtVersionMinor,
  381. 5, 8)) {
  382. AddDefinitionEscaped(
  383. makefile, "_moc_predefs_cmd",
  384. makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"));
  385. }
  386. }
  387. // Moc includes and compile definitions
  388. {
  389. auto GetIncludeDirs = [target,
  390. localGen](std::string const& cfg) -> std::string {
  391. // Get the include dirs for this target, without stripping the implicit
  392. // include dirs off, see
  393. // https://gitlab.kitware.com/cmake/cmake/issues/13667
  394. std::vector<std::string> includeDirs;
  395. localGen->GetIncludeDirectories(includeDirs, target, "CXX", cfg, false);
  396. return cmJoin(includeDirs, ";");
  397. };
  398. auto GetCompileDefinitions =
  399. [target, localGen](std::string const& cfg) -> std::string {
  400. std::set<std::string> defines;
  401. localGen->AddCompileDefinitions(defines, target, cfg, "CXX");
  402. return cmJoin(defines, ";");
  403. };
  404. // Default configuration settings
  405. std::string const includeDirs = GetIncludeDirs(configDefault);
  406. std::string const compileDefs = GetCompileDefinitions(configDefault);
  407. // Other configuration settings
  408. for (std::string const& cfg : configsList) {
  409. {
  410. std::string const configIncludeDirs = GetIncludeDirs(cfg);
  411. if (configIncludeDirs != includeDirs) {
  412. setup.ConfigMocIncludes[cfg] = configIncludeDirs;
  413. }
  414. }
  415. {
  416. std::string const configCompileDefs = GetCompileDefinitions(cfg);
  417. if (configCompileDefs != compileDefs) {
  418. setup.ConfigMocDefines[cfg] = configCompileDefs;
  419. }
  420. }
  421. }
  422. AddDefinitionEscaped(makefile, "_moc_include_dirs", includeDirs);
  423. AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs);
  424. }
  425. // Moc executable
  426. {
  427. std::string mocExec;
  428. std::string err;
  429. if (digest.QtVersionMajor == "5") {
  430. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc");
  431. if (tgt != nullptr) {
  432. mocExec = SafeString(tgt->ImportedGetLocation(""));
  433. } else {
  434. err = "AUTOMOC: Qt5::moc target not found";
  435. }
  436. } else if (digest.QtVersionMajor == "4") {
  437. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc");
  438. if (tgt != nullptr) {
  439. mocExec = SafeString(tgt->ImportedGetLocation(""));
  440. } else {
  441. err = "AUTOMOC: Qt4::moc target not found";
  442. }
  443. } else {
  444. err = "The AUTOMOC feature supports only Qt 4 and Qt 5";
  445. }
  446. if (err.empty()) {
  447. AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec);
  448. } else {
  449. err += " (" + target->GetName() + ")";
  450. cmSystemTools::Error(err.c_str());
  451. }
  452. }
  453. }
  454. static void SetupAutoTargetUic(cmQtAutoGenDigest const& digest,
  455. std::string const& config,
  456. std::vector<std::string> const& configs,
  457. cmQtAutoGenSetup& setup)
  458. {
  459. cmGeneratorTarget const* target = digest.Target;
  460. cmMakefile* makefile = target->Target->GetMakefile();
  461. // Uic search paths
  462. {
  463. std::vector<std::string> uicSearchPaths;
  464. {
  465. std::string const usp = GetSafeProperty(target, "AUTOUIC_SEARCH_PATHS");
  466. if (!usp.empty()) {
  467. cmSystemTools::ExpandListArgument(usp, uicSearchPaths);
  468. std::string const srcDir = makefile->GetCurrentSourceDirectory();
  469. for (std::string& path : uicSearchPaths) {
  470. path = cmSystemTools::CollapseFullPath(path, srcDir);
  471. }
  472. }
  473. }
  474. AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths);
  475. }
  476. // Uic target options
  477. {
  478. auto UicGetOpts = [target](std::string const& cfg) -> std::string {
  479. std::vector<std::string> opts;
  480. target->GetAutoUicOptions(opts, cfg);
  481. return cmJoin(opts, ";");
  482. };
  483. // Default settings
  484. std::string const uicOpts = UicGetOpts(config);
  485. AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts);
  486. // Configuration specific settings
  487. for (std::string const& cfg : configs) {
  488. std::string const configUicOpts = UicGetOpts(cfg);
  489. if (configUicOpts != uicOpts) {
  490. setup.ConfigUicOptions[cfg] = configUicOpts;
  491. }
  492. }
  493. }
  494. // .ui files skip and options
  495. {
  496. std::vector<std::string> uiFileFiles;
  497. std::vector<std::vector<std::string>> uiFileOptions;
  498. {
  499. std::string const uiExt = "ui";
  500. for (cmSourceFile* sf : makefile->GetSourceFiles()) {
  501. // sf->GetExtension() is only valid after sf->GetFullPath() ...
  502. std::string const& fPath = sf->GetFullPath();
  503. if (sf->GetExtension() == uiExt) {
  504. std::string const absFile = cmSystemTools::GetRealPath(fPath);
  505. // Check if the file should be skipped
  506. if (sf->GetPropertyAsBool("SKIP_AUTOUIC") ||
  507. sf->GetPropertyAsBool("SKIP_AUTOGEN")) {
  508. setup.UicSkip.insert(absFile);
  509. }
  510. // Check if the files has uic options
  511. std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS");
  512. if (!uicOpts.empty()) {
  513. // Check if file isn't skipped
  514. if (setup.UicSkip.count(absFile) == 0) {
  515. uiFileFiles.push_back(absFile);
  516. std::vector<std::string> optsVec;
  517. cmSystemTools::ExpandListArgument(uicOpts, optsVec);
  518. uiFileOptions.push_back(std::move(optsVec));
  519. }
  520. }
  521. }
  522. }
  523. }
  524. AddDefinitionEscaped(makefile, "_qt_uic_options_files", uiFileFiles);
  525. AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions);
  526. }
  527. AddDefinitionEscaped(makefile, "_uic_skip", setup.UicSkip);
  528. // Uic executable
  529. {
  530. std::string err;
  531. std::string uicExec;
  532. cmLocalGenerator* localGen = target->GetLocalGenerator();
  533. if (digest.QtVersionMajor == "5") {
  534. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::uic");
  535. if (tgt != nullptr) {
  536. uicExec = SafeString(tgt->ImportedGetLocation(""));
  537. } else {
  538. // Project does not use Qt5Widgets, but has AUTOUIC ON anyway
  539. }
  540. } else if (digest.QtVersionMajor == "4") {
  541. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic");
  542. if (tgt != nullptr) {
  543. uicExec = SafeString(tgt->ImportedGetLocation(""));
  544. } else {
  545. err = "AUTOUIC: Qt4::uic target not found";
  546. }
  547. } else {
  548. err = "The AUTOUIC feature supports only Qt 4 and Qt 5";
  549. }
  550. if (err.empty()) {
  551. AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec);
  552. } else {
  553. err += " (" + target->GetName() + ")";
  554. cmSystemTools::Error(err.c_str());
  555. }
  556. }
  557. }
  558. static std::string RccGetExecutable(cmGeneratorTarget const* target,
  559. std::string const& qtMajorVersion)
  560. {
  561. std::string rccExec;
  562. std::string err;
  563. cmLocalGenerator* localGen = target->GetLocalGenerator();
  564. if (qtMajorVersion == "5") {
  565. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::rcc");
  566. if (tgt != nullptr) {
  567. rccExec = SafeString(tgt->ImportedGetLocation(""));
  568. } else {
  569. err = "AUTORCC: Qt5::rcc target not found";
  570. }
  571. } else if (qtMajorVersion == "4") {
  572. cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::rcc");
  573. if (tgt != nullptr) {
  574. rccExec = SafeString(tgt->ImportedGetLocation(""));
  575. } else {
  576. err = "AUTORCC: Qt4::rcc target not found";
  577. }
  578. } else {
  579. err = "The AUTORCC feature supports only Qt 4 and Qt 5";
  580. }
  581. if (!err.empty()) {
  582. err += " (" + target->GetName() + ")";
  583. cmSystemTools::Error(err.c_str());
  584. }
  585. return rccExec;
  586. }
  587. static void SetupAutoTargetRcc(cmQtAutoGenDigest const& digest)
  588. {
  589. std::vector<std::string> rccFiles;
  590. std::vector<std::string> rccBuilds;
  591. std::vector<std::vector<std::string>> rccOptions;
  592. std::vector<std::vector<std::string>> rccInputs;
  593. for (cmQtAutoGenDigestQrc const& qrcDigest : digest.Qrcs) {
  594. rccFiles.push_back(qrcDigest.QrcFile);
  595. rccBuilds.push_back(qrcDigest.RccFile);
  596. rccOptions.push_back(qrcDigest.Options);
  597. rccInputs.push_back(qrcDigest.Resources);
  598. }
  599. cmMakefile* makefile = digest.Target->Target->GetMakefile();
  600. AddDefinitionEscaped(makefile, "_qt_rcc_executable",
  601. RccGetExecutable(digest.Target, digest.QtVersionMajor));
  602. AddDefinitionEscaped(makefile, "_rcc_files", rccFiles);
  603. AddDefinitionEscaped(makefile, "_rcc_builds", rccBuilds);
  604. AddDefinitionEscaped(makefile, "_rcc_options", rccOptions);
  605. AddDefinitionEscaped(makefile, "_rcc_inputs", rccInputs);
  606. }
  607. void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
  608. cmQtAutoGenDigest& digest)
  609. {
  610. cmGeneratorTarget* target = digest.Target;
  611. cmMakefile* makefile = target->Target->GetMakefile();
  612. cmLocalGenerator* localGen = target->GetLocalGenerator();
  613. cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator();
  614. std::string const autogenTargetName = GetAutogenTargetName(target);
  615. std::string const autogenInfoDir = GetAutogenTargetFilesDir(target);
  616. std::string const autogenBuildDir = GetAutogenTargetBuildDir(target);
  617. std::string const workingDirectory =
  618. cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory());
  619. cmQtAutoGen::MultiConfig const multiConfig = AutogenMultiConfig(globalGen);
  620. std::string configDefault;
  621. std::vector<std::string> configsList;
  622. GetConfigs(makefile, configDefault, configsList);
  623. std::set<std::string> autogenDependFiles;
  624. std::set<cmTarget*> autogenDependTargets;
  625. std::vector<std::string> autogenProvides;
  626. // Remove build directories on cleanup
  627. AddCleanFile(makefile, autogenBuildDir);
  628. // Remove old settings on cleanup
  629. {
  630. std::string base = autogenInfoDir + "/AutogenOldSettings";
  631. if (multiConfig == cmQtAutoGen::SINGLE) {
  632. AddCleanFile(makefile, base.append(".cmake"));
  633. } else {
  634. for (std::string const& cfg : configsList) {
  635. std::string filename = base;
  636. filename += "_";
  637. filename += cfg;
  638. filename += ".cmake";
  639. AddCleanFile(makefile, filename);
  640. }
  641. }
  642. }
  643. // Compose command lines
  644. cmCustomCommandLines commandLines;
  645. {
  646. cmCustomCommandLine currentLine;
  647. currentLine.push_back(cmSystemTools::GetCMakeCommand());
  648. currentLine.push_back("-E");
  649. currentLine.push_back("cmake_autogen");
  650. currentLine.push_back(autogenInfoDir);
  651. currentLine.push_back("$<CONFIGURATION>");
  652. commandLines.push_back(currentLine);
  653. }
  654. // Compose target comment
  655. std::string autogenComment;
  656. {
  657. std::vector<std::string> toolNames;
  658. if (digest.MocEnabled) {
  659. toolNames.emplace_back("MOC");
  660. }
  661. if (digest.UicEnabled) {
  662. toolNames.emplace_back("UIC");
  663. }
  664. if (digest.RccEnabled) {
  665. toolNames.emplace_back("RCC");
  666. }
  667. std::string tools = toolNames.front();
  668. toolNames.erase(toolNames.begin());
  669. if (!toolNames.empty()) {
  670. while (toolNames.size() > 1) {
  671. tools += ", ";
  672. tools += toolNames.front();
  673. toolNames.erase(toolNames.begin());
  674. }
  675. tools += " and " + toolNames.front();
  676. }
  677. autogenComment = "Automatic " + tools + " for target " + target->GetName();
  678. }
  679. // Add moc compilation to generated files list
  680. if (digest.MocEnabled) {
  681. std::string const mocsComp = autogenBuildDir + "/mocs_compilation.cpp";
  682. auto files = AddGeneratedSource(target, mocsComp, multiConfig, configsList,
  683. cmQtAutoGen::MOC);
  684. for (std::string& file : files) {
  685. autogenProvides.push_back(std::move(file));
  686. }
  687. }
  688. // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES
  689. if (digest.MocEnabled || digest.UicEnabled) {
  690. std::string includeDir = autogenBuildDir + "/include";
  691. if (multiConfig != cmQtAutoGen::SINGLE) {
  692. includeDir += "_$<CONFIG>";
  693. }
  694. target->AddIncludeDirectory(includeDir, true);
  695. }
  696. // Extract relevant source files
  697. std::vector<std::string> generatedSources;
  698. std::vector<std::string> generatedHeaders;
  699. {
  700. std::string const qrcExt = "qrc";
  701. std::vector<cmSourceFile*> srcFiles;
  702. target->GetConfigCommonSourceFiles(srcFiles);
  703. for (cmSourceFile* sf : srcFiles) {
  704. if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) {
  705. continue;
  706. }
  707. // sf->GetExtension() is only valid after sf->GetFullPath() ...
  708. std::string const& fPath = sf->GetFullPath();
  709. std::string const& ext = sf->GetExtension();
  710. // Register generated files that will be scanned by moc or uic
  711. if (digest.MocEnabled || digest.UicEnabled) {
  712. cmSystemTools::FileFormat const fileType =
  713. cmSystemTools::GetFileFormat(ext.c_str());
  714. if ((fileType == cmSystemTools::CXX_FILE_FORMAT) ||
  715. (fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
  716. std::string const absPath = cmSystemTools::GetRealPath(fPath);
  717. if ((digest.MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) ||
  718. (digest.UicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) {
  719. // Register source
  720. const bool generated = sf->GetPropertyAsBool("GENERATED");
  721. if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
  722. if (generated) {
  723. generatedHeaders.push_back(absPath);
  724. } else {
  725. digest.Headers.push_back(absPath);
  726. }
  727. } else {
  728. if (generated) {
  729. generatedSources.push_back(absPath);
  730. } else {
  731. digest.Sources.push_back(absPath);
  732. }
  733. }
  734. }
  735. }
  736. }
  737. // Register rcc enabled files
  738. if (digest.RccEnabled && (ext == qrcExt) &&
  739. !sf->GetPropertyAsBool("SKIP_AUTORCC")) {
  740. // Register qrc file
  741. {
  742. cmQtAutoGenDigestQrc qrcDigest;
  743. qrcDigest.QrcFile = cmSystemTools::GetRealPath(fPath);
  744. qrcDigest.QrcName =
  745. cmSystemTools::GetFilenameWithoutLastExtension(qrcDigest.QrcFile);
  746. qrcDigest.Generated = sf->GetPropertyAsBool("GENERATED");
  747. // RCC options
  748. {
  749. std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS");
  750. if (!opts.empty()) {
  751. cmSystemTools::ExpandListArgument(opts, qrcDigest.Options);
  752. }
  753. }
  754. digest.Qrcs.push_back(std::move(qrcDigest));
  755. }
  756. }
  757. }
  758. // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's
  759. // sources meta data cache. Clear it so that OBJECT library targets that
  760. // are AUTOGEN initialized after this target get their added
  761. // mocs_compilation.cpp source acknowledged by this target.
  762. target->ClearSourcesCache();
  763. }
  764. // Process GENERATED sources and headers
  765. if (!generatedSources.empty() || !generatedHeaders.empty()) {
  766. // Check status of policy CMP0071
  767. bool policyAccept = false;
  768. bool policyWarn = false;
  769. cmPolicies::PolicyStatus const CMP0071_status =
  770. target->Makefile->GetPolicyStatus(cmPolicies::CMP0071);
  771. switch (CMP0071_status) {
  772. case cmPolicies::WARN:
  773. policyWarn = true;
  774. CM_FALLTHROUGH;
  775. case cmPolicies::OLD:
  776. // Ignore GENERATED file
  777. break;
  778. case cmPolicies::REQUIRED_IF_USED:
  779. case cmPolicies::REQUIRED_ALWAYS:
  780. case cmPolicies::NEW:
  781. // Process GENERATED file
  782. policyAccept = true;
  783. break;
  784. }
  785. if (policyAccept) {
  786. // Accept GENERATED sources
  787. for (std::string const& absFile : generatedHeaders) {
  788. digest.Headers.push_back(absFile);
  789. autogenDependFiles.insert(absFile);
  790. }
  791. for (std::string const& absFile : generatedSources) {
  792. digest.Sources.push_back(absFile);
  793. autogenDependFiles.insert(absFile);
  794. }
  795. } else {
  796. if (policyWarn) {
  797. std::string msg;
  798. msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
  799. msg += "\n";
  800. std::string tools;
  801. std::string property;
  802. if (digest.MocEnabled && digest.UicEnabled) {
  803. tools = "AUTOMOC and AUTOUIC";
  804. property = "SKIP_AUTOGEN";
  805. } else if (digest.MocEnabled) {
  806. tools = "AUTOMOC";
  807. property = "SKIP_AUTOMOC";
  808. } else if (digest.UicEnabled) {
  809. tools = "AUTOUIC";
  810. property = "SKIP_AUTOUIC";
  811. }
  812. msg += "For compatibility, CMake is excluding the GENERATED source "
  813. "file(s):\n";
  814. for (const std::string& absFile : generatedHeaders) {
  815. msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n");
  816. }
  817. for (const std::string& absFile : generatedSources) {
  818. msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n");
  819. }
  820. msg += "from processing by ";
  821. msg += tools;
  822. msg +=
  823. ". If any of the files should be processed, set CMP0071 to NEW. "
  824. "If any of the files should not be processed, "
  825. "explicitly exclude them by setting the source file property ";
  826. msg += property;
  827. msg += ":\n set_property(SOURCE file.h PROPERTY ";
  828. msg += property;
  829. msg += " ON)\n";
  830. makefile->IssueMessage(cmake::AUTHOR_WARNING, msg);
  831. }
  832. }
  833. }
  834. // Sort headers and sources
  835. std::sort(digest.Headers.begin(), digest.Headers.end());
  836. std::sort(digest.Sources.begin(), digest.Sources.end());
  837. // Process qrc files
  838. if (!digest.Qrcs.empty()) {
  839. const bool QtV5 = (digest.QtVersionMajor == "5");
  840. std::string const rcc = RccGetExecutable(target, digest.QtVersionMajor);
  841. // Target rcc options
  842. std::vector<std::string> optionsTarget;
  843. cmSystemTools::ExpandListArgument(
  844. GetSafeProperty(target, "AUTORCC_OPTIONS"), optionsTarget);
  845. // Check if file name is unique
  846. for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
  847. qrcDigest.Unique = true;
  848. for (cmQtAutoGenDigestQrc const& qrcDig2 : digest.Qrcs) {
  849. if ((&qrcDigest != &qrcDig2) &&
  850. (qrcDigest.QrcName == qrcDig2.QrcName)) {
  851. qrcDigest.Unique = false;
  852. break;
  853. }
  854. }
  855. }
  856. // Path checksum
  857. {
  858. cmFilePathChecksum const fpathCheckSum(makefile);
  859. for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
  860. qrcDigest.PathChecksum = fpathCheckSum.getPart(qrcDigest.QrcFile);
  861. // RCC output file name
  862. std::string rccFile = autogenBuildDir + "/";
  863. rccFile += qrcDigest.PathChecksum;
  864. rccFile += "/qrc_";
  865. rccFile += qrcDigest.QrcName;
  866. rccFile += ".cpp";
  867. qrcDigest.RccFile = std::move(rccFile);
  868. }
  869. }
  870. // RCC options
  871. for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
  872. // Target options
  873. std::vector<std::string> opts = optionsTarget;
  874. // Merge computed "-name XYZ" option
  875. {
  876. std::string name = qrcDigest.QrcName;
  877. // Replace '-' with '_'. The former is not valid for symbol names.
  878. std::replace(name.begin(), name.end(), '-', '_');
  879. if (!qrcDigest.Unique) {
  880. name += "_";
  881. name += qrcDigest.PathChecksum;
  882. }
  883. std::vector<std::string> nameOpts;
  884. nameOpts.emplace_back("-name");
  885. nameOpts.emplace_back(std::move(name));
  886. cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5);
  887. }
  888. // Merge file option
  889. cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5);
  890. qrcDigest.Options = std::move(opts);
  891. }
  892. for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) {
  893. // Register file at target
  894. {
  895. auto files = AddGeneratedSource(target, qrcDigest.RccFile, multiConfig,
  896. configsList, cmQtAutoGen::RCC);
  897. for (std::string& file : files) {
  898. autogenProvides.push_back(std::move(file));
  899. }
  900. }
  901. // Dependencies
  902. if (qrcDigest.Generated) {
  903. // Add the GENERATED .qrc file to the dependencies
  904. autogenDependFiles.insert(qrcDigest.QrcFile);
  905. } else {
  906. // Add the resource files to the dependencies
  907. {
  908. std::string error;
  909. if (cmQtAutoGen::RccListInputs(digest.QtVersionMajor, rcc,
  910. qrcDigest.QrcFile,
  911. qrcDigest.Resources, &error)) {
  912. for (std::string const& fileName : qrcDigest.Resources) {
  913. autogenDependFiles.insert(fileName);
  914. }
  915. } else {
  916. cmSystemTools::Error(error.c_str());
  917. }
  918. }
  919. // Run cmake again when .qrc file changes
  920. makefile->AddCMakeDependFile(qrcDigest.QrcFile);
  921. }
  922. }
  923. }
  924. // Add user defined autogen target dependencies
  925. {
  926. std::string const deps = GetSafeProperty(target, "AUTOGEN_TARGET_DEPENDS");
  927. if (!deps.empty()) {
  928. std::vector<std::string> extraDeps;
  929. cmSystemTools::ExpandListArgument(deps, extraDeps);
  930. for (std::string const& depName : extraDeps) {
  931. // Allow target and file dependencies
  932. auto* depTarget = makefile->FindTargetToUse(depName);
  933. if (depTarget != nullptr) {
  934. autogenDependTargets.insert(depTarget);
  935. } else {
  936. autogenDependFiles.insert(depName);
  937. }
  938. }
  939. }
  940. }
  941. // Use PRE_BUILD on demand
  942. bool usePRE_BUILD = false;
  943. if (globalGen->GetName().find("Visual Studio") != std::string::npos) {
  944. // Under VS use a PRE_BUILD event instead of a separate target to
  945. // reduce the number of targets loaded into the IDE.
  946. // This also works around a VS 11 bug that may skip updating the target:
  947. // https://connect.microsoft.com/VisualStudio/feedback/details/769495
  948. usePRE_BUILD = true;
  949. }
  950. // Disable PRE_BUILD in some cases
  951. if (usePRE_BUILD) {
  952. // Cannot use PRE_BUILD with file depends
  953. if (!autogenDependFiles.empty()) {
  954. usePRE_BUILD = false;
  955. }
  956. }
  957. // Create the autogen target/command
  958. if (usePRE_BUILD) {
  959. // Add additional autogen target dependencies to origin target
  960. for (cmTarget* depTarget : autogenDependTargets) {
  961. target->Target->AddUtility(depTarget->GetName(), makefile);
  962. }
  963. // Add the pre-build command directly to bypass the OBJECT_LIBRARY
  964. // rejection in cmMakefile::AddCustomCommandToTarget because we know
  965. // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
  966. //
  967. // PRE_BUILD does not support file dependencies!
  968. const std::vector<std::string> no_output;
  969. const std::vector<std::string> no_deps;
  970. cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps,
  971. commandLines, autogenComment.c_str(),
  972. workingDirectory.c_str());
  973. cc.SetEscapeOldStyle(false);
  974. cc.SetEscapeAllowMakeVars(true);
  975. target->Target->AddPreBuildCommand(cc);
  976. } else {
  977. // Add link library target dependencies to the autogen target dependencies
  978. {
  979. // add_dependencies/addUtility do not support generator expressions.
  980. // We depend only on the libraries found in all configs therefore.
  981. std::map<cmGeneratorTarget const*, std::size_t> commonTargets;
  982. for (std::string const& config : configsList) {
  983. cmLinkImplementationLibraries const* libs =
  984. target->GetLinkImplementationLibraries(config);
  985. if (libs != nullptr) {
  986. for (cmLinkItem const& item : libs->Libraries) {
  987. cmGeneratorTarget const* libTarget = item.Target;
  988. if ((libTarget != nullptr) &&
  989. !StaticLibraryCycle(target, libTarget, config)) {
  990. // Increment target config count
  991. commonTargets[libTarget]++;
  992. }
  993. }
  994. }
  995. }
  996. for (auto const& item : commonTargets) {
  997. if (item.second == configsList.size()) {
  998. autogenDependTargets.insert(item.first->Target);
  999. }
  1000. }
  1001. }
  1002. // Create autogen target
  1003. cmTarget* autogenTarget = makefile->AddUtilityCommand(
  1004. autogenTargetName, true, workingDirectory.c_str(),
  1005. /*byproducts=*/autogenProvides,
  1006. std::vector<std::string>(autogenDependFiles.begin(),
  1007. autogenDependFiles.end()),
  1008. commandLines, false, autogenComment.c_str());
  1009. // Create autogen generator target
  1010. localGen->AddGeneratorTarget(
  1011. new cmGeneratorTarget(autogenTarget, localGen));
  1012. // Forward origin utilities to autogen target
  1013. for (std::string const& depName : target->Target->GetUtilities()) {
  1014. autogenTarget->AddUtility(depName, makefile);
  1015. }
  1016. // Add additional autogen target dependencies to autogen target
  1017. for (cmTarget* depTarget : autogenDependTargets) {
  1018. autogenTarget->AddUtility(depTarget->GetName(), makefile);
  1019. }
  1020. // Set FOLDER property in autogen target
  1021. {
  1022. const char* autogenFolder =
  1023. makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
  1024. if (autogenFolder == nullptr) {
  1025. autogenFolder =
  1026. makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
  1027. }
  1028. // Inherit FOLDER property from target (#13688)
  1029. if (autogenFolder == nullptr) {
  1030. autogenFolder = SafeString(target->Target->GetProperty("FOLDER"));
  1031. }
  1032. if ((autogenFolder != nullptr) && (*autogenFolder != '\0')) {
  1033. autogenTarget->SetProperty("FOLDER", autogenFolder);
  1034. }
  1035. }
  1036. // Add autogen target to the origin target dependencies
  1037. target->Target->AddUtility(autogenTargetName, makefile);
  1038. }
  1039. }
  1040. void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
  1041. cmQtAutoGenDigest const& digest)
  1042. {
  1043. cmGeneratorTarget const* target = digest.Target;
  1044. cmMakefile* makefile = target->Target->GetMakefile();
  1045. cmQtAutoGen::MultiConfig const multiConfig =
  1046. AutogenMultiConfig(target->GetGlobalGenerator());
  1047. // forget the variables added here afterwards again:
  1048. cmMakefile::ScopePushPop varScope(makefile);
  1049. static_cast<void>(varScope);
  1050. // Configurations
  1051. std::string configDefault;
  1052. std::vector<std::string> configsList;
  1053. std::map<std::string, std::string> configSuffixes;
  1054. {
  1055. configDefault = makefile->GetConfigurations(configsList);
  1056. if (configsList.empty()) {
  1057. configsList.push_back("");
  1058. }
  1059. }
  1060. for (std::string const& cfg : configsList) {
  1061. configSuffixes[cfg] = "_" + cfg;
  1062. }
  1063. // Configurations settings buffers
  1064. cmQtAutoGenSetup setup;
  1065. // Basic setup
  1066. AddDefinitionEscaped(makefile, "_multi_config",
  1067. cmQtAutoGen::MultiConfigName(multiConfig));
  1068. AddDefinitionEscaped(makefile, "_build_dir",
  1069. GetAutogenTargetBuildDir(target));
  1070. AddDefinitionEscaped(makefile, "_sources", digest.Sources);
  1071. AddDefinitionEscaped(makefile, "_headers", digest.Headers);
  1072. AddDefinitionEscaped(makefile, "_qt_version_major", digest.QtVersionMajor);
  1073. AddDefinitionEscaped(makefile, "_qt_version_minor", digest.QtVersionMinor);
  1074. {
  1075. if (digest.MocEnabled || digest.UicEnabled) {
  1076. SetupAcquireSkipFiles(digest, setup);
  1077. if (digest.MocEnabled) {
  1078. SetupAutoTargetMoc(digest, configDefault, configsList, setup);
  1079. }
  1080. if (digest.UicEnabled) {
  1081. SetupAutoTargetUic(digest, configDefault, configsList, setup);
  1082. }
  1083. }
  1084. if (digest.RccEnabled) {
  1085. SetupAutoTargetRcc(digest);
  1086. }
  1087. }
  1088. // Generate info file
  1089. {
  1090. std::string const infoDir = GetAutogenTargetFilesDir(target);
  1091. if (!cmSystemTools::MakeDirectory(infoDir)) {
  1092. std::string emsg = ("Could not create directory: ");
  1093. emsg += cmQtAutoGen::Quoted(infoDir);
  1094. cmSystemTools::Error(emsg.c_str());
  1095. }
  1096. std::string const infoFile = infoDir + "/AutogenInfo.cmake";
  1097. {
  1098. std::string infoFileIn = cmSystemTools::GetCMakeRoot();
  1099. infoFileIn += "/Modules/AutogenInfo.cmake.in";
  1100. makefile->ConfigureFile(infoFileIn.c_str(), infoFile.c_str(), false,
  1101. true, false);
  1102. }
  1103. // Append custom definitions to info file
  1104. // --------------------------------------
  1105. // Ensure we have write permission in case .in was read-only.
  1106. mode_t perm = 0;
  1107. #if defined(_WIN32) && !defined(__CYGWIN__)
  1108. mode_t mode_write = S_IWRITE;
  1109. #else
  1110. mode_t mode_write = S_IWUSR;
  1111. #endif
  1112. cmSystemTools::GetPermissions(infoFile, perm);
  1113. if (!(perm & mode_write)) {
  1114. cmSystemTools::SetPermissions(infoFile, perm | mode_write);
  1115. }
  1116. // Open and write file
  1117. cmsys::ofstream ofs(infoFile.c_str(), std::ios::app);
  1118. if (ofs) {
  1119. auto OfsWriteMap = [&ofs](
  1120. const char* key, std::map<std::string, std::string> const& map) {
  1121. for (auto const& item : map) {
  1122. ofs << "set(" << key << "_" << item.first << " "
  1123. << cmOutputConverter::EscapeForCMake(item.second) << ")\n";
  1124. }
  1125. };
  1126. ofs << "# Configurations options\n";
  1127. OfsWriteMap("AM_CONFIG_SUFFIX", configSuffixes);
  1128. OfsWriteMap("AM_MOC_DEFINITIONS", setup.ConfigMocDefines);
  1129. OfsWriteMap("AM_MOC_INCLUDES", setup.ConfigMocIncludes);
  1130. OfsWriteMap("AM_UIC_TARGET_OPTIONS", setup.ConfigUicOptions);
  1131. } else {
  1132. // File open error
  1133. std::string error = "Internal CMake error when trying to open file: ";
  1134. error += cmQtAutoGen::Quoted(infoFile);
  1135. error += " for writing.";
  1136. cmSystemTools::Error(error.c_str());
  1137. }
  1138. }
  1139. }