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