cmQtAutoGenerators.cxx 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmQtAutoGenerators.h"
  4. #include <algorithm>
  5. #include <assert.h>
  6. #include <cmConfigure.h>
  7. #include <cmsys/FStream.hxx>
  8. #include <cmsys/RegularExpression.hxx>
  9. #include <cmsys/Terminal.h>
  10. #include <iostream>
  11. #include <sstream>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <utility>
  15. #include "cmAlgorithms.h"
  16. #include "cmGlobalGenerator.h"
  17. #include "cmMakefile.h"
  18. #include "cmOutputConverter.h"
  19. #include "cmStateDirectory.h"
  20. #include "cmStateSnapshot.h"
  21. #include "cmSystemTools.h"
  22. #include "cm_auto_ptr.hxx"
  23. #include "cmake.h"
  24. #if defined(__APPLE__)
  25. #include <unistd.h>
  26. #endif
  27. static bool requiresMocing(const std::string& text, std::string& macroName)
  28. {
  29. // this simple check is much much faster than the regexp
  30. if (strstr(text.c_str(), "Q_OBJECT") == CM_NULLPTR &&
  31. strstr(text.c_str(), "Q_GADGET") == CM_NULLPTR) {
  32. return false;
  33. }
  34. cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
  35. if (qObjectRegExp.find(text)) {
  36. macroName = "Q_OBJECT";
  37. return true;
  38. }
  39. cmsys::RegularExpression qGadgetRegExp("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]");
  40. if (qGadgetRegExp.find(text)) {
  41. macroName = "Q_GADGET";
  42. return true;
  43. }
  44. return false;
  45. }
  46. static std::string findMatchingHeader(
  47. const std::string& absPath, const std::string& mocSubDir,
  48. const std::string& basename,
  49. const std::vector<std::string>& headerExtensions)
  50. {
  51. std::string header;
  52. for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  53. ext != headerExtensions.end(); ++ext) {
  54. std::string sourceFilePath = absPath + basename + "." + (*ext);
  55. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) {
  56. header = sourceFilePath;
  57. break;
  58. }
  59. // Try subdirectory instead
  60. if (!mocSubDir.empty()) {
  61. sourceFilePath = mocSubDir + basename + "." + (*ext);
  62. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) {
  63. header = sourceFilePath;
  64. break;
  65. }
  66. }
  67. }
  68. return header;
  69. }
  70. static std::string extractSubDir(const std::string& absPath,
  71. const std::string& currentMoc)
  72. {
  73. std::string subDir;
  74. if (currentMoc.find_first_of('/') != std::string::npos) {
  75. subDir = absPath + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
  76. }
  77. return subDir;
  78. }
  79. static bool FileNameIsUnique(const std::string& filePath,
  80. const std::map<std::string, std::string>& fileMap)
  81. {
  82. size_t count(0);
  83. const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath);
  84. for (std::map<std::string, std::string>::const_iterator si = fileMap.begin();
  85. si != fileMap.end(); ++si) {
  86. if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) {
  87. ++count;
  88. if (count > 1) {
  89. return false;
  90. }
  91. }
  92. }
  93. return true;
  94. }
  95. cmQtAutoGenerators::cmQtAutoGenerators()
  96. : Verbose(cmsys::SystemTools::HasEnv("VERBOSE"))
  97. , ColorOutput(true)
  98. , RunMocFailed(false)
  99. , RunUicFailed(false)
  100. , RunRccFailed(false)
  101. , GenerateAll(false)
  102. {
  103. std::string colorEnv;
  104. cmsys::SystemTools::GetEnv("COLOR", colorEnv);
  105. if (!colorEnv.empty()) {
  106. if (cmSystemTools::IsOn(colorEnv.c_str())) {
  107. this->ColorOutput = true;
  108. } else {
  109. this->ColorOutput = false;
  110. }
  111. }
  112. }
  113. void cmQtAutoGenerators::MergeUicOptions(
  114. std::vector<std::string>& opts, const std::vector<std::string>& fileOpts,
  115. bool isQt5)
  116. {
  117. static const char* valueOptions[] = { "tr", "translate",
  118. "postfix", "generator",
  119. "include", // Since Qt 5.3
  120. "g" };
  121. std::vector<std::string> extraOpts;
  122. for (std::vector<std::string>::const_iterator it = fileOpts.begin();
  123. it != fileOpts.end(); ++it) {
  124. std::vector<std::string>::iterator existingIt =
  125. std::find(opts.begin(), opts.end(), *it);
  126. if (existingIt != opts.end()) {
  127. const char* o = it->c_str();
  128. if (*o == '-') {
  129. ++o;
  130. }
  131. if (isQt5 && *o == '-') {
  132. ++o;
  133. }
  134. if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
  135. cmStrCmp(*it)) != cmArrayEnd(valueOptions)) {
  136. assert(existingIt + 1 != opts.end());
  137. *(existingIt + 1) = *(it + 1);
  138. ++it;
  139. }
  140. } else {
  141. extraOpts.push_back(*it);
  142. }
  143. }
  144. opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
  145. }
  146. bool cmQtAutoGenerators::Run(const std::string& targetDirectory,
  147. const std::string& config)
  148. {
  149. cmake cm;
  150. cm.SetHomeOutputDirectory(targetDirectory);
  151. cm.SetHomeDirectory(targetDirectory);
  152. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  153. cmGlobalGenerator gg(&cm);
  154. cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
  155. snapshot.GetDirectory().SetCurrentBinary(targetDirectory);
  156. snapshot.GetDirectory().SetCurrentSource(targetDirectory);
  157. CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, snapshot));
  158. gg.SetCurrentMakefile(mf.get());
  159. if (!this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) {
  160. return false;
  161. }
  162. this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory);
  163. this->Init();
  164. if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") {
  165. if (!this->RunAutogen(mf.get())) {
  166. return false;
  167. }
  168. }
  169. return this->WriteOldMocDefinitionsFile(targetDirectory);
  170. }
  171. bool cmQtAutoGenerators::ReadAutogenInfoFile(
  172. cmMakefile* makefile, const std::string& targetDirectory,
  173. const std::string& config)
  174. {
  175. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  176. cmSystemTools::ConvertToUnixSlashes(filename);
  177. filename += "/AutogenInfo.cmake";
  178. if (!makefile->ReadListFile(filename.c_str())) {
  179. std::ostringstream err;
  180. err << "AUTOGEN: error processing file: " << filename << std::endl;
  181. this->LogError(err.str());
  182. return false;
  183. }
  184. // - Target names
  185. this->OriginTargetName =
  186. makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME");
  187. this->AutogenTargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
  188. // - Directories
  189. this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
  190. this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
  191. this->CurrentSourceDir =
  192. makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
  193. this->CurrentBinaryDir =
  194. makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
  195. // - Qt environment
  196. this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
  197. if (this->QtMajorVersion == "") {
  198. this->QtMajorVersion =
  199. makefile->GetSafeDefinition("AM_Qt5Core_VERSION_MAJOR");
  200. }
  201. this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
  202. this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE");
  203. this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE");
  204. // - File Lists
  205. this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
  206. this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
  207. // - Moc
  208. this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
  209. {
  210. std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS";
  211. std::string compileDefsProp = compileDefsPropOrig;
  212. if (!config.empty()) {
  213. compileDefsProp += "_";
  214. compileDefsProp += config;
  215. }
  216. const char* compileDefs = makefile->GetDefinition(compileDefsProp);
  217. this->MocCompileDefinitionsStr = compileDefs
  218. ? compileDefs
  219. : makefile->GetSafeDefinition(compileDefsPropOrig);
  220. }
  221. {
  222. std::string includesPropOrig = "AM_MOC_INCLUDES";
  223. std::string includesProp = includesPropOrig;
  224. if (!config.empty()) {
  225. includesProp += "_";
  226. includesProp += config;
  227. }
  228. const char* includes = makefile->GetDefinition(includesProp);
  229. this->MocIncludesStr =
  230. includes ? includes : makefile->GetSafeDefinition(includesPropOrig);
  231. }
  232. this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  233. // - Uic
  234. this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
  235. {
  236. const char* uicOptionsFiles =
  237. makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES");
  238. std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS";
  239. std::string uicOptionsProp = uicOptionsPropOrig;
  240. if (!config.empty()) {
  241. uicOptionsProp += "_";
  242. uicOptionsProp += config;
  243. }
  244. const char* uicTargetOptions = makefile->GetSafeDefinition(uicOptionsProp);
  245. cmSystemTools::ExpandListArgument(
  246. uicTargetOptions ? uicTargetOptions
  247. : makefile->GetSafeDefinition(uicOptionsPropOrig),
  248. this->UicTargetOptions);
  249. const char* uicOptionsOptions =
  250. makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS");
  251. std::vector<std::string> uicFilesVec;
  252. cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec);
  253. std::vector<std::string> uicOptionsVec;
  254. cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec);
  255. if (uicFilesVec.size() != uicOptionsVec.size()) {
  256. return false;
  257. }
  258. for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(),
  259. optionIt = uicOptionsVec.begin();
  260. fileIt != uicFilesVec.end(); ++fileIt, ++optionIt) {
  261. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  262. this->UicOptions[*fileIt] = *optionIt;
  263. }
  264. }
  265. // - Rcc
  266. {
  267. std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
  268. cmSystemTools::ExpandListArgument(rccSources, this->RccSources);
  269. }
  270. {
  271. const char* rccOptionsFiles =
  272. makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES");
  273. const char* rccOptionsOptions =
  274. makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS");
  275. std::vector<std::string> rccFilesVec;
  276. cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec);
  277. std::vector<std::string> rccOptionsVec;
  278. cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec);
  279. if (rccFilesVec.size() != rccOptionsVec.size()) {
  280. return false;
  281. }
  282. for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(),
  283. optionIt = rccOptionsVec.begin();
  284. fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) {
  285. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  286. this->RccOptions[*fileIt] = *optionIt;
  287. }
  288. const char* rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS");
  289. std::vector<std::string> rccInputLists;
  290. cmSystemTools::ExpandListArgument(rccInputs, rccInputLists);
  291. // qrc files in the end of the list may have been empty
  292. if (rccInputLists.size() < this->RccSources.size()) {
  293. rccInputLists.resize(this->RccSources.size());
  294. }
  295. if (this->RccSources.size() != rccInputLists.size()) {
  296. std::ostringstream err;
  297. err << "AUTOGEN: RCC sources lists size missmatch in: " << filename;
  298. err << std::endl;
  299. this->LogError(err.str());
  300. return false;
  301. }
  302. for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(),
  303. inputIt = rccInputLists.begin();
  304. fileIt != this->RccSources.end(); ++fileIt, ++inputIt) {
  305. cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";");
  306. std::vector<std::string> rccInputFiles;
  307. cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles);
  308. this->RccInputs[*fileIt] = rccInputFiles;
  309. }
  310. }
  311. // - Settings
  312. this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
  313. // - Flags
  314. this->IncludeProjectDirsBefore =
  315. makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
  316. this->MocRelaxedMode = makefile->IsOn("AM_MOC_RELAXED_MODE");
  317. return true;
  318. }
  319. std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile)
  320. {
  321. std::string s;
  322. s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS");
  323. s += " ~~~ ";
  324. s += makefile->GetSafeDefinition("AM_MOC_INCLUDES");
  325. s += " ~~~ ";
  326. s += makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  327. s += " ~~~ ";
  328. s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE"
  329. : "FALSE";
  330. s += " ~~~ ";
  331. return s;
  332. }
  333. void cmQtAutoGenerators::ReadOldMocDefinitionsFile(
  334. cmMakefile* makefile, const std::string& targetDirectory)
  335. {
  336. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  337. cmSystemTools::ConvertToUnixSlashes(filename);
  338. filename += "/AutomocOldMocDefinitions.cmake";
  339. if (makefile->ReadListFile(filename.c_str())) {
  340. this->OldCompileSettingsStr =
  341. makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
  342. }
  343. }
  344. bool cmQtAutoGenerators::WriteOldMocDefinitionsFile(
  345. const std::string& targetDirectory)
  346. {
  347. bool success = true;
  348. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  349. cmSystemTools::ConvertToUnixSlashes(filename);
  350. filename += "/AutomocOldMocDefinitions.cmake";
  351. {
  352. cmsys::ofstream outfile;
  353. outfile.open(filename.c_str(), std::ios::trunc);
  354. if (outfile) {
  355. outfile << "set(AM_OLD_COMPILE_SETTINGS "
  356. << cmOutputConverter::EscapeForCMake(
  357. this->CurrentCompileSettingsStr)
  358. << ")\n";
  359. success = outfile.good();
  360. } else {
  361. success = false;
  362. }
  363. }
  364. return success;
  365. }
  366. void cmQtAutoGenerators::Init()
  367. {
  368. this->AutogenBuildSubDir = this->AutogenTargetName;
  369. this->AutogenBuildSubDir += "/";
  370. this->OutMocCppFilenameRel = this->AutogenBuildSubDir;
  371. this->OutMocCppFilenameRel += "moc_compilation.cpp";
  372. this->OutMocCppFilenameAbs =
  373. this->CurrentBinaryDir + this->OutMocCppFilenameRel;
  374. // Init file path checksum generator
  375. fpathCheckSum.setupParentDirs(this->CurrentSourceDir, this->CurrentBinaryDir,
  376. this->ProjectSourceDir,
  377. this->ProjectBinaryDir);
  378. std::vector<std::string> cdefList;
  379. cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
  380. for (std::vector<std::string>::const_iterator it = cdefList.begin();
  381. it != cdefList.end(); ++it) {
  382. this->MocDefinitions.push_back("-D" + (*it));
  383. }
  384. cmSystemTools::ExpandListArgument(this->MocOptionsStr, this->MocOptions);
  385. std::vector<std::string> incPaths;
  386. cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths);
  387. std::set<std::string> frameworkPaths;
  388. for (std::vector<std::string>::const_iterator it = incPaths.begin();
  389. it != incPaths.end(); ++it) {
  390. const std::string& path = *it;
  391. this->MocIncludes.push_back("-I" + path);
  392. if (cmHasLiteralSuffix(path, ".framework/Headers")) {
  393. // Go up twice to get to the framework root
  394. std::vector<std::string> pathComponents;
  395. cmsys::SystemTools::SplitPath(path, pathComponents);
  396. std::string frameworkPath = cmsys::SystemTools::JoinPath(
  397. pathComponents.begin(), pathComponents.end() - 2);
  398. frameworkPaths.insert(frameworkPath);
  399. }
  400. }
  401. for (std::set<std::string>::const_iterator it = frameworkPaths.begin();
  402. it != frameworkPaths.end(); ++it) {
  403. this->MocIncludes.push_back("-F");
  404. this->MocIncludes.push_back(*it);
  405. }
  406. if (this->IncludeProjectDirsBefore) {
  407. const std::string binDir = "-I" + this->ProjectBinaryDir;
  408. const std::string srcDir = "-I" + this->ProjectSourceDir;
  409. std::list<std::string> sortedMocIncludes;
  410. std::list<std::string>::iterator it = this->MocIncludes.begin();
  411. while (it != this->MocIncludes.end()) {
  412. if (cmsys::SystemTools::StringStartsWith(*it, binDir.c_str())) {
  413. sortedMocIncludes.push_back(*it);
  414. it = this->MocIncludes.erase(it);
  415. } else {
  416. ++it;
  417. }
  418. }
  419. it = this->MocIncludes.begin();
  420. while (it != this->MocIncludes.end()) {
  421. if (cmsys::SystemTools::StringStartsWith(*it, srcDir.c_str())) {
  422. sortedMocIncludes.push_back(*it);
  423. it = this->MocIncludes.erase(it);
  424. } else {
  425. ++it;
  426. }
  427. }
  428. sortedMocIncludes.insert(sortedMocIncludes.end(),
  429. this->MocIncludes.begin(),
  430. this->MocIncludes.end());
  431. this->MocIncludes = sortedMocIncludes;
  432. }
  433. }
  434. static std::string ReadAll(const std::string& filename)
  435. {
  436. cmsys::ifstream file(filename.c_str());
  437. std::ostringstream stream;
  438. stream << file.rdbuf();
  439. file.close();
  440. return stream.str();
  441. }
  442. bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
  443. {
  444. // If settings changed everything needs to be re-generated.
  445. if (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr) {
  446. this->GenerateAll = true;
  447. }
  448. // the program goes through all .cpp files to see which moc files are
  449. // included. It is not really interesting how the moc file is named, but
  450. // what file the moc is created from. Once a moc is included the same moc
  451. // may not be included in the moc_compilation.cpp file anymore. OTOH if
  452. // there's a header containing Q_OBJECT where no corresponding moc file
  453. // is included anywhere a moc_<filename>.cpp file is created and included in
  454. // the moc_compilation.cpp file.
  455. // key = moc source filepath, value = moc output filepath
  456. std::map<std::string, std::string> includedMocs;
  457. // collect all headers which may need to be mocced
  458. std::set<std::string> headerFiles;
  459. std::vector<std::string> sourceFiles;
  460. cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
  461. const std::vector<std::string>& headerExtensions =
  462. makefile->GetCMakeInstance()->GetHeaderExtensions();
  463. std::map<std::string, std::vector<std::string> > includedUis;
  464. std::map<std::string, std::vector<std::string> > skippedUis;
  465. std::vector<std::string> uicSkipped;
  466. cmSystemTools::ExpandListArgument(this->SkipUic, uicSkipped);
  467. for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
  468. it != sourceFiles.end(); ++it) {
  469. const bool skipUic =
  470. std::find(uicSkipped.begin(), uicSkipped.end(), *it) != uicSkipped.end();
  471. std::map<std::string, std::vector<std::string> >& uiFiles =
  472. skipUic ? skippedUis : includedUis;
  473. const std::string& absFilename = *it;
  474. if (this->Verbose) {
  475. std::ostringstream err;
  476. err << "AUTOGEN: Checking " << absFilename << std::endl;
  477. this->LogInfo(err.str());
  478. }
  479. if (this->MocRelaxedMode) {
  480. if (!this->ParseCppFile(absFilename, headerExtensions, includedMocs,
  481. uiFiles)) {
  482. return false;
  483. }
  484. } else {
  485. if (!this->StrictParseCppFile(absFilename, headerExtensions,
  486. includedMocs, uiFiles)) {
  487. return false;
  488. }
  489. }
  490. this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
  491. }
  492. {
  493. std::vector<std::string> mocSkipped;
  494. cmSystemTools::ExpandListArgument(this->SkipMoc, mocSkipped);
  495. for (std::vector<std::string>::const_iterator it = mocSkipped.begin();
  496. it != mocSkipped.end(); ++it) {
  497. if (std::find(uicSkipped.begin(), uicSkipped.end(), *it) !=
  498. uicSkipped.end()) {
  499. const std::string& absFilename = *it;
  500. if (this->Verbose) {
  501. std::ostringstream err;
  502. err << "AUTOGEN: Checking " << absFilename << std::endl;
  503. this->LogInfo(err.str());
  504. }
  505. this->ParseForUic(absFilename, includedUis);
  506. }
  507. }
  508. }
  509. std::vector<std::string> headerFilesVec;
  510. cmSystemTools::ExpandListArgument(this->Headers, headerFilesVec);
  511. headerFiles.insert(headerFilesVec.begin(), headerFilesVec.end());
  512. // key = moc source filepath, value = moc output filename
  513. std::map<std::string, std::string> notIncludedMocs;
  514. this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
  515. if (!this->MocExecutable.empty()) {
  516. if (!this->GenerateMocFiles(includedMocs, notIncludedMocs)) {
  517. return false;
  518. }
  519. }
  520. if (!this->UicExecutable.empty()) {
  521. if (!this->GenerateUiFiles(includedUis)) {
  522. return false;
  523. }
  524. }
  525. if (!this->RccExecutable.empty()) {
  526. if (!this->GenerateQrcFiles()) {
  527. return false;
  528. }
  529. }
  530. return true;
  531. }
  532. /**
  533. * @return True on success
  534. */
  535. bool cmQtAutoGenerators::ParseCppFile(
  536. const std::string& absFilename,
  537. const std::vector<std::string>& headerExtensions,
  538. std::map<std::string, std::string>& includedMocs,
  539. std::map<std::string, std::vector<std::string> >& includedUis)
  540. {
  541. cmsys::RegularExpression mocIncludeRegExp(
  542. "[\n][ \t]*#[ \t]*include[ \t]+"
  543. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  544. const std::string contentsString = ReadAll(absFilename);
  545. if (contentsString.empty()) {
  546. std::ostringstream err;
  547. err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  548. << std::endl;
  549. this->LogWarning(err.str());
  550. return true;
  551. }
  552. this->ParseForUic(absFilename, contentsString, includedUis);
  553. if (this->MocExecutable.empty()) {
  554. return true;
  555. }
  556. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  557. cmsys::SystemTools::GetRealPath(absFilename)) +
  558. '/';
  559. const std::string scannedFileBasename =
  560. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  561. std::string macroName;
  562. const bool requiresMoc = requiresMocing(contentsString, macroName);
  563. bool dotMocIncluded = false;
  564. bool mocUnderscoreIncluded = false;
  565. std::string ownMocUnderscoreFile;
  566. std::string ownDotMocFile;
  567. std::string ownMocHeaderFile;
  568. std::string::size_type matchOffset = 0;
  569. // first a simple string check for "moc" is *much* faster than the regexp,
  570. // and if the string search already fails, we don't have to try the
  571. // expensive regexp
  572. if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) &&
  573. (mocIncludeRegExp.find(contentsString))) {
  574. // for every moc include in the file
  575. do {
  576. const std::string currentMoc = mocIncludeRegExp.match(1);
  577. std::string basename =
  578. cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
  579. const bool mocUnderscoreStyle = cmHasLiteralPrefix(basename, "moc_");
  580. // If the moc include is of the moc_foo.cpp style we expect
  581. // the Q_OBJECT class declaration in a header file.
  582. // If the moc include is of the foo.moc style we need to look for
  583. // a Q_OBJECT macro in the current source file, if it contains the
  584. // macro we generate the moc file from the source file.
  585. if (mocUnderscoreStyle) {
  586. // basename should be the part of the moc filename used for
  587. // finding the correct header, so we need to remove the moc_ part
  588. basename = basename.substr(4);
  589. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  590. std::string headerToMoc =
  591. findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
  592. if (!headerToMoc.empty()) {
  593. includedMocs[headerToMoc] = currentMoc;
  594. if (basename == scannedFileBasename) {
  595. mocUnderscoreIncluded = true;
  596. ownMocUnderscoreFile = currentMoc;
  597. ownMocHeaderFile = headerToMoc;
  598. }
  599. } else {
  600. std::ostringstream err;
  601. err << "AUTOGEN: error: " << absFilename << ": The file "
  602. << "includes the moc file \"" << currentMoc << "\", "
  603. << "but could not find header \"" << basename << '{'
  604. << this->JoinExts(headerExtensions) << "}\" ";
  605. if (mocSubDir.empty()) {
  606. err << "in " << absPath << "\n" << std::endl;
  607. } else {
  608. err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
  609. << std::endl;
  610. }
  611. this->LogError(err.str());
  612. return false;
  613. }
  614. } else {
  615. std::string fileToMoc = absFilename;
  616. if (!requiresMoc || basename != scannedFileBasename) {
  617. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  618. std::string headerToMoc =
  619. findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
  620. if (!headerToMoc.empty()) {
  621. // this is for KDE4 compatibility:
  622. fileToMoc = headerToMoc;
  623. if (!requiresMoc && basename == scannedFileBasename) {
  624. std::ostringstream err;
  625. err << "AUTOGEN: warning: " << absFilename
  626. << ": The file "
  627. "includes the moc file \""
  628. << currentMoc << "\", but does not contain a " << macroName
  629. << " macro. Running moc on "
  630. << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
  631. << ".cpp\" for a compatibility with "
  632. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  633. << std::endl;
  634. this->LogWarning(err.str());
  635. } else {
  636. std::ostringstream err;
  637. err << "AUTOGEN: warning: " << absFilename
  638. << ": The file "
  639. "includes the moc file \""
  640. << currentMoc << "\" instead of \"moc_" << basename
  641. << ".cpp\". "
  642. "Running moc on "
  643. << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
  644. << ".cpp\" for compatibility with "
  645. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  646. << std::endl;
  647. this->LogWarning(err.str());
  648. }
  649. } else {
  650. std::ostringstream err;
  651. err << "AUTOGEN: error: " << absFilename
  652. << ": The file "
  653. "includes the moc file \""
  654. << currentMoc
  655. << "\", which seems to be the moc file from a different "
  656. "source file. CMake also could not find a matching "
  657. "header.\n"
  658. << std::endl;
  659. this->LogError(err.str());
  660. return false;
  661. }
  662. } else {
  663. dotMocIncluded = true;
  664. ownDotMocFile = currentMoc;
  665. }
  666. includedMocs[fileToMoc] = currentMoc;
  667. }
  668. matchOffset += mocIncludeRegExp.end();
  669. } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  670. }
  671. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  672. // If this is the case, the moc_foo.cpp should probably be generated from
  673. // foo.cpp instead of foo.h, because otherwise it won't build.
  674. // But warn, since this is not how it is supposed to be used.
  675. if (!dotMocIncluded && requiresMoc) {
  676. if (mocUnderscoreIncluded) {
  677. // this is for KDE4 compatibility:
  678. std::ostringstream err;
  679. err << "AUTOGEN: warning: " << absFilename << ": The file "
  680. << "contains a " << macroName << " macro, but does not "
  681. "include "
  682. << "\"" << scannedFileBasename << ".moc\", but instead "
  683. "includes "
  684. << "\"" << ownMocUnderscoreFile << "\". Running moc on "
  685. << "\"" << absFilename << "\" ! Better include \""
  686. << scannedFileBasename
  687. << ".moc\" for compatibility with "
  688. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  689. << std::endl;
  690. this->LogWarning(err.str());
  691. includedMocs[absFilename] = ownMocUnderscoreFile;
  692. includedMocs.erase(ownMocHeaderFile);
  693. } else {
  694. // otherwise always error out since it will not compile:
  695. std::ostringstream err;
  696. err << "AUTOGEN: error: " << absFilename << ": The file "
  697. << "contains a " << macroName << " macro, but does not "
  698. "include "
  699. << "\"" << scannedFileBasename << ".moc\" !\n"
  700. << std::endl;
  701. this->LogError(err.str());
  702. return false;
  703. }
  704. }
  705. return true;
  706. }
  707. /**
  708. * @return True on success
  709. */
  710. bool cmQtAutoGenerators::StrictParseCppFile(
  711. const std::string& absFilename,
  712. const std::vector<std::string>& headerExtensions,
  713. std::map<std::string, std::string>& includedMocs,
  714. std::map<std::string, std::vector<std::string> >& includedUis)
  715. {
  716. cmsys::RegularExpression mocIncludeRegExp(
  717. "[\n][ \t]*#[ \t]*include[ \t]+"
  718. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  719. const std::string contentsString = ReadAll(absFilename);
  720. if (contentsString.empty()) {
  721. std::ostringstream err;
  722. err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  723. << std::endl;
  724. this->LogWarning(err.str());
  725. return true;
  726. }
  727. this->ParseForUic(absFilename, contentsString, includedUis);
  728. if (this->MocExecutable.empty()) {
  729. return true;
  730. }
  731. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  732. cmsys::SystemTools::GetRealPath(absFilename)) +
  733. '/';
  734. const std::string scannedFileBasename =
  735. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  736. bool dotMocIncluded = false;
  737. std::string::size_type matchOffset = 0;
  738. // first a simple string check for "moc" is *much* faster than the regexp,
  739. // and if the string search already fails, we don't have to try the
  740. // expensive regexp
  741. if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) &&
  742. (mocIncludeRegExp.find(contentsString))) {
  743. // for every moc include in the file
  744. do {
  745. const std::string currentMoc = mocIncludeRegExp.match(1);
  746. std::string basename =
  747. cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
  748. const bool mocUnderscoreStyle = cmHasLiteralPrefix(basename, "moc_");
  749. // If the moc include is of the moc_foo.cpp style we expect
  750. // the Q_OBJECT class declaration in a header file.
  751. // If the moc include is of the foo.moc style we need to look for
  752. // a Q_OBJECT macro in the current source file, if it contains the
  753. // macro we generate the moc file from the source file.
  754. if (mocUnderscoreStyle) {
  755. // basename should be the part of the moc filename used for
  756. // finding the correct header, so we need to remove the moc_ part
  757. basename = basename.substr(4);
  758. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  759. std::string headerToMoc =
  760. findMatchingHeader(absPath, mocSubDir, basename, headerExtensions);
  761. if (!headerToMoc.empty()) {
  762. includedMocs[headerToMoc] = currentMoc;
  763. } else {
  764. std::ostringstream err;
  765. err << "AUTOGEN: error: " << absFilename << " The file "
  766. << "includes the moc file \"" << currentMoc << "\", "
  767. << "but could not find header \"" << basename << '{'
  768. << this->JoinExts(headerExtensions) << "}\" ";
  769. if (mocSubDir.empty()) {
  770. err << "in " << absPath << "\n" << std::endl;
  771. } else {
  772. err << "neither in " << absPath << " nor in " << mocSubDir << "\n"
  773. << std::endl;
  774. }
  775. this->LogError(err.str());
  776. return false;
  777. }
  778. } else {
  779. if (basename != scannedFileBasename) {
  780. std::ostringstream err;
  781. err << "AUTOGEN: error: " << absFilename
  782. << ": The file "
  783. "includes the moc file \""
  784. << currentMoc
  785. << "\", which seems to be the moc file from a different "
  786. "source file. This is not supported. "
  787. "Include \""
  788. << scannedFileBasename << ".moc\" to run "
  789. "moc on this source file.\n"
  790. << std::endl;
  791. this->LogError(err.str());
  792. return false;
  793. }
  794. dotMocIncluded = true;
  795. includedMocs[absFilename] = currentMoc;
  796. }
  797. matchOffset += mocIncludeRegExp.end();
  798. } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  799. }
  800. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  801. // If this is the case, the moc_foo.cpp should probably be generated from
  802. // foo.cpp instead of foo.h, because otherwise it won't build.
  803. // But warn, since this is not how it is supposed to be used.
  804. std::string macroName;
  805. if (!dotMocIncluded && requiresMocing(contentsString, macroName)) {
  806. // otherwise always error out since it will not compile:
  807. std::ostringstream err;
  808. err << "AUTOGEN: error: " << absFilename << ": The file "
  809. << "contains a " << macroName << " macro, but does not include "
  810. << "\"" << scannedFileBasename << ".moc\" !\n"
  811. << std::endl;
  812. this->LogError(err.str());
  813. return false;
  814. }
  815. return true;
  816. }
  817. /**
  818. * @return True on success
  819. */
  820. bool cmQtAutoGenerators::ParseSourceFile(
  821. const std::string& absFilename,
  822. const std::vector<std::string>& headerExtensions,
  823. std::map<std::string, std::string>& includedMocs,
  824. std::map<std::string, std::vector<std::string> >& includedUis, bool relaxed)
  825. {
  826. cmsys::RegularExpression mocIncludeRegExp(
  827. "[\n][ \t]*#[ \t]*include[ \t]+"
  828. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  829. const std::string contentsString = ReadAll(absFilename);
  830. if (contentsString.empty()) {
  831. std::ostringstream err;
  832. err << "AUTOGEN: warning: " << absFilename << "\n"
  833. << "The file is empty\n";
  834. this->LogWarning(err.str());
  835. return true;
  836. }
  837. // Parse source contents for UIC
  838. this->ParseForUic(absFilename, contentsString, includedUis);
  839. // Continue with moc parsing on demand
  840. if (this->MocExecutable.empty()) {
  841. return true;
  842. }
  843. const std::string scannedFileAbsPath =
  844. cmsys::SystemTools::GetFilenamePath(
  845. cmsys::SystemTools::GetRealPath(absFilename)) +
  846. '/';
  847. const std::string scannedFileBasename =
  848. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  849. std::string macroName;
  850. const bool requiresMoc = requiresMocing(contentsString, macroName);
  851. bool ownDotMocIncluded = false;
  852. bool ownMocUnderscoreIncluded = false;
  853. std::string ownMocUnderscoreFile;
  854. std::string ownMocHeaderFile;
  855. std::string::size_type matchOffset = 0;
  856. // first a simple string check for "moc" is *much* faster than the regexp,
  857. // and if the string search already fails, we don't have to try the
  858. // expensive regexp
  859. if (strstr(contentsString.c_str(), "moc") != CM_NULLPTR) {
  860. // Iterate over all included moc files
  861. const char* contentChars = contentsString.c_str();
  862. while (mocIncludeRegExp.find(contentChars)) {
  863. const std::string currentMoc = mocIncludeRegExp.match(1);
  864. // Basename of the current moc include
  865. std::string basename =
  866. cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
  867. // If the moc include is of the moc_foo.cpp style we expect
  868. // the Q_OBJECT class declaration in a header file.
  869. // If the moc include is of the foo.moc style we need to look for
  870. // a Q_OBJECT macro in the current source file, if it contains the
  871. // macro we generate the moc file from the source file.
  872. if (cmHasLiteralPrefix(basename, "moc_")) {
  873. // Include: moc_FOO.cxx
  874. // basename should be the part of the moc filename used for
  875. // finding the correct header, so we need to remove the moc_ part
  876. basename = basename.substr(4);
  877. const std::string mocSubDir =
  878. extractSubDir(scannedFileAbsPath, currentMoc);
  879. const std::string headerToMoc = findMatchingHeader(
  880. scannedFileAbsPath, mocSubDir, basename, headerExtensions);
  881. if (!headerToMoc.empty()) {
  882. includedMocs[headerToMoc] = currentMoc;
  883. if (relaxed && (basename == scannedFileBasename)) {
  884. ownMocUnderscoreIncluded = true;
  885. ownMocUnderscoreFile = currentMoc;
  886. ownMocHeaderFile = headerToMoc;
  887. }
  888. } else {
  889. std::ostringstream err;
  890. err << "AUTOGEN: error: " << absFilename << "\n"
  891. << "The file includes the moc file \"" << currentMoc
  892. << "\", but could not find header \"" << basename << '{'
  893. << this->JoinExts(headerExtensions) << "}\" ";
  894. if (mocSubDir.empty()) {
  895. err << "in " << scannedFileAbsPath << "\n";
  896. } else {
  897. err << "neither in " << scannedFileAbsPath << " nor in "
  898. << mocSubDir << "\n";
  899. }
  900. this->LogError(err.str());
  901. return false;
  902. }
  903. } else {
  904. // Include: FOO.moc
  905. std::string fileToMoc;
  906. if (relaxed) {
  907. // Mode: Relaxed
  908. if (!requiresMoc || basename != scannedFileBasename) {
  909. const std::string mocSubDir =
  910. extractSubDir(scannedFileAbsPath, currentMoc);
  911. const std::string headerToMoc = findMatchingHeader(
  912. scannedFileAbsPath, mocSubDir, basename, headerExtensions);
  913. if (!headerToMoc.empty()) {
  914. // This is for KDE4 compatibility:
  915. fileToMoc = headerToMoc;
  916. if (!requiresMoc && basename == scannedFileBasename) {
  917. std::ostringstream err;
  918. err << "AUTOMOC: warning: " << absFilename << "\n"
  919. << "The file includes the moc file \"" << currentMoc
  920. << "\", but does not contain a " << macroName
  921. << " macro. Running moc on "
  922. << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
  923. << ".cpp\" for a compatibility with "
  924. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
  925. this->LogWarning(err.str());
  926. } else {
  927. std::ostringstream err;
  928. err << "AUTOMOC: warning: " << absFilename << "\n"
  929. << "The file includes the moc file \"" << currentMoc
  930. << "\" instead of \"moc_" << basename
  931. << ".cpp\". Running moc on "
  932. << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
  933. << ".cpp\" for compatibility with "
  934. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
  935. this->LogWarning(err.str());
  936. }
  937. } else {
  938. std::ostringstream err;
  939. err << "AUTOMOC: error: " << absFilename << "\n"
  940. << "The file includes the moc file \"" << currentMoc
  941. << "\", which seems to be the moc file from a different "
  942. "source file. CMake also could not find a matching "
  943. "header.\n";
  944. this->LogError(err.str());
  945. return false;
  946. }
  947. } else {
  948. // Include self
  949. fileToMoc = absFilename;
  950. ownDotMocIncluded = true;
  951. }
  952. } else {
  953. // Mode: Strict
  954. if (basename != scannedFileBasename) {
  955. // Don't allow FOO.moc include other than self in strict mode
  956. std::ostringstream err;
  957. err << "AUTOMOC: error: " << absFilename << "\n"
  958. << "The file includes the moc file \"" << currentMoc
  959. << "\", which seems to be the moc file from a different "
  960. "source file. This is not supported. Include \""
  961. << scannedFileBasename
  962. << ".moc\" to run moc on this source file.\n";
  963. this->LogError(err.str());
  964. return false;
  965. } else {
  966. // Include self
  967. fileToMoc = absFilename;
  968. ownDotMocIncluded = true;
  969. }
  970. }
  971. if (!fileToMoc.empty()) {
  972. includedMocs[fileToMoc] = currentMoc;
  973. }
  974. }
  975. // Forward content pointer
  976. contentChars += mocIncludeRegExp.end();
  977. }
  978. }
  979. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  980. // If this is the case, the moc_foo.cpp should probably be generated from
  981. // foo.cpp instead of foo.h, because otherwise it won't build.
  982. // But warn, since this is not how it is supposed to be used.
  983. if (requiresMoc && !ownDotMocIncluded) {
  984. if (relaxed && ownMocUnderscoreIncluded) {
  985. // This is for KDE4 compatibility:
  986. std::ostringstream err;
  987. err << "AUTOMOC: warning: " << absFilename << "\n"
  988. << "The file contains a " << macroName
  989. << " macro, but does not include "
  990. << "\"" << scannedFileBasename << ".moc\", but instead includes "
  991. << "\"" << ownMocUnderscoreFile << "\". Running moc on "
  992. << "\"" << absFilename << "\" ! Better include \""
  993. << scannedFileBasename
  994. << ".moc\" for compatibility with "
  995. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
  996. this->LogWarning(err.str());
  997. // Use scanned source file instead of scanned header file as moc source
  998. includedMocs[absFilename] = ownMocUnderscoreFile;
  999. includedMocs.erase(ownMocHeaderFile);
  1000. } else {
  1001. // Otherwise always error out since it will not compile:
  1002. std::ostringstream err;
  1003. err << "AUTOMOC: error: " << absFilename << "\n"
  1004. << "The file contains a " << macroName
  1005. << " macro, but does not include "
  1006. << "\"" << scannedFileBasename << ".moc\" !\n";
  1007. this->LogError(err.str());
  1008. return false;
  1009. }
  1010. }
  1011. return true;
  1012. }
  1013. void cmQtAutoGenerators::ParseForUic(
  1014. const std::string& absFilename,
  1015. std::map<std::string, std::vector<std::string> >& includedUis)
  1016. {
  1017. if (this->UicExecutable.empty()) {
  1018. return;
  1019. }
  1020. const std::string contentsString = ReadAll(absFilename);
  1021. if (contentsString.empty()) {
  1022. std::ostringstream err;
  1023. err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  1024. << std::endl;
  1025. this->LogWarning(err.str());
  1026. return;
  1027. }
  1028. this->ParseForUic(absFilename, contentsString, includedUis);
  1029. }
  1030. void cmQtAutoGenerators::ParseForUic(
  1031. const std::string& absFilename, const std::string& contentsString,
  1032. std::map<std::string, std::vector<std::string> >& includedUis)
  1033. {
  1034. if (this->UicExecutable.empty()) {
  1035. return;
  1036. }
  1037. const std::string realName = cmsys::SystemTools::GetRealPath(absFilename);
  1038. cmsys::RegularExpression uiIncludeRegExp(
  1039. "[\n][ \t]*#[ \t]*include[ \t]+"
  1040. "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
  1041. const char* contentChars = contentsString.c_str();
  1042. if (strstr(contentChars, "ui_") != CM_NULLPTR) {
  1043. while (uiIncludeRegExp.find(contentChars)) {
  1044. const std::string currentUi = uiIncludeRegExp.match(1);
  1045. const std::string basename =
  1046. cmsys::SystemTools::GetFilenameWithoutLastExtension(currentUi);
  1047. // basename should be the part of the ui filename used for
  1048. // finding the correct header, so we need to remove the ui_ part
  1049. includedUis[realName].push_back(basename.substr(3));
  1050. contentChars += uiIncludeRegExp.end();
  1051. }
  1052. }
  1053. }
  1054. void cmQtAutoGenerators::SearchHeadersForCppFile(
  1055. const std::string& absFilename,
  1056. const std::vector<std::string>& headerExtensions,
  1057. std::set<std::string>& absHeaders)
  1058. {
  1059. // search for header files and private header files we may need to moc:
  1060. const std::string basename =
  1061. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  1062. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  1063. cmsys::SystemTools::GetRealPath(absFilename)) +
  1064. '/';
  1065. for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  1066. ext != headerExtensions.end(); ++ext) {
  1067. const std::string headerName = absPath + basename + "." + (*ext);
  1068. if (cmsys::SystemTools::FileExists(headerName.c_str())) {
  1069. absHeaders.insert(headerName);
  1070. break;
  1071. }
  1072. }
  1073. for (std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  1074. ext != headerExtensions.end(); ++ext) {
  1075. const std::string privateHeaderName = absPath + basename + "_p." + (*ext);
  1076. if (cmsys::SystemTools::FileExists(privateHeaderName.c_str())) {
  1077. absHeaders.insert(privateHeaderName);
  1078. break;
  1079. }
  1080. }
  1081. }
  1082. void cmQtAutoGenerators::ParseHeaders(
  1083. const std::set<std::string>& absHeaders,
  1084. const std::map<std::string, std::string>& includedMocs,
  1085. std::map<std::string, std::string>& notIncludedMocs,
  1086. std::map<std::string, std::vector<std::string> >& includedUis)
  1087. {
  1088. for (std::set<std::string>::const_iterator hIt = absHeaders.begin();
  1089. hIt != absHeaders.end(); ++hIt) {
  1090. const std::string& headerName = *hIt;
  1091. const std::string contents = ReadAll(headerName);
  1092. if (!this->MocExecutable.empty() &&
  1093. includedMocs.find(headerName) == includedMocs.end()) {
  1094. if (this->Verbose) {
  1095. std::ostringstream err;
  1096. err << "AUTOGEN: Checking " << headerName << std::endl;
  1097. this->LogInfo(err.str());
  1098. }
  1099. std::string macroName;
  1100. if (requiresMocing(contents, macroName)) {
  1101. notIncludedMocs[headerName] = fpathCheckSum.getPart(headerName) +
  1102. "/moc_" +
  1103. cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) +
  1104. ".cpp";
  1105. }
  1106. }
  1107. this->ParseForUic(headerName, contents, includedUis);
  1108. }
  1109. }
  1110. bool cmQtAutoGenerators::GenerateMocFiles(
  1111. const std::map<std::string, std::string>& includedMocs,
  1112. const std::map<std::string, std::string>& notIncludedMocs)
  1113. {
  1114. // look for name collisions
  1115. {
  1116. std::multimap<std::string, std::string> collisions;
  1117. // Test merged map of included and notIncluded
  1118. std::map<std::string, std::string> mergedMocs(includedMocs);
  1119. mergedMocs.insert(notIncludedMocs.begin(), notIncludedMocs.end());
  1120. if (this->NameCollisionTest(mergedMocs, collisions)) {
  1121. std::ostringstream err;
  1122. err << "AUTOGEN: error: "
  1123. "The same moc file will be generated "
  1124. "from different sources."
  1125. << std::endl
  1126. << "To avoid this error either" << std::endl
  1127. << "- rename the source files or" << std::endl
  1128. << "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl;
  1129. this->LogErrorNameCollision(err.str(), collisions);
  1130. return false;
  1131. }
  1132. }
  1133. // generate moc files that are included by source files.
  1134. {
  1135. const std::string subDirPrefix = "include/";
  1136. for (std::map<std::string, std::string>::const_iterator it =
  1137. includedMocs.begin();
  1138. it != includedMocs.end(); ++it) {
  1139. if (!this->GenerateMoc(it->first, it->second, subDirPrefix)) {
  1140. if (this->RunMocFailed) {
  1141. return false;
  1142. }
  1143. }
  1144. }
  1145. }
  1146. // generate moc files that are _not_ included by source files.
  1147. bool automocCppChanged = false;
  1148. {
  1149. const std::string subDirPrefix;
  1150. for (std::map<std::string, std::string>::const_iterator it =
  1151. notIncludedMocs.begin();
  1152. it != notIncludedMocs.end(); ++it) {
  1153. if (this->GenerateMoc(it->first, it->second, subDirPrefix)) {
  1154. automocCppChanged = true;
  1155. } else {
  1156. if (this->RunMocFailed) {
  1157. return false;
  1158. }
  1159. }
  1160. }
  1161. }
  1162. // Compose moc_compilation.cpp content
  1163. std::string automocSource;
  1164. {
  1165. std::ostringstream outStream;
  1166. outStream << "/* This file is autogenerated, do not edit*/\n";
  1167. if (notIncludedMocs.empty()) {
  1168. // Dummy content
  1169. outStream << "enum some_compilers { need_more_than_nothing };\n";
  1170. } else {
  1171. // Valid content
  1172. for (std::map<std::string, std::string>::const_iterator it =
  1173. notIncludedMocs.begin();
  1174. it != notIncludedMocs.end(); ++it) {
  1175. outStream << "#include \"" << it->second << "\"\n";
  1176. }
  1177. }
  1178. outStream.flush();
  1179. automocSource = outStream.str();
  1180. }
  1181. // Check if we even need to update moc_compilation.cpp
  1182. if (!automocCppChanged) {
  1183. // compare contents of the moc_compilation.cpp file
  1184. const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs);
  1185. if (oldContents == automocSource) {
  1186. // nothing changed: don't touch the moc_compilation.cpp file
  1187. if (this->Verbose) {
  1188. std::ostringstream err;
  1189. err << "AUTOGEN: " << this->OutMocCppFilenameRel << " still up to date"
  1190. << std::endl;
  1191. this->LogInfo(err.str());
  1192. }
  1193. return true;
  1194. }
  1195. }
  1196. // Actually write moc_compilation.cpp
  1197. {
  1198. std::string msg = "Generating MOC compilation ";
  1199. msg += this->OutMocCppFilenameRel;
  1200. this->LogBold(msg);
  1201. }
  1202. // Make sure the parent directory exists
  1203. bool success = this->MakeParentDirectory(this->OutMocCppFilenameAbs);
  1204. if (success) {
  1205. cmsys::ofstream outfile;
  1206. outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc);
  1207. if (!outfile) {
  1208. success = false;
  1209. std::ostringstream err;
  1210. err << "AUTOGEN: error opening " << this->OutMocCppFilenameAbs << "\n";
  1211. this->LogError(err.str());
  1212. } else {
  1213. outfile << automocSource;
  1214. // Check for write errors
  1215. if (!outfile.good()) {
  1216. success = false;
  1217. std::ostringstream err;
  1218. err << "AUTOGEN: error writing " << this->OutMocCppFilenameAbs << "\n";
  1219. this->LogError(err.str());
  1220. }
  1221. }
  1222. }
  1223. return success;
  1224. }
  1225. /**
  1226. * @return True if a moc file was created. False may indicate an error.
  1227. */
  1228. bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
  1229. const std::string& mocFileName,
  1230. const std::string& subDirPrefix)
  1231. {
  1232. const std::string mocFileRel =
  1233. this->AutogenBuildSubDir + subDirPrefix + mocFileName;
  1234. const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel;
  1235. int sourceNewerThanMoc = 0;
  1236. bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFileAbs,
  1237. &sourceNewerThanMoc);
  1238. if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) {
  1239. // Log
  1240. this->LogBold("Generating MOC source " + mocFileRel);
  1241. // Make sure the parent directory exists
  1242. if (!this->MakeParentDirectory(mocFileAbs)) {
  1243. this->RunMocFailed = true;
  1244. return false;
  1245. }
  1246. std::vector<std::string> command;
  1247. command.push_back(this->MocExecutable);
  1248. command.insert(command.end(), this->MocIncludes.begin(),
  1249. this->MocIncludes.end());
  1250. command.insert(command.end(), this->MocDefinitions.begin(),
  1251. this->MocDefinitions.end());
  1252. command.insert(command.end(), this->MocOptions.begin(),
  1253. this->MocOptions.end());
  1254. #ifdef _WIN32
  1255. command.push_back("-DWIN32");
  1256. #endif
  1257. command.push_back("-o");
  1258. command.push_back(mocFileAbs);
  1259. command.push_back(sourceFile);
  1260. if (this->Verbose) {
  1261. this->LogCommand(command);
  1262. }
  1263. std::string output;
  1264. int retVal = 0;
  1265. bool result =
  1266. cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
  1267. if (!result || retVal) {
  1268. {
  1269. std::ostringstream err;
  1270. err << "AUTOGEN: error: moc process for " << mocFileRel << " failed:\n"
  1271. << output << std::endl;
  1272. this->LogError(err.str());
  1273. }
  1274. cmSystemTools::RemoveFile(mocFileAbs);
  1275. this->RunMocFailed = true;
  1276. return false;
  1277. }
  1278. return true;
  1279. }
  1280. return false;
  1281. }
  1282. bool cmQtAutoGenerators::GenerateUiFiles(
  1283. const std::map<std::string, std::vector<std::string> >& includedUis)
  1284. {
  1285. // single map with input / output names
  1286. std::map<std::string, std::map<std::string, std::string> > uiGenMap;
  1287. std::map<std::string, std::string> testMap;
  1288. for (std::map<std::string, std::vector<std::string> >::const_iterator it =
  1289. includedUis.begin();
  1290. it != includedUis.end(); ++it) {
  1291. // source file path
  1292. std::string sourcePath = cmsys::SystemTools::GetFilenamePath(it->first);
  1293. sourcePath += '/';
  1294. // insert new map for source file an use new reference
  1295. uiGenMap[it->first] = std::map<std::string, std::string>();
  1296. std::map<std::string, std::string>& sourceMap = uiGenMap[it->first];
  1297. for (std::vector<std::string>::const_iterator sit = it->second.begin();
  1298. sit != it->second.end(); ++sit) {
  1299. const std::string& uiFileName = *sit;
  1300. const std::string uiInputFile = sourcePath + uiFileName + ".ui";
  1301. const std::string uiOutputFile = "ui_" + uiFileName + ".h";
  1302. sourceMap[uiInputFile] = uiOutputFile;
  1303. testMap[uiInputFile] = uiOutputFile;
  1304. }
  1305. }
  1306. // look for name collisions
  1307. {
  1308. std::multimap<std::string, std::string> collisions;
  1309. if (this->NameCollisionTest(testMap, collisions)) {
  1310. std::ostringstream err;
  1311. err << "AUTOGEN: error: The same ui_NAME.h file will be generated "
  1312. "from different sources."
  1313. << std::endl
  1314. << "To avoid this error rename the source files." << std::endl;
  1315. this->LogErrorNameCollision(err.str(), collisions);
  1316. return false;
  1317. }
  1318. }
  1319. testMap.clear();
  1320. // generate ui files
  1321. for (std::map<std::string,
  1322. std::map<std::string, std::string> >::const_iterator it =
  1323. uiGenMap.begin();
  1324. it != uiGenMap.end(); ++it) {
  1325. for (std::map<std::string, std::string>::const_iterator sit =
  1326. it->second.begin();
  1327. sit != it->second.end(); ++sit) {
  1328. if (!this->GenerateUi(it->first, sit->first, sit->second)) {
  1329. if (this->RunUicFailed) {
  1330. return false;
  1331. }
  1332. }
  1333. }
  1334. }
  1335. return true;
  1336. }
  1337. /**
  1338. * @return True if a uic file was created. False may indicate an error.
  1339. */
  1340. bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
  1341. const std::string& uiInputFile,
  1342. const std::string& uiOutputFile)
  1343. {
  1344. const std::string uicFileRel =
  1345. this->AutogenBuildSubDir + "include/" + uiOutputFile;
  1346. const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel;
  1347. int sourceNewerThanUi = 0;
  1348. bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uicFileAbs,
  1349. &sourceNewerThanUi);
  1350. if (this->GenerateAll || !success || sourceNewerThanUi >= 0) {
  1351. // Log
  1352. this->LogBold("Generating UIC header " + uicFileRel);
  1353. // Make sure the parent directory exists
  1354. if (!this->MakeParentDirectory(uicFileAbs)) {
  1355. this->RunUicFailed = true;
  1356. return false;
  1357. }
  1358. std::vector<std::string> command;
  1359. command.push_back(this->UicExecutable);
  1360. std::vector<std::string> opts = this->UicTargetOptions;
  1361. std::map<std::string, std::string>::const_iterator optionIt =
  1362. this->UicOptions.find(uiInputFile);
  1363. if (optionIt != this->UicOptions.end()) {
  1364. std::vector<std::string> fileOpts;
  1365. cmSystemTools::ExpandListArgument(optionIt->second, fileOpts);
  1366. cmQtAutoGenerators::MergeUicOptions(opts, fileOpts,
  1367. this->QtMajorVersion == "5");
  1368. }
  1369. command.insert(command.end(), opts.begin(), opts.end());
  1370. command.push_back("-o");
  1371. command.push_back(uicFileAbs);
  1372. command.push_back(uiInputFile);
  1373. if (this->Verbose) {
  1374. this->LogCommand(command);
  1375. }
  1376. std::string output;
  1377. int retVal = 0;
  1378. bool result =
  1379. cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
  1380. if (!result || retVal) {
  1381. {
  1382. std::ostringstream err;
  1383. err << "AUTOUIC: error: uic process for " << uicFileRel
  1384. << " needed by\n \"" << realName << "\"\nfailed:\n"
  1385. << output << std::endl;
  1386. this->LogError(err.str());
  1387. }
  1388. cmSystemTools::RemoveFile(uicFileAbs);
  1389. this->RunUicFailed = true;
  1390. return false;
  1391. }
  1392. return true;
  1393. }
  1394. return false;
  1395. }
  1396. bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile,
  1397. const std::string& rccOutput)
  1398. {
  1399. std::vector<std::string> const& files = this->RccInputs[qrcFile];
  1400. for (std::vector<std::string>::const_iterator it = files.begin();
  1401. it != files.end(); ++it) {
  1402. int inputNewerThanQrc = 0;
  1403. bool success =
  1404. cmsys::SystemTools::FileTimeCompare(*it, rccOutput, &inputNewerThanQrc);
  1405. if (!success || inputNewerThanQrc >= 0) {
  1406. return true;
  1407. }
  1408. }
  1409. return false;
  1410. }
  1411. bool cmQtAutoGenerators::GenerateQrcFiles()
  1412. {
  1413. // generate single map with input / output names
  1414. std::map<std::string, std::string> qrcGenMap;
  1415. for (std::vector<std::string>::const_iterator si = this->RccSources.begin();
  1416. si != this->RccSources.end(); ++si) {
  1417. const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
  1418. if (ext == ".qrc") {
  1419. qrcGenMap[*si] = this->AutogenBuildSubDir + fpathCheckSum.getPart(*si) +
  1420. "/qrc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(*si) +
  1421. ".cpp";
  1422. }
  1423. }
  1424. // look for name collisions
  1425. {
  1426. std::multimap<std::string, std::string> collisions;
  1427. if (this->NameCollisionTest(qrcGenMap, collisions)) {
  1428. std::ostringstream err;
  1429. err << "AUTOGEN: error: The same qrc_NAME.cpp file"
  1430. " will be generated from different sources."
  1431. << std::endl
  1432. << "To avoid this error rename the source .qrc files." << std::endl;
  1433. this->LogErrorNameCollision(err.str(), collisions);
  1434. return false;
  1435. }
  1436. }
  1437. // generate qrc files
  1438. for (std::map<std::string, std::string>::const_iterator si =
  1439. qrcGenMap.begin();
  1440. si != qrcGenMap.end(); ++si) {
  1441. bool unique = FileNameIsUnique(si->first, qrcGenMap);
  1442. if (!this->GenerateQrc(si->first, si->second, unique)) {
  1443. if (this->RunRccFailed) {
  1444. return false;
  1445. }
  1446. }
  1447. }
  1448. return true;
  1449. }
  1450. /**
  1451. * @return True if a rcc file was created. False may indicate an error.
  1452. */
  1453. bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
  1454. const std::string& qrcOutputFile,
  1455. bool unique_n)
  1456. {
  1457. std::string symbolName =
  1458. cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
  1459. if (!unique_n) {
  1460. symbolName += "_";
  1461. symbolName += fpathCheckSum.getPart(qrcInputFile);
  1462. }
  1463. // Replace '-' with '_'. The former is valid for
  1464. // file names but not for symbol names.
  1465. std::replace(symbolName.begin(), symbolName.end(), '-', '_');
  1466. const std::string qrcBuildFile = this->CurrentBinaryDir + qrcOutputFile;
  1467. int sourceNewerThanQrc = 0;
  1468. bool generateQrc = !cmsys::SystemTools::FileTimeCompare(
  1469. qrcInputFile, qrcBuildFile, &sourceNewerThanQrc);
  1470. generateQrc = generateQrc || (sourceNewerThanQrc >= 0);
  1471. generateQrc =
  1472. generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile);
  1473. if (this->GenerateAll || generateQrc) {
  1474. {
  1475. std::string msg = "Generating RCC source ";
  1476. msg += qrcOutputFile;
  1477. this->LogBold(msg);
  1478. }
  1479. // Make sure the parent directory exists
  1480. if (!this->MakeParentDirectory(qrcOutputFile)) {
  1481. this->RunRccFailed = true;
  1482. return false;
  1483. }
  1484. std::vector<std::string> command;
  1485. command.push_back(this->RccExecutable);
  1486. {
  1487. std::map<std::string, std::string>::const_iterator optionIt =
  1488. this->RccOptions.find(qrcInputFile);
  1489. if (optionIt != this->RccOptions.end()) {
  1490. cmSystemTools::ExpandListArgument(optionIt->second, command);
  1491. }
  1492. }
  1493. command.push_back("-name");
  1494. command.push_back(symbolName);
  1495. command.push_back("-o");
  1496. command.push_back(qrcBuildFile);
  1497. command.push_back(qrcInputFile);
  1498. if (this->Verbose) {
  1499. this->LogCommand(command);
  1500. }
  1501. std::string output;
  1502. int retVal = 0;
  1503. bool result =
  1504. cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
  1505. if (!result || retVal) {
  1506. {
  1507. std::ostringstream err;
  1508. err << "AUTORCC: error: rcc process for " << qrcOutputFile
  1509. << " failed:\n"
  1510. << output << std::endl;
  1511. this->LogError(err.str());
  1512. }
  1513. cmSystemTools::RemoveFile(qrcBuildFile);
  1514. this->RunRccFailed = true;
  1515. return false;
  1516. }
  1517. return true;
  1518. }
  1519. return false;
  1520. }
  1521. /**
  1522. * @brief Collects name collisions as output/input pairs
  1523. * @return True if there were collisions
  1524. */
  1525. bool cmQtAutoGenerators::NameCollisionTest(
  1526. const std::map<std::string, std::string>& genFiles,
  1527. std::multimap<std::string, std::string>& collisions)
  1528. {
  1529. typedef std::map<std::string, std::string>::const_iterator Iter;
  1530. typedef std::map<std::string, std::string>::value_type VType;
  1531. for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) {
  1532. bool first_match(true);
  1533. for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) {
  1534. if (ait->second == bit->second) {
  1535. if (first_match) {
  1536. if (collisions.find(ait->second) != collisions.end()) {
  1537. // We already know of this collision from before
  1538. break;
  1539. }
  1540. collisions.insert(VType(ait->second, ait->first));
  1541. first_match = false;
  1542. }
  1543. collisions.insert(VType(bit->second, bit->first));
  1544. }
  1545. }
  1546. }
  1547. return !collisions.empty();
  1548. }
  1549. void cmQtAutoGenerators::LogErrorNameCollision(
  1550. const std::string& message,
  1551. const std::multimap<std::string, std::string>& collisions)
  1552. {
  1553. typedef std::multimap<std::string, std::string>::const_iterator Iter;
  1554. std::ostringstream err;
  1555. // Add message
  1556. err << message;
  1557. // Append collision list
  1558. for (Iter it = collisions.begin(); it != collisions.end(); ++it) {
  1559. err << it->first << " : " << it->second << std::endl;
  1560. }
  1561. this->LogError(err.str());
  1562. }
  1563. void cmQtAutoGenerators::LogBold(const std::string& message)
  1564. {
  1565. cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
  1566. cmsysTerminal_Color_ForegroundBold,
  1567. message.c_str(), true, this->ColorOutput);
  1568. }
  1569. void cmQtAutoGenerators::LogInfo(const std::string& message)
  1570. {
  1571. std::cout << message.c_str();
  1572. }
  1573. void cmQtAutoGenerators::LogWarning(const std::string& message)
  1574. {
  1575. std::ostringstream ostr;
  1576. ostr << message << "\n";
  1577. std::cout << message.c_str();
  1578. }
  1579. void cmQtAutoGenerators::LogError(const std::string& message)
  1580. {
  1581. std::ostringstream ostr;
  1582. ostr << message << "\n\n";
  1583. std::cerr << ostr.str();
  1584. }
  1585. void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
  1586. {
  1587. std::ostringstream sbuf;
  1588. for (std::vector<std::string>::const_iterator cmdIt = command.begin();
  1589. cmdIt != command.end(); ++cmdIt) {
  1590. if (cmdIt != command.begin()) {
  1591. sbuf << " ";
  1592. }
  1593. sbuf << *cmdIt;
  1594. }
  1595. if (!sbuf.str().empty()) {
  1596. sbuf << std::endl;
  1597. this->LogInfo(sbuf.str());
  1598. }
  1599. }
  1600. /**
  1601. * @brief Generates the parent directory of the given file on demand
  1602. * @return True on success
  1603. */
  1604. bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename)
  1605. {
  1606. bool success = true;
  1607. const std::string dirName = cmSystemTools::GetFilenamePath(filename);
  1608. if (!dirName.empty()) {
  1609. success = cmsys::SystemTools::MakeDirectory(dirName);
  1610. if (!success) {
  1611. std::ostringstream err;
  1612. err << "AUTOGEN: Directory creation failed: " << dirName << std::endl;
  1613. this->LogError(err.str());
  1614. }
  1615. }
  1616. return success;
  1617. }
  1618. std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst)
  1619. {
  1620. if (lst.empty()) {
  1621. return "";
  1622. }
  1623. std::string result;
  1624. std::string separator = ",";
  1625. for (std::vector<std::string>::const_iterator it = lst.begin();
  1626. it != lst.end(); ++it) {
  1627. if (it != lst.begin()) {
  1628. result += separator;
  1629. }
  1630. result += '.' + (*it);
  1631. }
  1632. result.erase(result.end() - 1);
  1633. return result;
  1634. }