cmQtAutoGeneratorInitializer.cxx 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2004-2011 Kitware, Inc.
  4. Copyright 2011 Alexander Neundorf ([email protected])
  5. Distributed under the OSI-approved BSD License (the "License");
  6. see accompanying file Copyright.txt for details.
  7. This software is distributed WITHOUT ANY WARRANTY; without even the
  8. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. See the License for more information.
  10. ============================================================================*/
  11. #include "cmQtAutoGeneratorInitializer.h"
  12. #include "cmLocalGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmSourceFile.h"
  15. #include <sys/stat.h>
  16. #include <cmsys/FStream.hxx>
  17. #if defined(_WIN32) && !defined(__CYGWIN__)
  18. # include "cmGlobalVisualStudioGenerator.h"
  19. #endif
  20. static void SetupSourceFiles(cmGeneratorTarget const* target,
  21. std::vector<std::string>& skipMoc,
  22. std::vector<std::string>& mocSources,
  23. std::vector<std::string>& mocHeaders,
  24. std::vector<std::string>& skipUic)
  25. {
  26. cmMakefile* makefile = target->Target->GetMakefile();
  27. std::vector<cmSourceFile*> srcFiles;
  28. target->GetConfigCommonSourceFiles(srcFiles);
  29. std::vector<std::string> newRccFiles;
  30. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  31. fileIt != srcFiles.end();
  32. ++fileIt)
  33. {
  34. cmSourceFile* sf = *fileIt;
  35. std::string absFile = cmsys::SystemTools::GetRealPath(
  36. sf->GetFullPath());
  37. bool skipFileForMoc =
  38. cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
  39. bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
  40. if(cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC")))
  41. {
  42. skipUic.push_back(absFile);
  43. }
  44. std::string ext = sf->GetExtension();
  45. if (target->GetPropertyAsBool("AUTORCC"))
  46. {
  47. if (ext == "qrc"
  48. && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")))
  49. {
  50. std::string basename = cmsys::SystemTools::
  51. GetFilenameWithoutLastExtension(absFile);
  52. std::string rcc_output_dir = target->Target->GetSupportDirectory();
  53. cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
  54. std::string rcc_output_file = rcc_output_dir;
  55. rcc_output_file += "/qrc_" + basename + ".cpp";
  56. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
  57. rcc_output_file.c_str(), false);
  58. makefile->GetOrCreateSource(rcc_output_file, true);
  59. newRccFiles.push_back(rcc_output_file);
  60. }
  61. }
  62. if (!generated)
  63. {
  64. if (skipFileForMoc)
  65. {
  66. skipMoc.push_back(absFile);
  67. }
  68. else
  69. {
  70. cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(
  71. ext.c_str());
  72. if (fileType == cmSystemTools::CXX_FILE_FORMAT)
  73. {
  74. mocSources.push_back(absFile);
  75. }
  76. else if (fileType == cmSystemTools::HEADER_FILE_FORMAT)
  77. {
  78. mocHeaders.push_back(absFile);
  79. }
  80. }
  81. }
  82. }
  83. for(std::vector<std::string>::const_iterator fileIt = newRccFiles.begin();
  84. fileIt != newRccFiles.end();
  85. ++fileIt)
  86. {
  87. const_cast<cmGeneratorTarget*>(target)->AddSource(*fileIt);
  88. }
  89. }
  90. static void GetCompileDefinitionsAndDirectories(
  91. cmGeneratorTarget const* target,
  92. const std::string& config,
  93. std::string &incs,
  94. std::string &defs)
  95. {
  96. std::vector<std::string> includeDirs;
  97. cmLocalGenerator *localGen = target->GetLocalGenerator();
  98. // Get the include dirs for this target, without stripping the implicit
  99. // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
  100. localGen->GetIncludeDirectories(includeDirs, target, "CXX", config, false);
  101. incs = cmJoin(includeDirs, ";");
  102. std::set<std::string> defines;
  103. localGen->AddCompileDefinitions(defines, target->Target, config, "CXX");
  104. defs += cmJoin(defines, ";");
  105. }
  106. static void SetupAutoMocTarget(cmGeneratorTarget const* target,
  107. const std::string &autogenTargetName,
  108. std::vector<std::string> const& skipMoc,
  109. std::vector<std::string> const& mocHeaders,
  110. std::map<std::string, std::string> &configIncludes,
  111. std::map<std::string, std::string> &configDefines)
  112. {
  113. cmMakefile* makefile = target->Target->GetMakefile();
  114. const char* tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS");
  115. std::string _moc_options = (tmp!=0 ? tmp : "");
  116. makefile->AddDefinition("_moc_options",
  117. cmOutputConverter::EscapeForCMake(_moc_options).c_str());
  118. makefile->AddDefinition("_skip_moc",
  119. cmOutputConverter::EscapeForCMake(cmJoin(skipMoc, ";")).c_str());
  120. makefile->AddDefinition("_moc_headers",
  121. cmOutputConverter::EscapeForCMake(cmJoin(mocHeaders, ";")).c_str());
  122. bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE");
  123. makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE");
  124. std::string _moc_incs;
  125. std::string _moc_compile_defs;
  126. std::vector<std::string> configs;
  127. const std::string& config = makefile->GetConfigurations(configs);
  128. GetCompileDefinitionsAndDirectories(target, config,
  129. _moc_incs, _moc_compile_defs);
  130. makefile->AddDefinition("_moc_incs",
  131. cmOutputConverter::EscapeForCMake(_moc_incs).c_str());
  132. makefile->AddDefinition("_moc_compile_defs",
  133. cmOutputConverter::EscapeForCMake(_moc_compile_defs).c_str());
  134. for (std::vector<std::string>::const_iterator li = configs.begin();
  135. li != configs.end(); ++li)
  136. {
  137. std::string config_moc_incs;
  138. std::string config_moc_compile_defs;
  139. GetCompileDefinitionsAndDirectories(target, *li,
  140. config_moc_incs,
  141. config_moc_compile_defs);
  142. if (config_moc_incs != _moc_incs)
  143. {
  144. configIncludes[*li] =
  145. cmOutputConverter::EscapeForCMake(config_moc_incs);
  146. if(_moc_incs.empty())
  147. {
  148. _moc_incs = config_moc_incs;
  149. }
  150. }
  151. if (config_moc_compile_defs != _moc_compile_defs)
  152. {
  153. configDefines[*li] =
  154. cmOutputConverter::EscapeForCMake(config_moc_compile_defs);
  155. if(_moc_compile_defs.empty())
  156. {
  157. _moc_compile_defs = config_moc_compile_defs;
  158. }
  159. }
  160. }
  161. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  162. if (strcmp(qtVersion, "5") == 0)
  163. {
  164. cmTarget *qt5Moc = makefile->FindTargetToUse("Qt5::moc");
  165. if (!qt5Moc)
  166. {
  167. cmSystemTools::Error("Qt5::moc target not found ",
  168. autogenTargetName.c_str());
  169. return;
  170. }
  171. makefile->AddDefinition("_qt_moc_executable",
  172. qt5Moc->ImportedGetLocation(""));
  173. }
  174. else if (strcmp(qtVersion, "4") == 0)
  175. {
  176. cmTarget *qt4Moc = makefile->FindTargetToUse("Qt4::moc");
  177. if (!qt4Moc)
  178. {
  179. cmSystemTools::Error("Qt4::moc target not found ",
  180. autogenTargetName.c_str());
  181. return;
  182. }
  183. makefile->AddDefinition("_qt_moc_executable",
  184. qt4Moc->ImportedGetLocation(""));
  185. }
  186. else
  187. {
  188. cmSystemTools::Error("The CMAKE_AUTOMOC feature supports only Qt 4 and "
  189. "Qt 5 ", autogenTargetName.c_str());
  190. }
  191. }
  192. static void GetUicOpts(cmGeneratorTarget const* target,
  193. const std::string& config,
  194. std::string &optString)
  195. {
  196. std::vector<std::string> opts;
  197. target->GetAutoUicOptions(opts, config);
  198. optString = cmJoin(opts, ";");
  199. }
  200. static void SetupAutoUicTarget(cmGeneratorTarget const* target,
  201. std::vector<std::string> const& skipUic,
  202. std::map<std::string, std::string> &configUicOptions)
  203. {
  204. cmMakefile *makefile = target->Target->GetMakefile();
  205. std::set<std::string> skipped;
  206. skipped.insert(skipUic.begin(), skipUic.end());
  207. makefile->AddDefinition("_skip_uic",
  208. cmOutputConverter::EscapeForCMake(cmJoin(skipUic, ";")).c_str());
  209. std::vector<cmSourceFile*> uiFilesWithOptions
  210. = makefile->GetQtUiFilesWithOptions();
  211. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  212. std::string _uic_opts;
  213. std::vector<std::string> configs;
  214. const std::string& config = makefile->GetConfigurations(configs);
  215. GetUicOpts(target, config, _uic_opts);
  216. if (!_uic_opts.empty())
  217. {
  218. _uic_opts = cmOutputConverter::EscapeForCMake(_uic_opts);
  219. makefile->AddDefinition("_uic_target_options", _uic_opts.c_str());
  220. }
  221. for (std::vector<std::string>::const_iterator li = configs.begin();
  222. li != configs.end(); ++li)
  223. {
  224. std::string config_uic_opts;
  225. GetUicOpts(target, *li, config_uic_opts);
  226. if (config_uic_opts != _uic_opts)
  227. {
  228. configUicOptions[*li] =
  229. cmOutputConverter::EscapeForCMake(config_uic_opts);
  230. if(_uic_opts.empty())
  231. {
  232. _uic_opts = config_uic_opts;
  233. }
  234. }
  235. }
  236. std::string uiFileFiles;
  237. std::string uiFileOptions;
  238. const char* sep = "";
  239. for(std::vector<cmSourceFile*>::const_iterator fileIt =
  240. uiFilesWithOptions.begin();
  241. fileIt != uiFilesWithOptions.end();
  242. ++fileIt)
  243. {
  244. cmSourceFile* sf = *fileIt;
  245. std::string absFile = cmsys::SystemTools::GetRealPath(
  246. sf->GetFullPath());
  247. if (!skipped.insert(absFile).second)
  248. {
  249. continue;
  250. }
  251. uiFileFiles += sep;
  252. uiFileFiles += absFile;
  253. uiFileOptions += sep;
  254. std::string opts = sf->GetProperty("AUTOUIC_OPTIONS");
  255. cmSystemTools::ReplaceString(opts, ";", "@list_sep@");
  256. uiFileOptions += opts;
  257. sep = ";";
  258. }
  259. makefile->AddDefinition("_qt_uic_options_files",
  260. cmOutputConverter::EscapeForCMake(uiFileFiles).c_str());
  261. makefile->AddDefinition("_qt_uic_options_options",
  262. cmOutputConverter::EscapeForCMake(uiFileOptions).c_str());
  263. std::string targetName = target->GetName();
  264. if (strcmp(qtVersion, "5") == 0)
  265. {
  266. cmTarget *qt5Uic = makefile->FindTargetToUse("Qt5::uic");
  267. if (!qt5Uic)
  268. {
  269. // Project does not use Qt5Widgets, but has AUTOUIC ON anyway
  270. }
  271. else
  272. {
  273. makefile->AddDefinition("_qt_uic_executable",
  274. qt5Uic->ImportedGetLocation(""));
  275. }
  276. }
  277. else if (strcmp(qtVersion, "4") == 0)
  278. {
  279. cmTarget *qt4Uic = makefile->FindTargetToUse("Qt4::uic");
  280. if (!qt4Uic)
  281. {
  282. cmSystemTools::Error("Qt4::uic target not found ",
  283. targetName.c_str());
  284. return;
  285. }
  286. makefile->AddDefinition("_qt_uic_executable",
  287. qt4Uic->ImportedGetLocation(""));
  288. }
  289. else
  290. {
  291. cmSystemTools::Error("The CMAKE_AUTOUIC feature supports only Qt 4 and "
  292. "Qt 5 ", targetName.c_str());
  293. }
  294. }
  295. static std::string GetRccExecutable(cmGeneratorTarget const* target)
  296. {
  297. cmMakefile *makefile = target->Target->GetMakefile();
  298. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  299. if (!qtVersion)
  300. {
  301. qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
  302. if (!qtVersion)
  303. {
  304. qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
  305. }
  306. if (const char *targetQtVersion =
  307. target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
  308. ""))
  309. {
  310. qtVersion = targetQtVersion;
  311. }
  312. }
  313. std::string targetName = target->GetName();
  314. if (strcmp(qtVersion, "5") == 0)
  315. {
  316. cmTarget *qt5Rcc = makefile->FindTargetToUse("Qt5::rcc");
  317. if (!qt5Rcc)
  318. {
  319. cmSystemTools::Error("Qt5::rcc target not found ",
  320. targetName.c_str());
  321. return std::string();
  322. }
  323. return qt5Rcc->ImportedGetLocation("");
  324. }
  325. else if (strcmp(qtVersion, "4") == 0)
  326. {
  327. cmTarget *qt4Rcc = makefile->FindTargetToUse("Qt4::rcc");
  328. if (!qt4Rcc)
  329. {
  330. cmSystemTools::Error("Qt4::rcc target not found ",
  331. targetName.c_str());
  332. return std::string();
  333. }
  334. return qt4Rcc->ImportedGetLocation("");
  335. }
  336. cmSystemTools::Error("The CMAKE_AUTORCC feature supports only Qt 4 and "
  337. "Qt 5 ", targetName.c_str());
  338. return std::string();
  339. }
  340. static void MergeRccOptions(std::vector<std::string> &opts,
  341. const std::vector<std::string> &fileOpts,
  342. bool isQt5)
  343. {
  344. static const char* valueOptions[] = {
  345. "name",
  346. "root",
  347. "compress",
  348. "threshold"
  349. };
  350. std::vector<std::string> extraOpts;
  351. for(std::vector<std::string>::const_iterator it = fileOpts.begin();
  352. it != fileOpts.end(); ++it)
  353. {
  354. std::vector<std::string>::iterator existingIt
  355. = std::find(opts.begin(), opts.end(), *it);
  356. if (existingIt != opts.end())
  357. {
  358. const char *o = it->c_str();
  359. if (*o == '-')
  360. {
  361. ++o;
  362. }
  363. if (isQt5 && *o == '-')
  364. {
  365. ++o;
  366. }
  367. if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
  368. cmStrCmp(*it)) != cmArrayEnd(valueOptions))
  369. {
  370. assert(existingIt + 1 != opts.end());
  371. *(existingIt + 1) = *(it + 1);
  372. ++it;
  373. }
  374. }
  375. else
  376. {
  377. extraOpts.push_back(*it);
  378. }
  379. }
  380. opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
  381. }
  382. std::string GetAutogenTargetName(
  383. cmGeneratorTarget const* target)
  384. {
  385. std::string autogenTargetName = target->GetName();
  386. autogenTargetName += "_automoc";
  387. return autogenTargetName;
  388. }
  389. std::string GetAutogenTargetDir(
  390. cmGeneratorTarget const* target)
  391. {
  392. cmMakefile* makefile = target->Target->GetMakefile();
  393. std::string targetDir = makefile->GetCurrentBinaryDirectory();
  394. targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
  395. targetDir += "/";
  396. targetDir += GetAutogenTargetName(target);
  397. targetDir += ".dir/";
  398. return targetDir;
  399. }
  400. static void copyTargetProperty(cmTarget* destinationTarget,
  401. cmTarget* sourceTarget,
  402. const std::string& propertyName)
  403. {
  404. const char* propertyValue = sourceTarget->GetProperty(propertyName);
  405. if (propertyValue)
  406. {
  407. destinationTarget->SetProperty(propertyName, propertyValue);
  408. }
  409. }
  410. static std::string cmQtAutoGeneratorsStripCR(std::string const& line)
  411. {
  412. // Strip CR characters rcc may have printed (possibly more than one!).
  413. std::string::size_type cr = line.find('\r');
  414. if (cr != line.npos)
  415. {
  416. return line.substr(0, cr);
  417. }
  418. return line;
  419. }
  420. static std::string ReadAll(const std::string& filename)
  421. {
  422. cmsys::ifstream file(filename.c_str());
  423. std::stringstream stream;
  424. stream << file.rdbuf();
  425. file.close();
  426. return stream.str();
  427. }
  428. static std::string ListQt5RccInputs(cmSourceFile* sf,
  429. cmGeneratorTarget const* target,
  430. std::vector<std::string>& depends)
  431. {
  432. std::string rccCommand
  433. = GetRccExecutable(target);
  434. std::vector<std::string> qrcEntries;
  435. std::vector<std::string> command;
  436. command.push_back(rccCommand);
  437. command.push_back("-list");
  438. std::string absFile = cmsys::SystemTools::GetRealPath(
  439. sf->GetFullPath());
  440. command.push_back(absFile);
  441. std::string rccStdOut;
  442. std::string rccStdErr;
  443. int retVal = 0;
  444. bool result = cmSystemTools::RunSingleCommand(
  445. command, &rccStdOut, &rccStdErr,
  446. &retVal, 0, cmSystemTools::OUTPUT_NONE);
  447. if (!result || retVal)
  448. {
  449. std::cerr << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath()
  450. << " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl;
  451. return std::string();
  452. }
  453. {
  454. std::istringstream ostr(rccStdOut);
  455. std::string oline;
  456. while(std::getline(ostr, oline))
  457. {
  458. oline = cmQtAutoGeneratorsStripCR(oline);
  459. if(!oline.empty())
  460. {
  461. qrcEntries.push_back(oline);
  462. }
  463. }
  464. }
  465. {
  466. std::istringstream estr(rccStdErr);
  467. std::string eline;
  468. while(std::getline(estr, eline))
  469. {
  470. eline = cmQtAutoGeneratorsStripCR(eline);
  471. if (cmHasLiteralPrefix(eline, "RCC: Error in"))
  472. {
  473. static std::string searchString = "Cannot find file '";
  474. std::string::size_type pos = eline.find(searchString);
  475. if (pos == std::string::npos)
  476. {
  477. std::cerr << "AUTOGEN: error: Rcc lists unparsable output "
  478. << eline << std::endl;
  479. return std::string();
  480. }
  481. pos += searchString.length();
  482. std::string::size_type sz = eline.size() - pos - 1;
  483. qrcEntries.push_back(eline.substr(pos, sz));
  484. }
  485. }
  486. }
  487. depends.insert(depends.end(), qrcEntries.begin(), qrcEntries.end());
  488. return cmJoin(qrcEntries, "@list_sep@");
  489. }
  490. static std::string ListQt4RccInputs(cmSourceFile* sf,
  491. std::vector<std::string>& depends)
  492. {
  493. const std::string qrcContents = ReadAll(sf->GetFullPath());
  494. cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
  495. std::string entriesList;
  496. const char* sep = "";
  497. size_t offset = 0;
  498. while (fileMatchRegex.find(qrcContents.c_str() + offset))
  499. {
  500. std::string qrcEntry = fileMatchRegex.match(1);
  501. offset += qrcEntry.size();
  502. cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
  503. fileReplaceRegex.find(qrcEntry);
  504. std::string tag = fileReplaceRegex.match(1);
  505. qrcEntry = qrcEntry.substr(tag.size());
  506. if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str()))
  507. {
  508. qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry;
  509. }
  510. entriesList += sep;
  511. entriesList += qrcEntry;
  512. sep = "@list_sep@";
  513. depends.push_back(qrcEntry);
  514. }
  515. return entriesList;
  516. }
  517. static void SetupAutoRccTarget(cmGeneratorTarget const* target)
  518. {
  519. std::string _rcc_files;
  520. const char* sepRccFiles = "";
  521. cmMakefile *makefile = target->Target->GetMakefile();
  522. std::vector<cmSourceFile*> srcFiles;
  523. target->GetConfigCommonSourceFiles(srcFiles);
  524. std::string qrcInputs;
  525. const char* qrcInputsSep = "";
  526. std::string rccFileFiles;
  527. std::string rccFileOptions;
  528. const char *optionSep = "";
  529. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  530. std::vector<std::string> rccOptions;
  531. if (const char* opts = target->GetProperty("AUTORCC_OPTIONS"))
  532. {
  533. cmSystemTools::ExpandListArgument(opts, rccOptions);
  534. }
  535. std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
  536. if (qtMajorVersion == "")
  537. {
  538. qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
  539. }
  540. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  541. fileIt != srcFiles.end();
  542. ++fileIt)
  543. {
  544. cmSourceFile* sf = *fileIt;
  545. std::string ext = sf->GetExtension();
  546. if (ext == "qrc")
  547. {
  548. std::string absFile = cmsys::SystemTools::GetRealPath(
  549. sf->GetFullPath());
  550. bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"));
  551. if (!skip)
  552. {
  553. _rcc_files += sepRccFiles;
  554. _rcc_files += absFile;
  555. sepRccFiles = ";";
  556. if (const char *prop = sf->GetProperty("AUTORCC_OPTIONS"))
  557. {
  558. std::vector<std::string> optsVec;
  559. cmSystemTools::ExpandListArgument(prop, optsVec);
  560. MergeRccOptions(rccOptions, optsVec,
  561. strcmp(qtVersion, "5") == 0);
  562. }
  563. if (!rccOptions.empty())
  564. {
  565. rccFileFiles += optionSep;
  566. rccFileFiles += absFile;
  567. rccFileOptions += optionSep;
  568. }
  569. const char *listSep = "";
  570. for(std::vector<std::string>::const_iterator it = rccOptions.begin();
  571. it != rccOptions.end();
  572. ++it)
  573. {
  574. rccFileOptions += listSep;
  575. rccFileOptions += *it;
  576. listSep = "@list_sep@";
  577. }
  578. optionSep = ";";
  579. std::vector<std::string> depends;
  580. std::string entriesList;
  581. if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")))
  582. {
  583. if (qtMajorVersion == "5")
  584. {
  585. entriesList = ListQt5RccInputs(sf, target, depends);
  586. }
  587. else
  588. {
  589. entriesList = ListQt4RccInputs(sf, depends);
  590. }
  591. if (entriesList.empty())
  592. {
  593. return;
  594. }
  595. }
  596. qrcInputs += qrcInputsSep;
  597. qrcInputs += entriesList;
  598. qrcInputsSep = ";";
  599. }
  600. }
  601. }
  602. makefile->AddDefinition("_qt_rcc_inputs_" + target->GetName(),
  603. cmOutputConverter::EscapeForCMake(qrcInputs).c_str());
  604. makefile->AddDefinition("_rcc_files",
  605. cmOutputConverter::EscapeForCMake(_rcc_files).c_str());
  606. makefile->AddDefinition("_qt_rcc_options_files",
  607. cmOutputConverter::EscapeForCMake(rccFileFiles).c_str());
  608. makefile->AddDefinition("_qt_rcc_options_options",
  609. cmOutputConverter::EscapeForCMake(rccFileOptions).c_str());
  610. makefile->AddDefinition("_qt_rcc_executable",
  611. GetRccExecutable(target).c_str());
  612. }
  613. void cmQtAutoGeneratorInitializer::InitializeAutogenSources(
  614. cmGeneratorTarget* target)
  615. {
  616. cmMakefile* makefile = target->Target->GetMakefile();
  617. if (target->GetPropertyAsBool("AUTOMOC"))
  618. {
  619. std::string automocTargetName = GetAutogenTargetName(target);
  620. std::string mocCppFile = makefile->GetCurrentBinaryDirectory();
  621. mocCppFile += "/";
  622. mocCppFile += automocTargetName;
  623. mocCppFile += ".cpp";
  624. makefile->GetOrCreateSource(mocCppFile, true);
  625. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
  626. mocCppFile.c_str(), false);
  627. target->AddSource(mocCppFile);
  628. }
  629. }
  630. void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
  631. cmLocalGenerator* lg,
  632. cmGeneratorTarget* target)
  633. {
  634. cmMakefile* makefile = target->Target->GetMakefile();
  635. std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
  636. if (qtMajorVersion == "")
  637. {
  638. qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
  639. }
  640. // create a custom target for running generators at buildtime:
  641. std::string autogenTargetName = GetAutogenTargetName(target);
  642. std::string targetDir = GetAutogenTargetDir(target);
  643. cmCustomCommandLine currentLine;
  644. currentLine.push_back(cmSystemTools::GetCMakeCommand());
  645. currentLine.push_back("-E");
  646. currentLine.push_back("cmake_autogen");
  647. currentLine.push_back(targetDir);
  648. currentLine.push_back("$<CONFIGURATION>");
  649. cmCustomCommandLines commandLines;
  650. commandLines.push_back(currentLine);
  651. std::string workingDirectory = cmSystemTools::CollapseFullPath(
  652. "", makefile->GetCurrentBinaryDirectory());
  653. std::vector<std::string> depends;
  654. if (const char *autogenDepends =
  655. target->GetProperty("AUTOGEN_TARGET_DEPENDS"))
  656. {
  657. cmSystemTools::ExpandListArgument(autogenDepends, depends);
  658. }
  659. std::vector<std::string> toolNames;
  660. if (target->GetPropertyAsBool("AUTOMOC"))
  661. {
  662. toolNames.push_back("moc");
  663. }
  664. if (target->GetPropertyAsBool("AUTOUIC"))
  665. {
  666. toolNames.push_back("uic");
  667. }
  668. if (target->GetPropertyAsBool("AUTORCC"))
  669. {
  670. toolNames.push_back("rcc");
  671. }
  672. std::string tools = toolNames[0];
  673. toolNames.erase(toolNames.begin());
  674. while (toolNames.size() > 1)
  675. {
  676. tools += ", " + toolNames[0];
  677. toolNames.erase(toolNames.begin());
  678. }
  679. if (toolNames.size() == 1)
  680. {
  681. tools += " and " + toolNames[0];
  682. }
  683. std::string autogenComment = "Automatic " + tools + " for target ";
  684. autogenComment += target->GetName();
  685. #if defined(_WIN32) && !defined(__CYGWIN__)
  686. bool usePRE_BUILD = false;
  687. cmGlobalGenerator* gg = lg->GetGlobalGenerator();
  688. if(gg->GetName().find("Visual Studio") != std::string::npos)
  689. {
  690. cmGlobalVisualStudioGenerator* vsgg =
  691. static_cast<cmGlobalVisualStudioGenerator*>(gg);
  692. // Under VS >= 7 use a PRE_BUILD event instead of a separate target to
  693. // reduce the number of targets loaded into the IDE.
  694. // This also works around a VS 11 bug that may skip updating the target:
  695. // https://connect.microsoft.com/VisualStudio/feedback/details/769495
  696. usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7;
  697. if(usePRE_BUILD)
  698. {
  699. for (std::vector<std::string>::iterator it = depends.begin();
  700. it != depends.end(); ++it)
  701. {
  702. if(!makefile->FindTargetToUse(it->c_str()))
  703. {
  704. usePRE_BUILD = false;
  705. break;
  706. }
  707. }
  708. }
  709. }
  710. #endif
  711. std::vector<std::string> rcc_output;
  712. bool const isNinja =
  713. lg->GetGlobalGenerator()->GetName() == "Ninja";
  714. if(isNinja
  715. #if defined(_WIN32) && !defined(__CYGWIN__)
  716. || usePRE_BUILD
  717. #endif
  718. )
  719. {
  720. std::vector<cmSourceFile*> srcFiles;
  721. target->GetConfigCommonSourceFiles(srcFiles);
  722. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  723. fileIt != srcFiles.end();
  724. ++fileIt)
  725. {
  726. cmSourceFile* sf = *fileIt;
  727. std::string absFile = cmsys::SystemTools::GetRealPath(
  728. sf->GetFullPath());
  729. std::string ext = sf->GetExtension();
  730. if (target->GetPropertyAsBool("AUTORCC"))
  731. {
  732. if (ext == "qrc"
  733. && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")))
  734. {
  735. std::string basename = cmsys::SystemTools::
  736. GetFilenameWithoutLastExtension(absFile);
  737. std::string rcc_output_dir = target->Target->GetSupportDirectory();
  738. cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
  739. std::string rcc_output_file = rcc_output_dir;
  740. rcc_output_file += "/qrc_" + basename + ".cpp";
  741. rcc_output.push_back(rcc_output_file);
  742. if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")))
  743. {
  744. if (qtMajorVersion == "5")
  745. {
  746. ListQt5RccInputs(sf, target, depends);
  747. }
  748. else
  749. {
  750. ListQt4RccInputs(sf, depends);
  751. }
  752. #if defined(_WIN32) && !defined(__CYGWIN__)
  753. // Cannot use PRE_BUILD because the resource files themselves
  754. // may not be sources within the target so VS may not know the
  755. // target needs to re-build at all.
  756. usePRE_BUILD = false;
  757. #endif
  758. }
  759. }
  760. }
  761. }
  762. }
  763. #if defined(_WIN32) && !defined(__CYGWIN__)
  764. if(usePRE_BUILD)
  765. {
  766. // Add the pre-build command directly to bypass the OBJECT_LIBRARY
  767. // rejection in cmMakefile::AddCustomCommandToTarget because we know
  768. // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
  769. std::vector<std::string> no_output;
  770. std::vector<std::string> no_byproducts;
  771. cmCustomCommand cc(makefile, no_output, no_byproducts, depends,
  772. commandLines, autogenComment.c_str(),
  773. workingDirectory.c_str());
  774. cc.SetEscapeOldStyle(false);
  775. cc.SetEscapeAllowMakeVars(true);
  776. target->Target->AddPreBuildCommand(cc);
  777. }
  778. else
  779. #endif
  780. {
  781. cmTarget* autogenTarget = makefile->AddUtilityCommand(
  782. autogenTargetName, true,
  783. workingDirectory.c_str(),
  784. /*byproducts=*/rcc_output, depends,
  785. commandLines, false, autogenComment.c_str());
  786. autogenTarget->Compute();
  787. cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
  788. makefile->AddGeneratorTarget(autogenTarget, gt);
  789. // Set target folder
  790. const char* autogenFolder = makefile->GetState()
  791. ->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
  792. if (!autogenFolder)
  793. {
  794. autogenFolder = makefile->GetState()
  795. ->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
  796. }
  797. if (autogenFolder && *autogenFolder)
  798. {
  799. autogenTarget->SetProperty("FOLDER", autogenFolder);
  800. }
  801. else
  802. {
  803. // inherit FOLDER property from target (#13688)
  804. copyTargetProperty(gt->Target, target->Target, "FOLDER");
  805. }
  806. target->Target->AddUtility(autogenTargetName);
  807. }
  808. }
  809. void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
  810. cmGeneratorTarget const* target)
  811. {
  812. cmMakefile* makefile = target->Target->GetMakefile();
  813. // forget the variables added here afterwards again:
  814. cmMakefile::ScopePushPop varScope(makefile);
  815. static_cast<void>(varScope);
  816. // create a custom target for running generators at buildtime:
  817. std::string autogenTargetName = GetAutogenTargetName(target);
  818. makefile->AddDefinition("_moc_target_name",
  819. cmOutputConverter::EscapeForCMake(autogenTargetName).c_str());
  820. makefile->AddDefinition("_origin_target_name",
  821. cmOutputConverter::EscapeForCMake(target->GetName()).c_str());
  822. std::string targetDir = GetAutogenTargetDir(target);
  823. const char *qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
  824. if (!qtVersion)
  825. {
  826. qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
  827. }
  828. if (const char *targetQtVersion =
  829. target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""))
  830. {
  831. qtVersion = targetQtVersion;
  832. }
  833. if (qtVersion)
  834. {
  835. makefile->AddDefinition("_target_qt_version", qtVersion);
  836. }
  837. std::vector<std::string> skipUic;
  838. std::vector<std::string> skipMoc;
  839. std::vector<std::string> mocSources;
  840. std::vector<std::string> mocHeaders;
  841. std::map<std::string, std::string> configIncludes;
  842. std::map<std::string, std::string> configDefines;
  843. std::map<std::string, std::string> configUicOptions;
  844. if (target->GetPropertyAsBool("AUTOMOC")
  845. || target->GetPropertyAsBool("AUTOUIC")
  846. || target->GetPropertyAsBool("AUTORCC"))
  847. {
  848. SetupSourceFiles(target, skipMoc, mocSources, mocHeaders, skipUic);
  849. }
  850. makefile->AddDefinition("_cpp_files",
  851. cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str());
  852. if (target->GetPropertyAsBool("AUTOMOC"))
  853. {
  854. SetupAutoMocTarget(target, autogenTargetName,
  855. skipMoc, mocHeaders,
  856. configIncludes, configDefines);
  857. }
  858. if (target->GetPropertyAsBool("AUTOUIC"))
  859. {
  860. SetupAutoUicTarget(target, skipUic, configUicOptions);
  861. }
  862. if (target->GetPropertyAsBool("AUTORCC"))
  863. {
  864. SetupAutoRccTarget(target);
  865. }
  866. const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT");
  867. std::string inputFile = cmakeRoot;
  868. inputFile += "/Modules/AutogenInfo.cmake.in";
  869. std::string outputFile = targetDir;
  870. outputFile += "/AutogenInfo.cmake";
  871. makefile->AddDefinition("_qt_rcc_inputs",
  872. makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName()));
  873. makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(),
  874. false, true, false);
  875. // Ensure we have write permission in case .in was read-only.
  876. mode_t perm = 0;
  877. #if defined(_WIN32) && !defined(__CYGWIN__)
  878. mode_t mode_write = S_IWRITE;
  879. #else
  880. mode_t mode_write = S_IWUSR;
  881. #endif
  882. cmSystemTools::GetPermissions(outputFile, perm);
  883. if (!(perm & mode_write))
  884. {
  885. cmSystemTools::SetPermissions(outputFile, perm | mode_write);
  886. }
  887. if (!configDefines.empty()
  888. || !configIncludes.empty()
  889. || !configUicOptions.empty())
  890. {
  891. cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app);
  892. if ( !infoFile )
  893. {
  894. std::string error = "Internal CMake error when trying to open file: ";
  895. error += outputFile.c_str();
  896. error += " for writing.";
  897. cmSystemTools::Error(error.c_str());
  898. return;
  899. }
  900. if (!configDefines.empty())
  901. {
  902. for (std::map<std::string, std::string>::iterator
  903. it = configDefines.begin(), end = configDefines.end();
  904. it != end; ++it)
  905. {
  906. infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first <<
  907. " " << it->second << ")\n";
  908. }
  909. }
  910. if (!configIncludes.empty())
  911. {
  912. for (std::map<std::string, std::string>::iterator
  913. it = configIncludes.begin(), end = configIncludes.end();
  914. it != end; ++it)
  915. {
  916. infoFile << "set(AM_MOC_INCLUDES_" << it->first <<
  917. " " << it->second << ")\n";
  918. }
  919. }
  920. if (!configUicOptions.empty())
  921. {
  922. for (std::map<std::string, std::string>::iterator
  923. it = configUicOptions.begin(), end = configUicOptions.end();
  924. it != end; ++it)
  925. {
  926. infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first <<
  927. " " << it->second << ")\n";
  928. }
  929. }
  930. }
  931. }