cmQtAutoGeneratorInitializer.cxx 40 KB

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