cmQtAutoGeneratorInitializer.cxx 35 KB

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