cmQtAutoGeneratorInitializer.cxx 46 KB

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