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. std::string cmQtAutoGeneratorInitializer::GetAutogenTargetName(
  94. cmTarget const* target)
  95. {
  96. std::string autogenTargetName = target->GetName();
  97. autogenTargetName += "_automoc";
  98. return autogenTargetName;
  99. }
  100. std::string cmQtAutoGeneratorInitializer::GetAutogenTargetDir(
  101. cmTarget const* target)
  102. {
  103. cmMakefile* makefile = target->GetMakefile();
  104. std::string targetDir = makefile->GetCurrentBinaryDirectory();
  105. targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
  106. targetDir += "/";
  107. targetDir += cmQtAutoGeneratorInitializer::GetAutogenTargetName(target);
  108. targetDir += ".dir/";
  109. return targetDir;
  110. }
  111. static void copyTargetProperty(cmTarget* destinationTarget,
  112. cmTarget* sourceTarget,
  113. const std::string& propertyName)
  114. {
  115. const char* propertyValue = sourceTarget->GetProperty(propertyName);
  116. if (propertyValue)
  117. {
  118. destinationTarget->SetProperty(propertyName, propertyValue);
  119. }
  120. }
  121. static std::string cmQtAutoGeneratorsStripCR(std::string const& line)
  122. {
  123. // Strip CR characters rcc may have printed (possibly more than one!).
  124. std::string::size_type cr = line.find('\r');
  125. if (cr != line.npos)
  126. {
  127. return line.substr(0, cr);
  128. }
  129. return line;
  130. }
  131. static std::string ReadAll(const std::string& filename)
  132. {
  133. cmsys::ifstream file(filename.c_str());
  134. std::stringstream stream;
  135. stream << file.rdbuf();
  136. file.close();
  137. return stream.str();
  138. }
  139. std::string cmQtAutoGeneratorInitializer::ListQt5RccInputs(cmSourceFile* sf,
  140. cmTarget const* target,
  141. std::vector<std::string>& depends)
  142. {
  143. std::string rccCommand
  144. = cmQtAutoGeneratorInitializer::GetRccExecutable(target);
  145. std::vector<std::string> qrcEntries;
  146. std::vector<std::string> command;
  147. command.push_back(rccCommand);
  148. command.push_back("-list");
  149. std::string absFile = cmsys::SystemTools::GetRealPath(
  150. sf->GetFullPath());
  151. command.push_back(absFile);
  152. std::string rccStdOut;
  153. std::string rccStdErr;
  154. int retVal = 0;
  155. bool result = cmSystemTools::RunSingleCommand(
  156. command, &rccStdOut, &rccStdErr,
  157. &retVal, 0, cmSystemTools::OUTPUT_NONE);
  158. if (!result || retVal)
  159. {
  160. std::cerr << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath()
  161. << " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl;
  162. return std::string();
  163. }
  164. {
  165. std::istringstream ostr(rccStdOut);
  166. std::string oline;
  167. while(std::getline(ostr, oline))
  168. {
  169. oline = cmQtAutoGeneratorsStripCR(oline);
  170. if(!oline.empty())
  171. {
  172. qrcEntries.push_back(oline);
  173. }
  174. }
  175. }
  176. {
  177. std::istringstream estr(rccStdErr);
  178. std::string eline;
  179. while(std::getline(estr, eline))
  180. {
  181. eline = cmQtAutoGeneratorsStripCR(eline);
  182. if (cmHasLiteralPrefix(eline, "RCC: Error in"))
  183. {
  184. static std::string searchString = "Cannot find file '";
  185. std::string::size_type pos = eline.find(searchString);
  186. if (pos == std::string::npos)
  187. {
  188. std::cerr << "AUTOGEN: error: Rcc lists unparsable output "
  189. << eline << std::endl;
  190. return std::string();
  191. }
  192. pos += searchString.length();
  193. std::string::size_type sz = eline.size() - pos - 1;
  194. qrcEntries.push_back(eline.substr(pos, sz));
  195. }
  196. }
  197. }
  198. depends.insert(depends.end(), qrcEntries.begin(), qrcEntries.end());
  199. return cmJoin(qrcEntries, "@list_sep@");
  200. }
  201. std::string cmQtAutoGeneratorInitializer::ListQt4RccInputs(cmSourceFile* sf,
  202. std::vector<std::string>& depends)
  203. {
  204. const std::string qrcContents = ReadAll(sf->GetFullPath());
  205. cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
  206. std::string entriesList;
  207. const char* sep = "";
  208. size_t offset = 0;
  209. while (fileMatchRegex.find(qrcContents.c_str() + offset))
  210. {
  211. std::string qrcEntry = fileMatchRegex.match(1);
  212. offset += qrcEntry.size();
  213. cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
  214. fileReplaceRegex.find(qrcEntry);
  215. std::string tag = fileReplaceRegex.match(1);
  216. qrcEntry = qrcEntry.substr(tag.size());
  217. if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str()))
  218. {
  219. qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry;
  220. }
  221. entriesList += sep;
  222. entriesList += qrcEntry;
  223. sep = "@list_sep@";
  224. depends.push_back(qrcEntry);
  225. }
  226. return entriesList;
  227. }
  228. void cmQtAutoGeneratorInitializer::InitializeAutogenSources(cmTarget* target)
  229. {
  230. cmMakefile* makefile = target->GetMakefile();
  231. if (target->GetPropertyAsBool("AUTOMOC"))
  232. {
  233. std::string automocTargetName =
  234. cmQtAutoGeneratorInitializer::GetAutogenTargetName(target);
  235. std::string mocCppFile = makefile->GetCurrentBinaryDirectory();
  236. mocCppFile += "/";
  237. mocCppFile += automocTargetName;
  238. mocCppFile += ".cpp";
  239. makefile->GetOrCreateSource(mocCppFile, true);
  240. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
  241. mocCppFile.c_str(), false);
  242. target->AddSource(mocCppFile);
  243. }
  244. }
  245. void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
  246. cmLocalGenerator* lg,
  247. cmTarget* target)
  248. {
  249. cmMakefile* makefile = target->GetMakefile();
  250. std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
  251. if (qtMajorVersion == "")
  252. {
  253. qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
  254. }
  255. // create a custom target for running generators at buildtime:
  256. std::string autogenTargetName =
  257. cmQtAutoGeneratorInitializer::GetAutogenTargetName(target);
  258. std::string targetDir =
  259. cmQtAutoGeneratorInitializer::GetAutogenTargetDir(target);
  260. cmCustomCommandLine currentLine;
  261. currentLine.push_back(cmSystemTools::GetCMakeCommand());
  262. currentLine.push_back("-E");
  263. currentLine.push_back("cmake_autogen");
  264. currentLine.push_back(targetDir);
  265. currentLine.push_back("$<CONFIGURATION>");
  266. cmCustomCommandLines commandLines;
  267. commandLines.push_back(currentLine);
  268. std::string workingDirectory = cmSystemTools::CollapseFullPath(
  269. "", makefile->GetCurrentBinaryDirectory());
  270. std::vector<std::string> depends;
  271. if (const char *autogenDepends =
  272. target->GetProperty("AUTOGEN_TARGET_DEPENDS"))
  273. {
  274. cmSystemTools::ExpandListArgument(autogenDepends, depends);
  275. }
  276. std::vector<std::string> toolNames;
  277. if (target->GetPropertyAsBool("AUTOMOC"))
  278. {
  279. toolNames.push_back("moc");
  280. }
  281. if (target->GetPropertyAsBool("AUTOUIC"))
  282. {
  283. toolNames.push_back("uic");
  284. }
  285. if (target->GetPropertyAsBool("AUTORCC"))
  286. {
  287. toolNames.push_back("rcc");
  288. }
  289. std::string tools = toolNames[0];
  290. toolNames.erase(toolNames.begin());
  291. while (toolNames.size() > 1)
  292. {
  293. tools += ", " + toolNames[0];
  294. toolNames.erase(toolNames.begin());
  295. }
  296. if (toolNames.size() == 1)
  297. {
  298. tools += " and " + toolNames[0];
  299. }
  300. std::string autogenComment = "Automatic " + tools + " for target ";
  301. autogenComment += target->GetName();
  302. #if defined(_WIN32) && !defined(__CYGWIN__)
  303. bool usePRE_BUILD = false;
  304. cmGlobalGenerator* gg = lg->GetGlobalGenerator();
  305. if(gg->GetName().find("Visual Studio") != std::string::npos)
  306. {
  307. cmGlobalVisualStudioGenerator* vsgg =
  308. static_cast<cmGlobalVisualStudioGenerator*>(gg);
  309. // Under VS >= 7 use a PRE_BUILD event instead of a separate target to
  310. // reduce the number of targets loaded into the IDE.
  311. // This also works around a VS 11 bug that may skip updating the target:
  312. // https://connect.microsoft.com/VisualStudio/feedback/details/769495
  313. usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7;
  314. if(usePRE_BUILD)
  315. {
  316. for (std::vector<std::string>::iterator it = depends.begin();
  317. it != depends.end(); ++it)
  318. {
  319. if(!makefile->FindTargetToUse(it->c_str()))
  320. {
  321. usePRE_BUILD = false;
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. #endif
  328. std::vector<std::string> rcc_output;
  329. bool const isNinja =
  330. lg->GetGlobalGenerator()->GetName() == "Ninja";
  331. if(isNinja
  332. #if defined(_WIN32) && !defined(__CYGWIN__)
  333. || usePRE_BUILD
  334. #endif
  335. )
  336. {
  337. std::vector<cmSourceFile*> srcFiles;
  338. cmGeneratorTarget* gtgt =
  339. lg->GetGlobalGenerator()->GetGeneratorTarget(target);
  340. gtgt->GetConfigCommonSourceFiles(srcFiles);
  341. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  342. fileIt != srcFiles.end();
  343. ++fileIt)
  344. {
  345. cmSourceFile* sf = *fileIt;
  346. std::string absFile = cmsys::SystemTools::GetRealPath(
  347. sf->GetFullPath());
  348. std::string ext = sf->GetExtension();
  349. if (target->GetPropertyAsBool("AUTORCC"))
  350. {
  351. if (ext == "qrc"
  352. && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")))
  353. {
  354. std::string basename = cmsys::SystemTools::
  355. GetFilenameWithoutLastExtension(absFile);
  356. std::string rcc_output_dir = target->GetSupportDirectory();
  357. cmSystemTools::MakeDirectory(rcc_output_dir.c_str());
  358. std::string rcc_output_file = rcc_output_dir;
  359. rcc_output_file += "/qrc_" + basename + ".cpp";
  360. rcc_output.push_back(rcc_output_file);
  361. if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")))
  362. {
  363. if (qtMajorVersion == "5")
  364. {
  365. cmQtAutoGeneratorInitializer::ListQt5RccInputs(sf, target,
  366. depends);
  367. }
  368. else
  369. {
  370. cmQtAutoGeneratorInitializer::ListQt4RccInputs(sf, depends);
  371. }
  372. #if defined(_WIN32) && !defined(__CYGWIN__)
  373. // Cannot use PRE_BUILD because the resource files themselves
  374. // may not be sources within the target so VS may not know the
  375. // target needs to re-build at all.
  376. usePRE_BUILD = false;
  377. #endif
  378. }
  379. }
  380. }
  381. }
  382. }
  383. #if defined(_WIN32) && !defined(__CYGWIN__)
  384. if(usePRE_BUILD)
  385. {
  386. // Add the pre-build command directly to bypass the OBJECT_LIBRARY
  387. // rejection in cmMakefile::AddCustomCommandToTarget because we know
  388. // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
  389. std::vector<std::string> no_output;
  390. std::vector<std::string> no_byproducts;
  391. cmCustomCommand cc(makefile, no_output, no_byproducts, depends,
  392. commandLines, autogenComment.c_str(),
  393. workingDirectory.c_str());
  394. cc.SetEscapeOldStyle(false);
  395. cc.SetEscapeAllowMakeVars(true);
  396. target->AddPreBuildCommand(cc);
  397. }
  398. else
  399. #endif
  400. {
  401. cmTarget* autogenTarget = makefile->AddUtilityCommand(
  402. autogenTargetName, true,
  403. workingDirectory.c_str(),
  404. /*byproducts=*/rcc_output, depends,
  405. commandLines, false, autogenComment.c_str());
  406. cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
  407. makefile->AddGeneratorTarget(autogenTarget, gt);
  408. // Set target folder
  409. const char* autogenFolder = makefile->GetState()
  410. ->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
  411. if (!autogenFolder)
  412. {
  413. autogenFolder = makefile->GetState()
  414. ->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
  415. }
  416. if (autogenFolder && *autogenFolder)
  417. {
  418. autogenTarget->SetProperty("FOLDER", autogenFolder);
  419. }
  420. else
  421. {
  422. // inherit FOLDER property from target (#13688)
  423. copyTargetProperty(autogenTarget, target, "FOLDER");
  424. }
  425. target->AddUtility(autogenTargetName);
  426. }
  427. }
  428. static void GetCompileDefinitionsAndDirectories(cmTarget const* target,
  429. const std::string& config,
  430. std::string &incs,
  431. std::string &defs)
  432. {
  433. cmMakefile* makefile = target->GetMakefile();
  434. cmGlobalGenerator* globalGen = makefile->GetGlobalGenerator();
  435. std::vector<std::string> includeDirs;
  436. cmGeneratorTarget *gtgt = globalGen->GetGeneratorTarget(target);
  437. cmLocalGenerator *localGen = gtgt->GetLocalGenerator();
  438. // Get the include dirs for this target, without stripping the implicit
  439. // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
  440. localGen->GetIncludeDirectories(includeDirs, gtgt, "CXX", config, false);
  441. incs = cmJoin(includeDirs, ";");
  442. std::set<std::string> defines;
  443. localGen->AddCompileDefinitions(defines, target, config, "CXX");
  444. defs += cmJoin(defines, ";");
  445. }
  446. void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
  447. cmTarget const* target)
  448. {
  449. cmMakefile* makefile = target->GetMakefile();
  450. // forget the variables added here afterwards again:
  451. cmMakefile::ScopePushPop varScope(makefile);
  452. static_cast<void>(varScope);
  453. // create a custom target for running generators at buildtime:
  454. std::string autogenTargetName =
  455. cmQtAutoGeneratorInitializer::GetAutogenTargetName(target);
  456. makefile->AddDefinition("_moc_target_name",
  457. cmOutputConverter::EscapeForCMake(autogenTargetName).c_str());
  458. makefile->AddDefinition("_origin_target_name",
  459. cmOutputConverter::EscapeForCMake(target->GetName()).c_str());
  460. std::string targetDir =
  461. cmQtAutoGeneratorInitializer::GetAutogenTargetDir(target);
  462. const char *qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
  463. if (!qtVersion)
  464. {
  465. qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
  466. }
  467. cmGeneratorTarget *gtgt = target->GetMakefile()
  468. ->GetGlobalGenerator()
  469. ->GetGeneratorTarget(target);
  470. if (const char *targetQtVersion =
  471. gtgt->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""))
  472. {
  473. qtVersion = targetQtVersion;
  474. }
  475. if (qtVersion)
  476. {
  477. makefile->AddDefinition("_target_qt_version", qtVersion);
  478. }
  479. std::vector<std::string> skipUic;
  480. std::vector<std::string> skipMoc;
  481. std::vector<std::string> mocSources;
  482. std::vector<std::string> mocHeaders;
  483. std::map<std::string, std::string> configIncludes;
  484. std::map<std::string, std::string> configDefines;
  485. std::map<std::string, std::string> configUicOptions;
  486. if (target->GetPropertyAsBool("AUTOMOC")
  487. || target->GetPropertyAsBool("AUTOUIC")
  488. || target->GetPropertyAsBool("AUTORCC"))
  489. {
  490. cmQtAutoGeneratorInitializer::SetupSourceFiles(target, skipMoc,
  491. mocSources, mocHeaders, skipUic);
  492. }
  493. makefile->AddDefinition("_cpp_files",
  494. cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str());
  495. if (target->GetPropertyAsBool("AUTOMOC"))
  496. {
  497. cmQtAutoGeneratorInitializer::SetupAutoMocTarget(target, autogenTargetName,
  498. skipMoc, mocHeaders,
  499. configIncludes, configDefines);
  500. }
  501. if (target->GetPropertyAsBool("AUTOUIC"))
  502. {
  503. cmQtAutoGeneratorInitializer::SetupAutoUicTarget(target, skipUic,
  504. configUicOptions);
  505. }
  506. if (target->GetPropertyAsBool("AUTORCC"))
  507. {
  508. cmQtAutoGeneratorInitializer::SetupAutoRccTarget(target);
  509. }
  510. const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT");
  511. std::string inputFile = cmakeRoot;
  512. inputFile += "/Modules/AutogenInfo.cmake.in";
  513. std::string outputFile = targetDir;
  514. outputFile += "/AutogenInfo.cmake";
  515. makefile->AddDefinition("_qt_rcc_inputs",
  516. makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName()));
  517. makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(),
  518. false, true, false);
  519. // Ensure we have write permission in case .in was read-only.
  520. mode_t perm = 0;
  521. #if defined(_WIN32) && !defined(__CYGWIN__)
  522. mode_t mode_write = S_IWRITE;
  523. #else
  524. mode_t mode_write = S_IWUSR;
  525. #endif
  526. cmSystemTools::GetPermissions(outputFile, perm);
  527. if (!(perm & mode_write))
  528. {
  529. cmSystemTools::SetPermissions(outputFile, perm | mode_write);
  530. }
  531. if (!configDefines.empty()
  532. || !configIncludes.empty()
  533. || !configUicOptions.empty())
  534. {
  535. cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app);
  536. if ( !infoFile )
  537. {
  538. std::string error = "Internal CMake error when trying to open file: ";
  539. error += outputFile.c_str();
  540. error += " for writing.";
  541. cmSystemTools::Error(error.c_str());
  542. return;
  543. }
  544. if (!configDefines.empty())
  545. {
  546. for (std::map<std::string, std::string>::iterator
  547. it = configDefines.begin(), end = configDefines.end();
  548. it != end; ++it)
  549. {
  550. infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first <<
  551. " " << it->second << ")\n";
  552. }
  553. }
  554. if (!configIncludes.empty())
  555. {
  556. for (std::map<std::string, std::string>::iterator
  557. it = configIncludes.begin(), end = configIncludes.end();
  558. it != end; ++it)
  559. {
  560. infoFile << "set(AM_MOC_INCLUDES_" << it->first <<
  561. " " << it->second << ")\n";
  562. }
  563. }
  564. if (!configUicOptions.empty())
  565. {
  566. for (std::map<std::string, std::string>::iterator
  567. it = configUicOptions.begin(), end = configUicOptions.end();
  568. it != end; ++it)
  569. {
  570. infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first <<
  571. " " << it->second << ")\n";
  572. }
  573. }
  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. }