cmQtAutoGenerators.cxx 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  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 "cmGlobalGenerator.h"
  12. #include "cmOutputConverter.h"
  13. #include "cmMakefile.h"
  14. #include "cmSystemTools.h"
  15. #include "cmState.h"
  16. #include "cmAlgorithms.h"
  17. #include <sys/stat.h>
  18. #include <cmsys/Terminal.h>
  19. #include <cmsys/FStream.hxx>
  20. #include <assert.h>
  21. #include <string.h>
  22. #if defined(__APPLE__)
  23. #include <unistd.h>
  24. #endif
  25. #include "cmQtAutoGenerators.h"
  26. static bool requiresMocing(const std::string& text, std::string &macroName)
  27. {
  28. // this simple check is much much faster than the regexp
  29. if (strstr(text.c_str(), "Q_OBJECT") == NULL
  30. && strstr(text.c_str(), "Q_GADGET") == NULL)
  31. {
  32. return false;
  33. }
  34. cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
  35. if (qObjectRegExp.find(text))
  36. {
  37. macroName = "Q_OBJECT";
  38. return true;
  39. }
  40. cmsys::RegularExpression qGadgetRegExp("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]");
  41. if (qGadgetRegExp.find(text))
  42. {
  43. macroName = "Q_GADGET";
  44. return true;
  45. }
  46. return false;
  47. }
  48. static std::string findMatchingHeader(const std::string& absPath,
  49. const std::string& mocSubDir,
  50. const std::string& basename,
  51. const std::vector<std::string>& headerExtensions)
  52. {
  53. std::string header;
  54. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  55. ext != headerExtensions.end();
  56. ++ext)
  57. {
  58. std::string sourceFilePath = absPath + basename + "." + (*ext);
  59. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
  60. {
  61. header = sourceFilePath;
  62. break;
  63. }
  64. if (!mocSubDir.empty())
  65. {
  66. sourceFilePath = mocSubDir + basename + "." + (*ext);
  67. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
  68. {
  69. header = sourceFilePath;
  70. break;
  71. }
  72. }
  73. }
  74. return header;
  75. }
  76. static std::string extractSubDir(const std::string& absPath,
  77. const std::string& currentMoc)
  78. {
  79. std::string subDir;
  80. if (currentMoc.find_first_of('/') != std::string::npos)
  81. {
  82. subDir = absPath
  83. + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
  84. }
  85. return subDir;
  86. }
  87. cmQtAutoGenerators::cmQtAutoGenerators()
  88. :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
  89. ,ColorOutput(true)
  90. ,RunMocFailed(false)
  91. ,RunUicFailed(false)
  92. ,RunRccFailed(false)
  93. ,GenerateAll(false)
  94. {
  95. std::string colorEnv = "";
  96. cmsys::SystemTools::GetEnv("COLOR", colorEnv);
  97. if(!colorEnv.empty())
  98. {
  99. if(cmSystemTools::IsOn(colorEnv.c_str()))
  100. {
  101. this->ColorOutput = true;
  102. }
  103. else
  104. {
  105. this->ColorOutput = false;
  106. }
  107. }
  108. }
  109. void cmQtAutoGenerators::MergeUicOptions(std::vector<std::string> &opts,
  110. const std::vector<std::string> &fileOpts,
  111. bool isQt5)
  112. {
  113. static const char* valueOptions[] = {
  114. "tr",
  115. "translate",
  116. "postfix",
  117. "generator",
  118. "include", // Since Qt 5.3
  119. "g"
  120. };
  121. std::vector<std::string> extraOpts;
  122. for(std::vector<std::string>::const_iterator it = fileOpts.begin();
  123. it != fileOpts.end(); ++it)
  124. {
  125. std::vector<std::string>::iterator existingIt
  126. = std::find(opts.begin(), opts.end(), *it);
  127. if (existingIt != opts.end())
  128. {
  129. const char *o = it->c_str();
  130. if (*o == '-')
  131. {
  132. ++o;
  133. }
  134. if (isQt5 && *o == '-')
  135. {
  136. ++o;
  137. }
  138. if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
  139. cmStrCmp(*it)) != cmArrayEnd(valueOptions))
  140. {
  141. assert(existingIt + 1 != opts.end());
  142. *(existingIt + 1) = *(it + 1);
  143. ++it;
  144. }
  145. }
  146. else
  147. {
  148. extraOpts.push_back(*it);
  149. }
  150. }
  151. opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
  152. }
  153. bool cmQtAutoGenerators::Run(const std::string& targetDirectory,
  154. const std::string& config)
  155. {
  156. bool success = true;
  157. cmake cm;
  158. cm.SetHomeOutputDirectory(targetDirectory);
  159. cm.SetHomeDirectory(targetDirectory);
  160. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  161. cmGlobalGenerator gg(&cm);
  162. cmState::Snapshot snapshot = cm.GetCurrentSnapshot();
  163. snapshot.GetDirectory().SetCurrentBinary(targetDirectory);
  164. snapshot.GetDirectory().SetCurrentSource(targetDirectory);
  165. cmsys::auto_ptr<cmMakefile> mf(new cmMakefile(&gg, snapshot));
  166. gg.SetCurrentMakefile(mf.get());
  167. this->ReadAutogenInfoFile(mf.get(), targetDirectory, config);
  168. this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory);
  169. this->Init();
  170. if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5")
  171. {
  172. success = this->RunAutogen(mf.get());
  173. }
  174. this->WriteOldMocDefinitionsFile(targetDirectory);
  175. return success;
  176. }
  177. bool cmQtAutoGenerators::ReadAutogenInfoFile(cmMakefile* makefile,
  178. const std::string& targetDirectory,
  179. const std::string& config)
  180. {
  181. std::string filename(
  182. cmSystemTools::CollapseFullPath(targetDirectory));
  183. cmSystemTools::ConvertToUnixSlashes(filename);
  184. filename += "/AutogenInfo.cmake";
  185. if (!makefile->ReadListFile(filename.c_str()))
  186. {
  187. cmSystemTools::Error("Error processing file: ", filename.c_str());
  188. return false;
  189. }
  190. this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
  191. if (this->QtMajorVersion == "")
  192. {
  193. this->QtMajorVersion = makefile->GetSafeDefinition(
  194. "AM_Qt5Core_VERSION_MAJOR");
  195. }
  196. this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
  197. {
  198. std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
  199. cmSystemTools::ExpandListArgument(rccSources, this->RccSources);
  200. }
  201. this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
  202. this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
  203. this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
  204. this->IncludeProjectDirsBefore = makefile->IsOn(
  205. "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
  206. this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
  207. this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
  208. this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
  209. this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE");
  210. this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE");
  211. {
  212. std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS";
  213. std::string compileDefsProp = compileDefsPropOrig;
  214. if(!config.empty())
  215. {
  216. compileDefsProp += "_";
  217. compileDefsProp += config;
  218. }
  219. const char *compileDefs = makefile->GetDefinition(compileDefsProp);
  220. this->MocCompileDefinitionsStr = compileDefs ? compileDefs
  221. : makefile->GetSafeDefinition(compileDefsPropOrig);
  222. }
  223. {
  224. std::string includesPropOrig = "AM_MOC_INCLUDES";
  225. std::string includesProp = includesPropOrig;
  226. if(!config.empty())
  227. {
  228. includesProp += "_";
  229. includesProp += config;
  230. }
  231. const char *includes = makefile->GetDefinition(includesProp);
  232. this->MocIncludesStr = includes ? includes
  233. : makefile->GetSafeDefinition(includesPropOrig);
  234. }
  235. this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  236. this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
  237. this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
  238. this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
  239. this->OriginTargetName
  240. = makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME");
  241. {
  242. const char *uicOptionsFiles
  243. = makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES");
  244. std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS";
  245. std::string uicOptionsProp = uicOptionsPropOrig;
  246. if(!config.empty())
  247. {
  248. uicOptionsProp += "_";
  249. uicOptionsProp += config;
  250. }
  251. const char *uicTargetOptions
  252. = makefile->GetSafeDefinition(uicOptionsProp);
  253. cmSystemTools::ExpandListArgument(
  254. uicTargetOptions ? uicTargetOptions
  255. : makefile->GetSafeDefinition(uicOptionsPropOrig),
  256. this->UicTargetOptions);
  257. const char *uicOptionsOptions
  258. = makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS");
  259. std::vector<std::string> uicFilesVec;
  260. cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec);
  261. std::vector<std::string> uicOptionsVec;
  262. cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec);
  263. if (uicFilesVec.size() != uicOptionsVec.size())
  264. {
  265. return false;
  266. }
  267. for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(),
  268. optionIt = uicOptionsVec.begin();
  269. fileIt != uicFilesVec.end();
  270. ++fileIt, ++optionIt)
  271. {
  272. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  273. this->UicOptions[*fileIt] = *optionIt;
  274. }
  275. }
  276. {
  277. const char *rccOptionsFiles
  278. = makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES");
  279. const char *rccOptionsOptions
  280. = makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS");
  281. std::vector<std::string> rccFilesVec;
  282. cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec);
  283. std::vector<std::string> rccOptionsVec;
  284. cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec);
  285. if (rccFilesVec.size() != rccOptionsVec.size())
  286. {
  287. return false;
  288. }
  289. for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(),
  290. optionIt = rccOptionsVec.begin();
  291. fileIt != rccFilesVec.end();
  292. ++fileIt, ++optionIt)
  293. {
  294. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  295. this->RccOptions[*fileIt] = *optionIt;
  296. }
  297. const char *rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS");
  298. std::vector<std::string> rccInputLists;
  299. cmSystemTools::ExpandListArgument(rccInputs, rccInputLists);
  300. if (this->RccSources.size() != rccInputLists.size())
  301. {
  302. cmSystemTools::Error("Error processing file: ", filename.c_str());
  303. return false;
  304. }
  305. for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(),
  306. inputIt = rccInputLists.begin();
  307. fileIt != this->RccSources.end();
  308. ++fileIt, ++inputIt)
  309. {
  310. cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";");
  311. std::vector<std::string> rccInputFiles;
  312. cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles);
  313. this->RccInputs[*fileIt] = rccInputFiles;
  314. }
  315. }
  316. this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
  317. this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE");
  318. return true;
  319. }
  320. std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile)
  321. {
  322. std::string s;
  323. s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS");
  324. s += " ~~~ ";
  325. s += makefile->GetSafeDefinition("AM_MOC_INCLUDES");
  326. s += " ~~~ ";
  327. s += makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  328. s += " ~~~ ";
  329. s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE"
  330. : "FALSE";
  331. s += " ~~~ ";
  332. return s;
  333. }
  334. bool cmQtAutoGenerators::ReadOldMocDefinitionsFile(cmMakefile* makefile,
  335. const std::string& targetDirectory)
  336. {
  337. std::string filename(
  338. cmSystemTools::CollapseFullPath(targetDirectory));
  339. cmSystemTools::ConvertToUnixSlashes(filename);
  340. filename += "/AutomocOldMocDefinitions.cmake";
  341. if (makefile->ReadListFile(filename.c_str()))
  342. {
  343. this->OldCompileSettingsStr =
  344. makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
  345. }
  346. return true;
  347. }
  348. void
  349. cmQtAutoGenerators::WriteOldMocDefinitionsFile(
  350. const std::string& targetDirectory)
  351. {
  352. std::string filename(
  353. cmSystemTools::CollapseFullPath(targetDirectory));
  354. cmSystemTools::ConvertToUnixSlashes(filename);
  355. filename += "/AutomocOldMocDefinitions.cmake";
  356. cmsys::ofstream outfile;
  357. outfile.open(filename.c_str(),
  358. std::ios::trunc);
  359. outfile << "set(AM_OLD_COMPILE_SETTINGS "
  360. << cmOutputConverter::EscapeForCMake(
  361. this->CurrentCompileSettingsStr) << ")\n";
  362. outfile.close();
  363. }
  364. void cmQtAutoGenerators::Init()
  365. {
  366. this->OutMocCppFilename = this->Builddir;
  367. this->OutMocCppFilename += this->TargetName;
  368. this->OutMocCppFilename += ".cpp";
  369. std::vector<std::string> cdefList;
  370. cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
  371. for(std::vector<std::string>::const_iterator it = cdefList.begin();
  372. it != cdefList.end();
  373. ++it)
  374. {
  375. this->MocDefinitions.push_back("-D" + (*it));
  376. }
  377. cmSystemTools::ExpandListArgument(this->MocOptionsStr, this->MocOptions);
  378. std::vector<std::string> incPaths;
  379. cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths);
  380. std::set<std::string> frameworkPaths;
  381. for(std::vector<std::string>::const_iterator it = incPaths.begin();
  382. it != incPaths.end();
  383. ++it)
  384. {
  385. const std::string &path = *it;
  386. this->MocIncludes.push_back("-I" + path);
  387. if (cmHasLiteralSuffix(path, ".framework/Headers"))
  388. {
  389. // Go up twice to get to the framework root
  390. std::vector<std::string> pathComponents;
  391. cmsys::SystemTools::SplitPath(path, pathComponents);
  392. std::string frameworkPath =cmsys::SystemTools::JoinPath(
  393. pathComponents.begin(), pathComponents.end() - 2);
  394. frameworkPaths.insert(frameworkPath);
  395. }
  396. }
  397. for (std::set<std::string>::const_iterator it = frameworkPaths.begin();
  398. it != frameworkPaths.end(); ++it)
  399. {
  400. this->MocIncludes.push_back("-F");
  401. this->MocIncludes.push_back(*it);
  402. }
  403. if (this->IncludeProjectDirsBefore)
  404. {
  405. const std::string binDir = "-I" + this->ProjectBinaryDir;
  406. const std::string srcDir = "-I" + this->ProjectSourceDir;
  407. std::list<std::string> sortedMocIncludes;
  408. std::list<std::string>::iterator it = this->MocIncludes.begin();
  409. while (it != this->MocIncludes.end())
  410. {
  411. if (this->StartsWith(*it, binDir))
  412. {
  413. sortedMocIncludes.push_back(*it);
  414. it = this->MocIncludes.erase(it);
  415. }
  416. else
  417. {
  418. ++it;
  419. }
  420. }
  421. it = this->MocIncludes.begin();
  422. while (it != this->MocIncludes.end())
  423. {
  424. if (this->StartsWith(*it, srcDir))
  425. {
  426. sortedMocIncludes.push_back(*it);
  427. it = this->MocIncludes.erase(it);
  428. }
  429. else
  430. {
  431. ++it;
  432. }
  433. }
  434. sortedMocIncludes.insert(sortedMocIncludes.end(),
  435. this->MocIncludes.begin(), this->MocIncludes.end());
  436. this->MocIncludes = sortedMocIncludes;
  437. }
  438. }
  439. static std::string ReadAll(const std::string& filename)
  440. {
  441. cmsys::ifstream file(filename.c_str());
  442. std::stringstream stream;
  443. stream << file.rdbuf();
  444. file.close();
  445. return stream.str();
  446. }
  447. bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
  448. {
  449. if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str())
  450. || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr))
  451. {
  452. this->GenerateAll = true;
  453. }
  454. // the program goes through all .cpp files to see which moc files are
  455. // included. It is not really interesting how the moc file is named, but
  456. // what file the moc is created from. Once a moc is included the same moc
  457. // may not be included in the _automoc.cpp file anymore. OTOH if there's a
  458. // header containing Q_OBJECT where no corresponding moc file is included
  459. // anywhere a moc_<filename>.cpp file is created and included in
  460. // the _automoc.cpp file.
  461. // key = moc source filepath, value = moc output filepath
  462. std::map<std::string, std::string> includedMocs;
  463. // collect all headers which may need to be mocced
  464. std::set<std::string> headerFiles;
  465. std::vector<std::string> sourceFiles;
  466. cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
  467. const std::vector<std::string>& headerExtensions =
  468. makefile->GetCMakeInstance()->GetHeaderExtensions();
  469. std::map<std::string, std::vector<std::string> > includedUis;
  470. std::map<std::string, std::vector<std::string> > skippedUis;
  471. std::vector<std::string> uicSkipped;
  472. cmSystemTools::ExpandListArgument(this->SkipUic, uicSkipped);
  473. for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
  474. it != sourceFiles.end();
  475. ++it)
  476. {
  477. const bool skipUic = std::find(uicSkipped.begin(), uicSkipped.end(), *it)
  478. != uicSkipped.end();
  479. std::map<std::string, std::vector<std::string> >& uiFiles
  480. = skipUic ? skippedUis : includedUis;
  481. const std::string &absFilename = *it;
  482. if (this->Verbose)
  483. {
  484. std::cout << "AUTOGEN: Checking " << absFilename << std::endl;
  485. }
  486. if (this->RelaxedMode)
  487. {
  488. this->ParseCppFile(absFilename, headerExtensions, includedMocs,
  489. uiFiles);
  490. }
  491. else
  492. {
  493. this->StrictParseCppFile(absFilename, headerExtensions, includedMocs,
  494. uiFiles);
  495. }
  496. this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
  497. }
  498. {
  499. std::vector<std::string> mocSkipped;
  500. cmSystemTools::ExpandListArgument(this->SkipMoc, mocSkipped);
  501. for (std::vector<std::string>::const_iterator it = mocSkipped.begin();
  502. it != mocSkipped.end();
  503. ++it)
  504. {
  505. if (std::find(uicSkipped.begin(), uicSkipped.end(), *it)
  506. != uicSkipped.end())
  507. {
  508. const std::string &absFilename = *it;
  509. if (this->Verbose)
  510. {
  511. std::cout << "AUTOGEN: Checking " << absFilename << std::endl;
  512. }
  513. this->ParseForUic(absFilename, includedUis);
  514. }
  515. }
  516. }
  517. std::vector<std::string> headerFilesVec;
  518. cmSystemTools::ExpandListArgument(this->Headers, headerFilesVec);
  519. headerFiles.insert(headerFilesVec.begin(), headerFilesVec.end());
  520. // key = moc source filepath, value = moc output filename
  521. std::map<std::string, std::string> notIncludedMocs;
  522. this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
  523. // run moc on all the moc's that are #included in source files
  524. for(std::map<std::string, std::string>::const_iterator
  525. it = includedMocs.begin();
  526. it != includedMocs.end();
  527. ++it)
  528. {
  529. this->GenerateMoc(it->first, it->second);
  530. }
  531. for(std::map<std::string, std::vector<std::string> >::const_iterator
  532. it = includedUis.begin();
  533. it != includedUis.end();
  534. ++it)
  535. {
  536. for (std::vector<std::string>::const_iterator nit = it->second.begin();
  537. nit != it->second.end();
  538. ++nit)
  539. {
  540. this->GenerateUi(it->first, *nit);
  541. }
  542. }
  543. if(!this->RccExecutable.empty())
  544. {
  545. this->GenerateQrc();
  546. }
  547. std::stringstream outStream;
  548. outStream << "/* This file is autogenerated, do not edit*/\n";
  549. bool automocCppChanged = false;
  550. if (notIncludedMocs.empty())
  551. {
  552. outStream << "enum some_compilers { need_more_than_nothing };\n";
  553. }
  554. else
  555. {
  556. // run moc on the remaining headers and include them in
  557. // the _automoc.cpp file
  558. for(std::map<std::string, std::string>::const_iterator
  559. it = notIncludedMocs.begin();
  560. it != notIncludedMocs.end();
  561. ++it)
  562. {
  563. bool mocSuccess = this->GenerateMoc(it->first, it->second);
  564. if (mocSuccess)
  565. {
  566. automocCppChanged = true;
  567. }
  568. outStream << "#include \"" << it->second << "\"\n";
  569. }
  570. }
  571. if (this->RunMocFailed)
  572. {
  573. std::cerr << "moc failed..." << std::endl;
  574. return false;
  575. }
  576. if (this->RunUicFailed)
  577. {
  578. std::cerr << "uic failed..." << std::endl;
  579. return false;
  580. }
  581. if (this->RunRccFailed)
  582. {
  583. std::cerr << "rcc failed..." << std::endl;
  584. return false;
  585. }
  586. outStream.flush();
  587. std::string automocSource = outStream.str();
  588. if (!automocCppChanged)
  589. {
  590. // compare contents of the _automoc.cpp file
  591. const std::string oldContents = ReadAll(this->OutMocCppFilename);
  592. if (oldContents == automocSource)
  593. {
  594. // nothing changed: don't touch the _automoc.cpp file
  595. return true;
  596. }
  597. }
  598. // source file that includes all remaining moc files (_automoc.cpp file)
  599. cmsys::ofstream outfile;
  600. outfile.open(this->OutMocCppFilename.c_str(),
  601. std::ios::trunc);
  602. outfile << automocSource;
  603. outfile.close();
  604. return true;
  605. }
  606. void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
  607. const std::vector<std::string>& headerExtensions,
  608. std::map<std::string, std::string>& includedMocs,
  609. std::map<std::string, std::vector<std::string> > &includedUis)
  610. {
  611. cmsys::RegularExpression mocIncludeRegExp(
  612. "[\n][ \t]*#[ \t]*include[ \t]+"
  613. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  614. const std::string contentsString = ReadAll(absFilename);
  615. if (contentsString.empty())
  616. {
  617. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  618. << std::endl;
  619. return;
  620. }
  621. this->ParseForUic(absFilename, contentsString, includedUis);
  622. if (this->MocExecutable.empty())
  623. {
  624. return;
  625. }
  626. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  627. cmsys::SystemTools::GetRealPath(absFilename)) + '/';
  628. const std::string scannedFileBasename = cmsys::SystemTools::
  629. GetFilenameWithoutLastExtension(absFilename);
  630. std::string macroName;
  631. const bool requiresMoc = requiresMocing(contentsString, macroName);
  632. bool dotMocIncluded = false;
  633. bool mocUnderscoreIncluded = false;
  634. std::string ownMocUnderscoreFile;
  635. std::string ownDotMocFile;
  636. std::string ownMocHeaderFile;
  637. std::string::size_type matchOffset = 0;
  638. // first a simple string check for "moc" is *much* faster than the regexp,
  639. // and if the string search already fails, we don't have to try the
  640. // expensive regexp
  641. if ((strstr(contentsString.c_str(), "moc") != NULL)
  642. && (mocIncludeRegExp.find(contentsString)))
  643. {
  644. // for every moc include in the file
  645. do
  646. {
  647. const std::string currentMoc = mocIncludeRegExp.match(1);
  648. //std::cout << "found moc include: " << currentMoc << std::endl;
  649. std::string basename = cmsys::SystemTools::
  650. GetFilenameWithoutLastExtension(currentMoc);
  651. const bool moc_style = cmHasLiteralPrefix(basename, "moc_");
  652. // If the moc include is of the moc_foo.cpp style we expect
  653. // the Q_OBJECT class declaration in a header file.
  654. // If the moc include is of the foo.moc style we need to look for
  655. // a Q_OBJECT macro in the current source file, if it contains the
  656. // macro we generate the moc file from the source file.
  657. // Q_OBJECT
  658. if (moc_style)
  659. {
  660. // basename should be the part of the moc filename used for
  661. // finding the correct header, so we need to remove the moc_ part
  662. basename = basename.substr(4);
  663. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  664. std::string headerToMoc = findMatchingHeader(
  665. absPath, mocSubDir, basename, headerExtensions);
  666. if (!headerToMoc.empty())
  667. {
  668. includedMocs[headerToMoc] = currentMoc;
  669. if (basename == scannedFileBasename)
  670. {
  671. mocUnderscoreIncluded = true;
  672. ownMocUnderscoreFile = currentMoc;
  673. ownMocHeaderFile = headerToMoc;
  674. }
  675. }
  676. else
  677. {
  678. std::cerr << "AUTOGEN: error: " << absFilename << ": The file "
  679. << "includes the moc file \"" << currentMoc << "\", "
  680. << "but could not find header \"" << basename
  681. << '{' << this->Join(headerExtensions, ',') << "}\" ";
  682. if (mocSubDir.empty())
  683. {
  684. std::cerr << "in " << absPath << "\n" << std::endl;
  685. }
  686. else
  687. {
  688. std::cerr << "neither in " << absPath
  689. << " nor in " << mocSubDir << "\n" << std::endl;
  690. }
  691. ::exit(EXIT_FAILURE);
  692. }
  693. }
  694. else
  695. {
  696. std::string fileToMoc = absFilename;
  697. if ((basename != scannedFileBasename) || (requiresMoc==false))
  698. {
  699. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  700. std::string headerToMoc = findMatchingHeader(
  701. absPath, mocSubDir, basename, headerExtensions);
  702. if (!headerToMoc.empty())
  703. {
  704. // this is for KDE4 compatibility:
  705. fileToMoc = headerToMoc;
  706. if ((requiresMoc==false) &&(basename==scannedFileBasename))
  707. {
  708. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  709. "includes the moc file \"" << currentMoc <<
  710. "\", but does not contain a " << macroName
  711. << " macro. Running moc on "
  712. << "\"" << headerToMoc << "\" ! Include \"moc_"
  713. << basename << ".cpp\" for a compatiblity with "
  714. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  715. << std::endl;
  716. }
  717. else
  718. {
  719. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  720. "includes the moc file \"" << currentMoc <<
  721. "\" instead of \"moc_" << basename << ".cpp\". "
  722. "Running moc on "
  723. << "\"" << headerToMoc << "\" ! Include \"moc_"
  724. << basename << ".cpp\" for compatiblity with "
  725. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  726. << std::endl;
  727. }
  728. }
  729. else
  730. {
  731. std::cerr <<"AUTOGEN: error: " << absFilename << ": The file "
  732. "includes the moc file \"" << currentMoc <<
  733. "\", which seems to be the moc file from a different "
  734. "source file. CMake also could not find a matching "
  735. "header.\n" << std::endl;
  736. ::exit(EXIT_FAILURE);
  737. }
  738. }
  739. else
  740. {
  741. dotMocIncluded = true;
  742. ownDotMocFile = currentMoc;
  743. }
  744. includedMocs[fileToMoc] = currentMoc;
  745. }
  746. matchOffset += mocIncludeRegExp.end();
  747. } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  748. }
  749. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  750. // If this is the case, the moc_foo.cpp should probably be generated from
  751. // foo.cpp instead of foo.h, because otherwise it won't build.
  752. // But warn, since this is not how it is supposed to be used.
  753. if ((dotMocIncluded == false) && (requiresMoc == true))
  754. {
  755. if (mocUnderscoreIncluded == true)
  756. {
  757. // this is for KDE4 compatibility:
  758. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  759. << "contains a " << macroName << " macro, but does not "
  760. "include "
  761. << "\"" << scannedFileBasename << ".moc\", but instead "
  762. "includes "
  763. << "\"" << ownMocUnderscoreFile << "\". Running moc on "
  764. << "\"" << absFilename << "\" ! Better include \""
  765. << scannedFileBasename << ".moc\" for compatiblity with "
  766. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  767. << std::endl;
  768. includedMocs[absFilename] = ownMocUnderscoreFile;
  769. includedMocs.erase(ownMocHeaderFile);
  770. }
  771. else
  772. {
  773. // otherwise always error out since it will not compile:
  774. std::cerr << "AUTOGEN: error: " << absFilename << ": The file "
  775. << "contains a " << macroName << " macro, but does not "
  776. "include "
  777. << "\"" << scannedFileBasename << ".moc\" !\n"
  778. << std::endl;
  779. ::exit(EXIT_FAILURE);
  780. }
  781. }
  782. }
  783. void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
  784. const std::vector<std::string>& headerExtensions,
  785. std::map<std::string, std::string>& includedMocs,
  786. std::map<std::string, std::vector<std::string> >& includedUis)
  787. {
  788. cmsys::RegularExpression mocIncludeRegExp(
  789. "[\n][ \t]*#[ \t]*include[ \t]+"
  790. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  791. const std::string contentsString = ReadAll(absFilename);
  792. if (contentsString.empty())
  793. {
  794. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  795. << std::endl;
  796. return;
  797. }
  798. this->ParseForUic(absFilename, contentsString, includedUis);
  799. if (this->MocExecutable.empty())
  800. {
  801. return;
  802. }
  803. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  804. cmsys::SystemTools::GetRealPath(absFilename)) + '/';
  805. const std::string scannedFileBasename = cmsys::SystemTools::
  806. GetFilenameWithoutLastExtension(absFilename);
  807. bool dotMocIncluded = false;
  808. std::string::size_type matchOffset = 0;
  809. // first a simple string check for "moc" is *much* faster than the regexp,
  810. // and if the string search already fails, we don't have to try the
  811. // expensive regexp
  812. if ((strstr(contentsString.c_str(), "moc") != NULL)
  813. && (mocIncludeRegExp.find(contentsString)))
  814. {
  815. // for every moc include in the file
  816. do
  817. {
  818. const std::string currentMoc = mocIncludeRegExp.match(1);
  819. std::string basename = cmsys::SystemTools::
  820. GetFilenameWithoutLastExtension(currentMoc);
  821. const bool mocUnderscoreStyle = cmHasLiteralPrefix(basename, "moc_");
  822. // If the moc include is of the moc_foo.cpp style we expect
  823. // the Q_OBJECT class declaration in a header file.
  824. // If the moc include is of the foo.moc style we need to look for
  825. // a Q_OBJECT macro in the current source file, if it contains the
  826. // macro we generate the moc file from the source file.
  827. if (mocUnderscoreStyle)
  828. {
  829. // basename should be the part of the moc filename used for
  830. // finding the correct header, so we need to remove the moc_ part
  831. basename = basename.substr(4);
  832. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  833. std::string headerToMoc = findMatchingHeader(
  834. absPath, mocSubDir, basename, headerExtensions);
  835. if (!headerToMoc.empty())
  836. {
  837. includedMocs[headerToMoc] = currentMoc;
  838. }
  839. else
  840. {
  841. std::cerr << "AUTOGEN: error: " << absFilename << " The file "
  842. << "includes the moc file \"" << currentMoc << "\", "
  843. << "but could not find header \"" << basename
  844. << '{' << this->Join(headerExtensions, ',') << "}\" ";
  845. if (mocSubDir.empty())
  846. {
  847. std::cerr << "in " << absPath << "\n" << std::endl;
  848. }
  849. else
  850. {
  851. std::cerr << "neither in " << absPath
  852. << " nor in " << mocSubDir << "\n" << std::endl;
  853. }
  854. ::exit(EXIT_FAILURE);
  855. }
  856. }
  857. else
  858. {
  859. if (basename != scannedFileBasename)
  860. {
  861. std::cerr <<"AUTOGEN: error: " << absFilename << ": The file "
  862. "includes the moc file \"" << currentMoc <<
  863. "\", which seems to be the moc file from a different "
  864. "source file. This is not supported. "
  865. "Include \"" << scannedFileBasename << ".moc\" to run "
  866. "moc on this source file.\n" << std::endl;
  867. ::exit(EXIT_FAILURE);
  868. }
  869. dotMocIncluded = true;
  870. includedMocs[absFilename] = currentMoc;
  871. }
  872. matchOffset += mocIncludeRegExp.end();
  873. } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  874. }
  875. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  876. // If this is the case, the moc_foo.cpp should probably be generated from
  877. // foo.cpp instead of foo.h, because otherwise it won't build.
  878. // But warn, since this is not how it is supposed to be used.
  879. std::string macroName;
  880. if ((dotMocIncluded == false) && (requiresMocing(contentsString,
  881. macroName)))
  882. {
  883. // otherwise always error out since it will not compile:
  884. std::cerr << "AUTOGEN: error: " << absFilename << ": The file "
  885. << "contains a " << macroName << " macro, but does not include "
  886. << "\"" << scannedFileBasename << ".moc\" !\n"
  887. << std::endl;
  888. ::exit(EXIT_FAILURE);
  889. }
  890. }
  891. void cmQtAutoGenerators::ParseForUic(const std::string& absFilename,
  892. std::map<std::string, std::vector<std::string> >& includedUis)
  893. {
  894. if (this->UicExecutable.empty())
  895. {
  896. return;
  897. }
  898. const std::string contentsString = ReadAll(absFilename);
  899. if (contentsString.empty())
  900. {
  901. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  902. << std::endl;
  903. return;
  904. }
  905. this->ParseForUic(absFilename, contentsString, includedUis);
  906. }
  907. void cmQtAutoGenerators::ParseForUic(const std::string& absFilename,
  908. const std::string& contentsString,
  909. std::map<std::string, std::vector<std::string> >& includedUis)
  910. {
  911. if (this->UicExecutable.empty())
  912. {
  913. return;
  914. }
  915. cmsys::RegularExpression uiIncludeRegExp(
  916. "[\n][ \t]*#[ \t]*include[ \t]+"
  917. "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
  918. std::string::size_type matchOffset = 0;
  919. const std::string realName =
  920. cmsys::SystemTools::GetRealPath(absFilename);
  921. matchOffset = 0;
  922. if ((strstr(contentsString.c_str(), "ui_") != NULL)
  923. && (uiIncludeRegExp.find(contentsString)))
  924. {
  925. do
  926. {
  927. const std::string currentUi = uiIncludeRegExp.match(1);
  928. std::string basename = cmsys::SystemTools::
  929. GetFilenameWithoutLastExtension(currentUi);
  930. // basename should be the part of the ui filename used for
  931. // finding the correct header, so we need to remove the ui_ part
  932. basename = basename.substr(3);
  933. includedUis[realName].push_back(basename);
  934. matchOffset += uiIncludeRegExp.end();
  935. } while(uiIncludeRegExp.find(contentsString.c_str() + matchOffset));
  936. }
  937. }
  938. void
  939. cmQtAutoGenerators::SearchHeadersForCppFile(const std::string& absFilename,
  940. const std::vector<std::string>& headerExtensions,
  941. std::set<std::string>& absHeaders)
  942. {
  943. // search for header files and private header files we may need to moc:
  944. const std::string basename =
  945. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  946. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  947. cmsys::SystemTools::GetRealPath(absFilename)) + '/';
  948. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  949. ext != headerExtensions.end();
  950. ++ext)
  951. {
  952. const std::string headerName = absPath + basename + "." + (*ext);
  953. if (cmsys::SystemTools::FileExists(headerName.c_str()))
  954. {
  955. absHeaders.insert(headerName);
  956. break;
  957. }
  958. }
  959. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  960. ext != headerExtensions.end();
  961. ++ext)
  962. {
  963. const std::string privateHeaderName = absPath+basename+"_p."+(*ext);
  964. if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()))
  965. {
  966. absHeaders.insert(privateHeaderName);
  967. break;
  968. }
  969. }
  970. }
  971. void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
  972. const std::map<std::string, std::string>& includedMocs,
  973. std::map<std::string, std::string>& notIncludedMocs,
  974. std::map<std::string, std::vector<std::string> >& includedUis)
  975. {
  976. for(std::set<std::string>::const_iterator hIt=absHeaders.begin();
  977. hIt!=absHeaders.end();
  978. ++hIt)
  979. {
  980. const std::string& headerName = *hIt;
  981. const std::string contents = ReadAll(headerName);
  982. if (!this->MocExecutable.empty()
  983. && includedMocs.find(headerName) == includedMocs.end())
  984. {
  985. if (this->Verbose)
  986. {
  987. std::cout << "AUTOGEN: Checking " << headerName << std::endl;
  988. }
  989. const std::string basename = cmsys::SystemTools::
  990. GetFilenameWithoutLastExtension(headerName);
  991. const std::string currentMoc = "moc_" + basename + ".cpp";
  992. std::string macroName;
  993. if (requiresMocing(contents, macroName))
  994. {
  995. //std::cout << "header contains Q_OBJECT macro";
  996. notIncludedMocs[headerName] = currentMoc;
  997. }
  998. }
  999. this->ParseForUic(headerName, contents, includedUis);
  1000. }
  1001. }
  1002. bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
  1003. const std::string& mocFileName)
  1004. {
  1005. const std::string mocFilePath = this->Builddir + mocFileName;
  1006. int sourceNewerThanMoc = 0;
  1007. bool success = cmsys::SystemTools::FileTimeCompare(sourceFile,
  1008. mocFilePath,
  1009. &sourceNewerThanMoc);
  1010. if (this->GenerateAll || !success || sourceNewerThanMoc >= 0)
  1011. {
  1012. // make sure the directory for the resulting moc file exists
  1013. std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/'));
  1014. if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false))
  1015. {
  1016. cmsys::SystemTools::MakeDirectory(mocDir.c_str());
  1017. }
  1018. std::string msg = "Generating ";
  1019. msg += mocFileName;
  1020. cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
  1021. |cmsysTerminal_Color_ForegroundBold,
  1022. msg.c_str(), true, this->ColorOutput);
  1023. std::vector<std::string> command;
  1024. command.push_back(this->MocExecutable);
  1025. command.insert(command.end(),
  1026. this->MocIncludes.begin(), this->MocIncludes.end());
  1027. command.insert(command.end(),
  1028. this->MocDefinitions.begin(), this->MocDefinitions.end());
  1029. command.insert(command.end(),
  1030. this->MocOptions.begin(), this->MocOptions.end());
  1031. #ifdef _WIN32
  1032. command.push_back("-DWIN32");
  1033. #endif
  1034. command.push_back("-o");
  1035. command.push_back(mocFilePath);
  1036. command.push_back(sourceFile);
  1037. if (this->Verbose)
  1038. {
  1039. for(std::vector<std::string>::const_iterator cmdIt = command.begin();
  1040. cmdIt != command.end();
  1041. ++cmdIt)
  1042. {
  1043. std::cout << *cmdIt << " ";
  1044. }
  1045. std::cout << std::endl;
  1046. }
  1047. std::string output;
  1048. int retVal = 0;
  1049. bool result = cmSystemTools::RunSingleCommand(command, &output, &output,
  1050. &retVal);
  1051. if (!result || retVal)
  1052. {
  1053. std::cerr << "AUTOGEN: error: process for " << mocFilePath <<" failed:\n"
  1054. << output << std::endl;
  1055. this->RunMocFailed = true;
  1056. cmSystemTools::RemoveFile(mocFilePath);
  1057. }
  1058. return true;
  1059. }
  1060. return false;
  1061. }
  1062. bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
  1063. const std::string& uiFileName)
  1064. {
  1065. if (!cmsys::SystemTools::FileExists(this->Builddir.c_str(), false))
  1066. {
  1067. cmsys::SystemTools::MakeDirectory(this->Builddir.c_str());
  1068. }
  1069. const std::string path = cmsys::SystemTools::GetFilenamePath(
  1070. realName) + '/';
  1071. std::string ui_output_file = "ui_" + uiFileName + ".h";
  1072. std::string ui_input_file = path + uiFileName + ".ui";
  1073. int sourceNewerThanUi = 0;
  1074. bool success = cmsys::SystemTools::FileTimeCompare(ui_input_file,
  1075. this->Builddir + ui_output_file,
  1076. &sourceNewerThanUi);
  1077. if (this->GenerateAll || !success || sourceNewerThanUi >= 0)
  1078. {
  1079. std::string msg = "Generating ";
  1080. msg += ui_output_file;
  1081. cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
  1082. |cmsysTerminal_Color_ForegroundBold,
  1083. msg.c_str(), true, this->ColorOutput);
  1084. std::vector<std::string> command;
  1085. command.push_back(this->UicExecutable);
  1086. std::vector<std::string> opts = this->UicTargetOptions;
  1087. std::map<std::string, std::string>::const_iterator optionIt
  1088. = this->UicOptions.find(ui_input_file);
  1089. if (optionIt != this->UicOptions.end())
  1090. {
  1091. std::vector<std::string> fileOpts;
  1092. cmSystemTools::ExpandListArgument(optionIt->second, fileOpts);
  1093. cmQtAutoGenerators::MergeUicOptions(opts, fileOpts,
  1094. this->QtMajorVersion == "5");
  1095. }
  1096. command.insert(command.end(), opts.begin(), opts.end());
  1097. command.push_back("-o");
  1098. command.push_back(this->Builddir + ui_output_file);
  1099. command.push_back(ui_input_file);
  1100. if (this->Verbose)
  1101. {
  1102. for(std::vector<std::string>::const_iterator cmdIt = command.begin();
  1103. cmdIt != command.end();
  1104. ++cmdIt)
  1105. {
  1106. std::cout << *cmdIt << " ";
  1107. }
  1108. std::cout << std::endl;
  1109. }
  1110. std::string output;
  1111. int retVal = 0;
  1112. bool result = cmSystemTools::RunSingleCommand(command, &output, &output,
  1113. &retVal);
  1114. if (!result || retVal)
  1115. {
  1116. std::cerr << "AUTOUIC: error: process for " << ui_output_file <<
  1117. " needed by\n \"" << realName << "\"\nfailed:\n" << output
  1118. << std::endl;
  1119. this->RunUicFailed = true;
  1120. cmSystemTools::RemoveFile(ui_output_file);
  1121. return false;
  1122. }
  1123. return true;
  1124. }
  1125. return false;
  1126. }
  1127. bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile,
  1128. const std::string& rccOutput)
  1129. {
  1130. std::vector<std::string> const& files = this->RccInputs[qrcFile];
  1131. for (std::vector<std::string>::const_iterator it = files.begin();
  1132. it != files.end(); ++it)
  1133. {
  1134. int inputNewerThanQrc = 0;
  1135. bool success = cmsys::SystemTools::FileTimeCompare(*it,
  1136. rccOutput,
  1137. &inputNewerThanQrc);
  1138. if (!success || inputNewerThanQrc >= 0)
  1139. {
  1140. return true;
  1141. }
  1142. }
  1143. return false;
  1144. }
  1145. bool cmQtAutoGenerators::GenerateQrc()
  1146. {
  1147. for(std::vector<std::string>::const_iterator si = this->RccSources.begin();
  1148. si != this->RccSources.end(); ++si)
  1149. {
  1150. std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
  1151. if (ext != ".qrc")
  1152. {
  1153. continue;
  1154. }
  1155. std::vector<std::string> command;
  1156. command.push_back(this->RccExecutable);
  1157. std::string basename = cmsys::SystemTools::
  1158. GetFilenameWithoutLastExtension(*si);
  1159. std::string rcc_output_file = this->Builddir
  1160. + "CMakeFiles/" + this->OriginTargetName
  1161. + ".dir/qrc_" + basename + ".cpp";
  1162. int sourceNewerThanQrc = 0;
  1163. bool generateQrc = !cmsys::SystemTools::FileTimeCompare(*si,
  1164. rcc_output_file,
  1165. &sourceNewerThanQrc);
  1166. generateQrc = generateQrc || (sourceNewerThanQrc >= 0);
  1167. generateQrc = generateQrc || this->InputFilesNewerThanQrc(*si,
  1168. rcc_output_file);
  1169. if (this->GenerateAll || generateQrc)
  1170. {
  1171. std::map<std::string, std::string>::const_iterator optionIt
  1172. = this->RccOptions.find(*si);
  1173. if (optionIt != this->RccOptions.end())
  1174. {
  1175. cmSystemTools::ExpandListArgument(optionIt->second, command);
  1176. }
  1177. command.push_back("-name");
  1178. command.push_back(basename);
  1179. command.push_back("-o");
  1180. command.push_back(rcc_output_file);
  1181. command.push_back(*si);
  1182. if (this->Verbose)
  1183. {
  1184. for(std::vector<std::string>::const_iterator cmdIt = command.begin();
  1185. cmdIt != command.end();
  1186. ++cmdIt)
  1187. {
  1188. std::cout << *cmdIt << " ";
  1189. }
  1190. std::cout << std::endl;
  1191. }
  1192. std::string output;
  1193. int retVal = 0;
  1194. bool result = cmSystemTools::RunSingleCommand(command, &output, &output,
  1195. &retVal);
  1196. if (!result || retVal)
  1197. {
  1198. std::cerr << "AUTORCC: error: process for " << rcc_output_file <<
  1199. " failed:\n" << output << std::endl;
  1200. this->RunRccFailed = true;
  1201. cmSystemTools::RemoveFile(rcc_output_file);
  1202. return false;
  1203. }
  1204. }
  1205. }
  1206. return true;
  1207. }
  1208. std::string cmQtAutoGenerators::Join(const std::vector<std::string>& lst,
  1209. char separator)
  1210. {
  1211. if (lst.empty())
  1212. {
  1213. return "";
  1214. }
  1215. std::string result;
  1216. for (std::vector<std::string>::const_iterator it = lst.begin();
  1217. it != lst.end();
  1218. ++it)
  1219. {
  1220. result += "." + (*it) + separator;
  1221. }
  1222. result.erase(result.end() - 1);
  1223. return result;
  1224. }
  1225. bool cmQtAutoGenerators::StartsWith(const std::string& str,
  1226. const std::string& with)
  1227. {
  1228. return (str.substr(0, with.length()) == with);
  1229. }
  1230. bool cmQtAutoGenerators::EndsWith(const std::string& str,
  1231. const std::string& with)
  1232. {
  1233. if (with.length() > (str.length()))
  1234. {
  1235. return false;
  1236. }
  1237. return (str.substr(str.length() - with.length(), with.length()) == with);
  1238. }