cmQtAutoGenerators.cxx 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130
  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 "cmLocalGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmSourceFile.h"
  15. #include "cmSystemTools.h"
  16. #if defined(_WIN32) && !defined(__CYGWIN__)
  17. # include "cmLocalVisualStudioGenerator.h"
  18. #endif
  19. #include <cmsys/Terminal.h>
  20. #include <cmsys/ios/sstream>
  21. #include <cmsys/FStream.hxx>
  22. #include <assert.h>
  23. #include <string.h>
  24. #if defined(__APPLE__)
  25. #include <unistd.h>
  26. #endif
  27. #include "cmQtAutoGenerators.h"
  28. static bool requiresMocing(const std::string& text, std::string &macroName)
  29. {
  30. // this simple check is much much faster than the regexp
  31. if (strstr(text.c_str(), "Q_OBJECT") == NULL
  32. && strstr(text.c_str(), "Q_GADGET") == NULL)
  33. {
  34. return false;
  35. }
  36. cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
  37. if (qObjectRegExp.find(text))
  38. {
  39. macroName = "Q_OBJECT";
  40. return true;
  41. }
  42. cmsys::RegularExpression qGadgetRegExp("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]");
  43. if (qGadgetRegExp.find(text))
  44. {
  45. macroName = "Q_GADGET";
  46. return true;
  47. }
  48. return false;
  49. }
  50. static std::string findMatchingHeader(const std::string& absPath,
  51. const std::string& mocSubDir,
  52. const std::string& basename,
  53. const std::vector<std::string>& headerExtensions)
  54. {
  55. std::string header;
  56. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  57. ext != headerExtensions.end();
  58. ++ext)
  59. {
  60. std::string sourceFilePath = absPath + basename + "." + (*ext);
  61. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
  62. {
  63. header = sourceFilePath;
  64. break;
  65. }
  66. if (!mocSubDir.empty())
  67. {
  68. sourceFilePath = mocSubDir + basename + "." + (*ext);
  69. if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
  70. {
  71. header = sourceFilePath;
  72. break;
  73. }
  74. }
  75. }
  76. return header;
  77. }
  78. static std::string extractSubDir(const std::string& absPath,
  79. const std::string& currentMoc)
  80. {
  81. std::string subDir;
  82. if (currentMoc.find_first_of('/') != std::string::npos)
  83. {
  84. subDir = absPath
  85. + cmsys::SystemTools::GetFilenamePath(currentMoc) + '/';
  86. }
  87. return subDir;
  88. }
  89. static void copyTargetProperty(cmTarget* destinationTarget,
  90. cmTarget* sourceTarget,
  91. const char* propertyName)
  92. {
  93. const char* propertyValue = sourceTarget->GetProperty(propertyName);
  94. if (propertyValue)
  95. {
  96. destinationTarget->SetProperty(propertyName, propertyValue);
  97. }
  98. }
  99. static std::string ReadAll(const std::string& filename)
  100. {
  101. cmsys::ifstream file(filename.c_str());
  102. cmsys_ios::stringstream stream;
  103. stream << file.rdbuf();
  104. file.close();
  105. return stream.str();
  106. }
  107. cmQtAutoGenerators::cmQtAutoGenerators()
  108. :Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
  109. ,ColorOutput(true)
  110. ,RunMocFailed(false)
  111. ,RunUicFailed(false)
  112. ,RunRccFailed(false)
  113. ,GenerateAll(false)
  114. {
  115. std::string colorEnv = "";
  116. cmsys::SystemTools::GetEnv("COLOR", colorEnv);
  117. if(!colorEnv.empty())
  118. {
  119. if(cmSystemTools::IsOn(colorEnv.c_str()))
  120. {
  121. this->ColorOutput = true;
  122. }
  123. else
  124. {
  125. this->ColorOutput = false;
  126. }
  127. }
  128. }
  129. static std::string getAutogenTargetName(cmTarget const* target)
  130. {
  131. std::string autogenTargetName = target->GetName();
  132. autogenTargetName += "_automoc";
  133. return autogenTargetName;
  134. }
  135. static std::string getAutogenTargetDir(cmTarget const* target)
  136. {
  137. cmMakefile* makefile = target->GetMakefile();
  138. std::string targetDir = makefile->GetCurrentOutputDirectory();
  139. targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
  140. targetDir += "/";
  141. targetDir += getAutogenTargetName(target);
  142. targetDir += ".dir/";
  143. return targetDir;
  144. }
  145. bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target)
  146. {
  147. cmMakefile* makefile = target->GetMakefile();
  148. // don't do anything if there is no Qt4 or Qt5Core (which contains moc):
  149. std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
  150. if (qtMajorVersion == "")
  151. {
  152. qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
  153. }
  154. if (qtMajorVersion != "4" && qtMajorVersion != "5")
  155. {
  156. return false;
  157. }
  158. if (target->GetPropertyAsBool("AUTOMOC"))
  159. {
  160. std::string automocTargetName = getAutogenTargetName(target);
  161. std::string mocCppFile = makefile->GetCurrentOutputDirectory();
  162. mocCppFile += "/";
  163. mocCppFile += automocTargetName;
  164. mocCppFile += ".cpp";
  165. cmSourceFile* mocCppSource = makefile->GetOrCreateSource(
  166. mocCppFile.c_str(),
  167. true);
  168. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
  169. mocCppFile.c_str(), false);
  170. target->AddSourceFile(mocCppSource);
  171. }
  172. // create a custom target for running generators at buildtime:
  173. std::string autogenTargetName = getAutogenTargetName(target);
  174. std::string targetDir = getAutogenTargetDir(target);
  175. cmCustomCommandLine currentLine;
  176. currentLine.push_back(makefile->GetSafeDefinition("CMAKE_COMMAND"));
  177. currentLine.push_back("-E");
  178. currentLine.push_back("cmake_autogen");
  179. currentLine.push_back(targetDir);
  180. currentLine.push_back("$<CONFIGURATION>");
  181. cmCustomCommandLines commandLines;
  182. commandLines.push_back(currentLine);
  183. std::string workingDirectory = cmSystemTools::CollapseFullPath(
  184. "", makefile->GetCurrentOutputDirectory());
  185. std::vector<std::string> depends;
  186. if (const char *autogenDepends =
  187. target->GetProperty("AUTOGEN_TARGET_DEPENDS"))
  188. {
  189. cmSystemTools::ExpandListArgument(autogenDepends, depends);
  190. }
  191. std::vector<std::string> toolNames;
  192. if (target->GetPropertyAsBool("AUTOMOC"))
  193. {
  194. toolNames.push_back("moc");
  195. }
  196. if (target->GetPropertyAsBool("AUTOUIC"))
  197. {
  198. toolNames.push_back("uic");
  199. }
  200. if (target->GetPropertyAsBool("AUTORCC"))
  201. {
  202. toolNames.push_back("rcc");
  203. }
  204. std::string tools = toolNames[0];
  205. toolNames.erase(toolNames.begin());
  206. while (toolNames.size() > 1)
  207. {
  208. tools += ", " + toolNames[0];
  209. toolNames.erase(toolNames.begin());
  210. }
  211. if (toolNames.size() == 1)
  212. {
  213. tools += " and " + toolNames[0];
  214. }
  215. std::string autogenComment = "Automatic " + tools + " for target ";
  216. autogenComment += target->GetName();
  217. #if defined(_WIN32) && !defined(__CYGWIN__)
  218. bool usePRE_BUILD = false;
  219. cmLocalGenerator* localGen = makefile->GetLocalGenerator();
  220. cmGlobalGenerator* gg = localGen->GetGlobalGenerator();
  221. if(strstr(gg->GetName(), "Visual Studio"))
  222. {
  223. cmLocalVisualStudioGenerator* vslg =
  224. static_cast<cmLocalVisualStudioGenerator*>(localGen);
  225. // Under VS >= 7 use a PRE_BUILD event instead of a separate target to
  226. // reduce the number of targets loaded into the IDE.
  227. // This also works around a VS 11 bug that may skip updating the target:
  228. // https://connect.microsoft.com/VisualStudio/feedback/details/769495
  229. usePRE_BUILD = vslg->GetVersion() >= cmLocalVisualStudioGenerator::VS7;
  230. }
  231. if(usePRE_BUILD)
  232. {
  233. // Add the pre-build command directly to bypass the OBJECT_LIBRARY
  234. // rejection in cmMakefile::AddCustomCommandToTarget because we know
  235. // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
  236. std::vector<std::string> no_output;
  237. cmCustomCommand cc(makefile, no_output, depends,
  238. commandLines, autogenComment.c_str(),
  239. workingDirectory.c_str());
  240. cc.SetEscapeOldStyle(false);
  241. cc.SetEscapeAllowMakeVars(true);
  242. target->AddPreBuildCommand(cc);
  243. }
  244. else
  245. #endif
  246. {
  247. cmTarget* autogenTarget = makefile->AddUtilityCommand(
  248. autogenTargetName.c_str(), true,
  249. workingDirectory.c_str(), depends,
  250. commandLines, false, autogenComment.c_str());
  251. // Set target folder
  252. const char* autogenFolder = makefile->GetCMakeInstance()->GetProperty(
  253. "AUTOMOC_TARGETS_FOLDER");
  254. if (!autogenFolder)
  255. {
  256. autogenFolder = makefile->GetCMakeInstance()->GetProperty(
  257. "AUTOGEN_TARGETS_FOLDER");
  258. }
  259. if (autogenFolder && *autogenFolder)
  260. {
  261. autogenTarget->SetProperty("FOLDER", autogenFolder);
  262. }
  263. else
  264. {
  265. // inherit FOLDER property from target (#13688)
  266. copyTargetProperty(autogenTarget, target, "FOLDER");
  267. }
  268. target->AddUtility(autogenTargetName.c_str());
  269. }
  270. return true;
  271. }
  272. static void GetCompileDefinitionsAndDirectories(cmTarget const* target,
  273. const char * config,
  274. std::string &incs,
  275. std::string &defs)
  276. {
  277. cmMakefile* makefile = target->GetMakefile();
  278. cmLocalGenerator* localGen = makefile->GetLocalGenerator();
  279. std::vector<std::string> includeDirs;
  280. cmGeneratorTarget *gtgt = target->GetMakefile()->GetLocalGenerator()
  281. ->GetGlobalGenerator()
  282. ->GetGeneratorTarget(target);
  283. // Get the include dirs for this target, without stripping the implicit
  284. // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667
  285. localGen->GetIncludeDirectories(includeDirs, gtgt, "CXX", config, false);
  286. const char* sep = "";
  287. incs = "";
  288. for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin();
  289. incDirIt != includeDirs.end();
  290. ++incDirIt)
  291. {
  292. incs += sep;
  293. sep = ";";
  294. incs += *incDirIt;
  295. }
  296. std::set<std::string> defines;
  297. localGen->AddCompileDefinitions(defines, target, config);
  298. sep = "";
  299. for(std::set<std::string>::const_iterator defIt = defines.begin();
  300. defIt != defines.end();
  301. ++defIt)
  302. {
  303. defs += sep;
  304. sep = ";";
  305. defs += *defIt;
  306. }
  307. }
  308. void cmQtAutoGenerators::SetupAutoGenerateTarget(cmTarget const* target)
  309. {
  310. cmMakefile* makefile = target->GetMakefile();
  311. // forget the variables added here afterwards again:
  312. cmMakefile::ScopePushPop varScope(makefile);
  313. static_cast<void>(varScope);
  314. // create a custom target for running generators at buildtime:
  315. std::string autogenTargetName = getAutogenTargetName(target);
  316. makefile->AddDefinition("_moc_target_name",
  317. cmLocalGenerator::EscapeForCMake(autogenTargetName.c_str()).c_str());
  318. std::string targetDir = getAutogenTargetDir(target);
  319. const char *qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
  320. if (!qtVersion)
  321. {
  322. qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
  323. }
  324. if (const char *targetQtVersion =
  325. target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", 0))
  326. {
  327. qtVersion = targetQtVersion;
  328. }
  329. if (qtVersion)
  330. {
  331. makefile->AddDefinition("_target_qt_version", qtVersion);
  332. }
  333. std::map<std::string, std::string> configIncludes;
  334. std::map<std::string, std::string> configDefines;
  335. std::map<std::string, std::string> configUicOptions;
  336. if (target->GetPropertyAsBool("AUTOMOC")
  337. || target->GetPropertyAsBool("AUTOUIC"))
  338. {
  339. this->SetupSourceFiles(target);
  340. }
  341. makefile->AddDefinition("_cpp_files",
  342. cmLocalGenerator::EscapeForCMake(this->Sources.c_str()).c_str());
  343. if (target->GetPropertyAsBool("AUTOMOC"))
  344. {
  345. this->SetupAutoMocTarget(target, autogenTargetName,
  346. configIncludes, configDefines);
  347. }
  348. if (target->GetPropertyAsBool("AUTOUIC"))
  349. {
  350. this->SetupAutoUicTarget(target, configUicOptions);
  351. }
  352. if (target->GetPropertyAsBool("AUTORCC"))
  353. {
  354. this->SetupAutoRccTarget(target);
  355. }
  356. const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT");
  357. std::string inputFile = cmakeRoot;
  358. inputFile += "/Modules/AutogenInfo.cmake.in";
  359. std::string outputFile = targetDir;
  360. outputFile += "/AutogenInfo.cmake";
  361. makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(),
  362. false, true, false);
  363. if (!configDefines.empty()
  364. || !configIncludes.empty()
  365. || !configUicOptions.empty())
  366. {
  367. cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app);
  368. if ( !infoFile )
  369. {
  370. std::string error = "Internal CMake error when trying to open file: ";
  371. error += outputFile.c_str();
  372. error += " for writing.";
  373. cmSystemTools::Error(error.c_str());
  374. return;
  375. }
  376. if (!configDefines.empty())
  377. {
  378. for (std::map<std::string, std::string>::iterator
  379. it = configDefines.begin(), end = configDefines.end();
  380. it != end; ++it)
  381. {
  382. infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first <<
  383. " " << it->second << ")\n";
  384. }
  385. }
  386. if (!configIncludes.empty())
  387. {
  388. for (std::map<std::string, std::string>::iterator
  389. it = configIncludes.begin(), end = configIncludes.end();
  390. it != end; ++it)
  391. {
  392. infoFile << "set(AM_MOC_INCLUDES_" << it->first <<
  393. " " << it->second << ")\n";
  394. }
  395. }
  396. if (!configUicOptions.empty())
  397. {
  398. for (std::map<std::string, std::string>::iterator
  399. it = configUicOptions.begin(), end = configUicOptions.end();
  400. it != end; ++it)
  401. {
  402. infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first <<
  403. " " << it->second << ")\n";
  404. }
  405. }
  406. }
  407. }
  408. void cmQtAutoGenerators::SetupSourceFiles(cmTarget const* target)
  409. {
  410. cmMakefile* makefile = target->GetMakefile();
  411. const char* sepFiles = "";
  412. const char* sepHeaders = "";
  413. std::vector<cmSourceFile*> srcFiles;
  414. target->GetSourceFiles(srcFiles);
  415. const char *skipMocSep = "";
  416. const char *skipUicSep = "";
  417. std::vector<cmSourceFile*> newRccFiles;
  418. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  419. fileIt != srcFiles.end();
  420. ++fileIt)
  421. {
  422. cmSourceFile* sf = *fileIt;
  423. std::string absFile = cmsys::SystemTools::GetRealPath(
  424. sf->GetFullPath().c_str());
  425. bool skipMoc = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
  426. bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
  427. if(cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC")))
  428. {
  429. this->SkipUic += skipUicSep;
  430. this->SkipUic += absFile;
  431. skipUicSep = ";";
  432. }
  433. std::string ext = sf->GetExtension();
  434. if (target->GetPropertyAsBool("AUTORCC"))
  435. {
  436. if (ext == "qrc"
  437. && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")))
  438. {
  439. std::string basename = cmsys::SystemTools::
  440. GetFilenameWithoutLastExtension(absFile);
  441. std::string rcc_output_file = makefile->GetCurrentOutputDirectory();
  442. rcc_output_file += "/qrc_" + basename + ".cpp";
  443. makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
  444. rcc_output_file.c_str(), false);
  445. cmSourceFile* rccCppSource
  446. = makefile->GetOrCreateSource(rcc_output_file.c_str(), true);
  447. newRccFiles.push_back(rccCppSource);
  448. }
  449. }
  450. if (!generated)
  451. {
  452. if (skipMoc)
  453. {
  454. this->SkipMoc += skipMocSep;
  455. this->SkipMoc += absFile;
  456. skipMocSep = ";";
  457. }
  458. else
  459. {
  460. cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(
  461. ext.c_str());
  462. if (fileType == cmSystemTools::CXX_FILE_FORMAT)
  463. {
  464. this->Sources += sepFiles;
  465. this->Sources += absFile;
  466. sepFiles = ";";
  467. }
  468. else if (fileType == cmSystemTools::HEADER_FILE_FORMAT)
  469. {
  470. this->Headers += sepHeaders;
  471. this->Headers += absFile;
  472. sepHeaders = ";";
  473. }
  474. }
  475. }
  476. }
  477. for(std::vector<cmSourceFile*>::const_iterator fileIt = newRccFiles.begin();
  478. fileIt != newRccFiles.end();
  479. ++fileIt)
  480. {
  481. const_cast<cmTarget*>(target)->AddSourceFile(*fileIt);
  482. }
  483. }
  484. void cmQtAutoGenerators::SetupAutoMocTarget(cmTarget const* target,
  485. const std::string &autogenTargetName,
  486. std::map<std::string, std::string> &configIncludes,
  487. std::map<std::string, std::string> &configDefines)
  488. {
  489. cmMakefile* makefile = target->GetMakefile();
  490. const char* tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS");
  491. std::string _moc_options = (tmp!=0 ? tmp : "");
  492. makefile->AddDefinition("_moc_options",
  493. cmLocalGenerator::EscapeForCMake(_moc_options.c_str()).c_str());
  494. makefile->AddDefinition("_skip_moc",
  495. cmLocalGenerator::EscapeForCMake(this->SkipMoc.c_str()).c_str());
  496. makefile->AddDefinition("_moc_headers",
  497. cmLocalGenerator::EscapeForCMake(this->Headers.c_str()).c_str());
  498. bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE");
  499. makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE");
  500. std::string _moc_incs;
  501. std::string _moc_compile_defs;
  502. std::vector<std::string> configs;
  503. const char *config = makefile->GetConfigurations(configs);
  504. GetCompileDefinitionsAndDirectories(target, config,
  505. _moc_incs, _moc_compile_defs);
  506. makefile->AddDefinition("_moc_incs",
  507. cmLocalGenerator::EscapeForCMake(_moc_incs.c_str()).c_str());
  508. makefile->AddDefinition("_moc_compile_defs",
  509. cmLocalGenerator::EscapeForCMake(_moc_compile_defs.c_str()).c_str());
  510. for (std::vector<std::string>::const_iterator li = configs.begin();
  511. li != configs.end(); ++li)
  512. {
  513. std::string config_moc_incs;
  514. std::string config_moc_compile_defs;
  515. GetCompileDefinitionsAndDirectories(target, li->c_str(),
  516. config_moc_incs,
  517. config_moc_compile_defs);
  518. if (config_moc_incs != _moc_incs)
  519. {
  520. configIncludes[*li] =
  521. cmLocalGenerator::EscapeForCMake(config_moc_incs.c_str());
  522. if(_moc_incs.empty())
  523. {
  524. _moc_incs = config_moc_incs;
  525. }
  526. }
  527. if (config_moc_compile_defs != _moc_compile_defs)
  528. {
  529. configDefines[*li] =
  530. cmLocalGenerator::EscapeForCMake(config_moc_compile_defs.c_str());
  531. if(_moc_compile_defs.empty())
  532. {
  533. _moc_compile_defs = config_moc_compile_defs;
  534. }
  535. }
  536. }
  537. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  538. if (strcmp(qtVersion, "5") == 0)
  539. {
  540. cmTarget *qt5Moc = makefile->FindTargetToUse("Qt5::moc");
  541. if (!qt5Moc)
  542. {
  543. cmSystemTools::Error("Qt5::moc target not found ",
  544. autogenTargetName.c_str());
  545. return;
  546. }
  547. makefile->AddDefinition("_qt_moc_executable", qt5Moc->GetLocation(0));
  548. }
  549. else if (strcmp(qtVersion, "4") == 0)
  550. {
  551. cmTarget *qt4Moc = makefile->FindTargetToUse("Qt4::moc");
  552. if (!qt4Moc)
  553. {
  554. cmSystemTools::Error("Qt4::moc target not found ",
  555. autogenTargetName.c_str());
  556. return;
  557. }
  558. makefile->AddDefinition("_qt_moc_executable", qt4Moc->GetLocation(0));
  559. }
  560. else
  561. {
  562. cmSystemTools::Error("The CMAKE_AUTOMOC feature supports only Qt 4 and "
  563. "Qt 5 ", autogenTargetName.c_str());
  564. }
  565. }
  566. void cmQtAutoGenerators::MergeUicOptions(std::vector<std::string> &opts,
  567. const std::vector<std::string> &fileOpts,
  568. bool isQt5)
  569. {
  570. static const char* valueOptions[] = {
  571. "tr",
  572. "translate",
  573. "postfix",
  574. "generator",
  575. "include", // Since Qt 5.3
  576. "g"
  577. };
  578. std::vector<std::string> extraOpts;
  579. for(std::vector<std::string>::const_iterator it = fileOpts.begin();
  580. it != fileOpts.end(); ++it)
  581. {
  582. std::vector<std::string>::iterator existingIt
  583. = std::find(opts.begin(), opts.end(), *it);
  584. if (existingIt != opts.end())
  585. {
  586. const char *o = it->c_str();
  587. if (*o == '-')
  588. {
  589. ++o;
  590. }
  591. if (isQt5 && *o == '-')
  592. {
  593. ++o;
  594. }
  595. if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
  596. cmStrCmp(o)) != cmArrayEnd(valueOptions))
  597. {
  598. assert(existingIt + 1 != opts.end());
  599. *(existingIt + 1) = *(it + 1);
  600. ++it;
  601. }
  602. }
  603. else
  604. {
  605. extraOpts.push_back(*it);
  606. }
  607. }
  608. opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
  609. }
  610. static void GetUicOpts(cmTarget const* target, const char * config,
  611. std::string &optString)
  612. {
  613. std::vector<std::string> opts;
  614. target->GetAutoUicOptions(opts, config);
  615. const char* sep = "";
  616. for(std::vector<std::string>::const_iterator optIt = opts.begin();
  617. optIt != opts.end();
  618. ++optIt)
  619. {
  620. optString += sep;
  621. sep = ";";
  622. optString += *optIt;
  623. }
  624. }
  625. void cmQtAutoGenerators::SetupAutoUicTarget(cmTarget const* target,
  626. std::map<std::string, std::string> &configUicOptions)
  627. {
  628. cmMakefile *makefile = target->GetMakefile();
  629. std::set<cmStdString> skipped;
  630. std::vector<std::string> skipVec;
  631. cmSystemTools::ExpandListArgument(this->SkipUic.c_str(), skipVec);
  632. for (std::vector<std::string>::const_iterator li = skipVec.begin();
  633. li != skipVec.end(); ++li)
  634. {
  635. skipped.insert(*li);
  636. }
  637. makefile->AddDefinition("_skip_uic",
  638. cmLocalGenerator::EscapeForCMake(this->SkipUic.c_str()).c_str());
  639. std::vector<cmSourceFile*> uiFilesWithOptions
  640. = makefile->GetQtUiFilesWithOptions();
  641. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  642. std::string _uic_opts;
  643. std::vector<std::string> configs;
  644. const char *config = makefile->GetConfigurations(configs);
  645. GetUicOpts(target, config, _uic_opts);
  646. if (!_uic_opts.empty())
  647. {
  648. _uic_opts = cmLocalGenerator::EscapeForCMake(_uic_opts.c_str());
  649. makefile->AddDefinition("_uic_target_options", _uic_opts.c_str());
  650. }
  651. for (std::vector<std::string>::const_iterator li = configs.begin();
  652. li != configs.end(); ++li)
  653. {
  654. std::string config_uic_opts;
  655. GetUicOpts(target, li->c_str(), config_uic_opts);
  656. if (config_uic_opts != _uic_opts)
  657. {
  658. configUicOptions[*li] =
  659. cmLocalGenerator::EscapeForCMake(config_uic_opts.c_str());
  660. if(_uic_opts.empty())
  661. {
  662. _uic_opts = config_uic_opts;
  663. }
  664. }
  665. }
  666. std::string uiFileFiles;
  667. std::string uiFileOptions;
  668. const char* sep = "";
  669. for(std::vector<cmSourceFile*>::const_iterator fileIt =
  670. uiFilesWithOptions.begin();
  671. fileIt != uiFilesWithOptions.end();
  672. ++fileIt)
  673. {
  674. cmSourceFile* sf = *fileIt;
  675. std::string absFile = cmsys::SystemTools::GetRealPath(
  676. sf->GetFullPath().c_str());
  677. if (!skipped.insert(absFile).second)
  678. {
  679. continue;
  680. }
  681. uiFileFiles += sep;
  682. uiFileFiles += absFile;
  683. uiFileOptions += sep;
  684. std::string opts = sf->GetProperty("AUTOUIC_OPTIONS");
  685. cmSystemTools::ReplaceString(opts, ";", "@list_sep@");
  686. uiFileOptions += opts;
  687. sep = ";";
  688. }
  689. makefile->AddDefinition("_qt_uic_options_files",
  690. cmLocalGenerator::EscapeForCMake(uiFileFiles.c_str()).c_str());
  691. makefile->AddDefinition("_qt_uic_options_options",
  692. cmLocalGenerator::EscapeForCMake(uiFileOptions.c_str()).c_str());
  693. const char* targetName = target->GetName();
  694. if (strcmp(qtVersion, "5") == 0)
  695. {
  696. cmTarget *qt5Uic = makefile->FindTargetToUse("Qt5::uic");
  697. if (!qt5Uic)
  698. {
  699. // Project does not use Qt5Widgets, but has AUTOUIC ON anyway
  700. }
  701. else
  702. {
  703. makefile->AddDefinition("_qt_uic_executable", qt5Uic->GetLocation(0));
  704. }
  705. }
  706. else if (strcmp(qtVersion, "4") == 0)
  707. {
  708. cmTarget *qt4Uic = makefile->FindTargetToUse("Qt4::uic");
  709. if (!qt4Uic)
  710. {
  711. cmSystemTools::Error("Qt4::uic target not found ",
  712. targetName);
  713. return;
  714. }
  715. makefile->AddDefinition("_qt_uic_executable", qt4Uic->GetLocation(0));
  716. }
  717. else
  718. {
  719. cmSystemTools::Error("The CMAKE_AUTOUIC feature supports only Qt 4 and "
  720. "Qt 5 ", targetName);
  721. }
  722. }
  723. void cmQtAutoGenerators::MergeRccOptions(std::vector<std::string> &opts,
  724. const std::vector<std::string> &fileOpts,
  725. bool isQt5)
  726. {
  727. static const char* valueOptions[] = {
  728. "name",
  729. "root",
  730. "compress",
  731. "threshold"
  732. };
  733. std::vector<std::string> extraOpts;
  734. for(std::vector<std::string>::const_iterator it = fileOpts.begin();
  735. it != fileOpts.end(); ++it)
  736. {
  737. std::vector<std::string>::iterator existingIt
  738. = std::find(opts.begin(), opts.end(), *it);
  739. if (existingIt != opts.end())
  740. {
  741. const char *o = it->c_str();
  742. if (*o == '-')
  743. {
  744. ++o;
  745. }
  746. if (isQt5 && *o == '-')
  747. {
  748. ++o;
  749. }
  750. if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
  751. cmStrCmp(o)) != cmArrayEnd(valueOptions))
  752. {
  753. assert(existingIt + 1 != opts.end());
  754. *(existingIt + 1) = *(it + 1);
  755. ++it;
  756. }
  757. }
  758. else
  759. {
  760. extraOpts.push_back(*it);
  761. }
  762. }
  763. opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
  764. }
  765. void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target)
  766. {
  767. std::string _rcc_files;
  768. const char* sepRccFiles = "";
  769. cmMakefile *makefile = target->GetMakefile();
  770. std::vector<cmSourceFile*> srcFiles;
  771. target->GetSourceFiles(srcFiles);
  772. std::string rccFileFiles;
  773. std::string rccFileOptions;
  774. const char *sep = "";
  775. const char *qtVersion = makefile->GetDefinition("_target_qt_version");
  776. std::vector<std::string> rccOptions;
  777. if (const char* opts = target->GetProperty("AUTORCC_OPTIONS"))
  778. {
  779. cmSystemTools::ExpandListArgument(opts, rccOptions);
  780. }
  781. for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
  782. fileIt != srcFiles.end();
  783. ++fileIt)
  784. {
  785. cmSourceFile* sf = *fileIt;
  786. std::string ext = sf->GetExtension();
  787. if (ext == "qrc")
  788. {
  789. std::string absFile = cmsys::SystemTools::GetRealPath(
  790. sf->GetFullPath().c_str());
  791. bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"));
  792. if (!skip)
  793. {
  794. _rcc_files += sepRccFiles;
  795. _rcc_files += absFile;
  796. sepRccFiles = ";";
  797. if (const char *prop = sf->GetProperty("AUTORCC_OPTIONS"))
  798. {
  799. std::vector<std::string> optsVec;
  800. cmSystemTools::ExpandListArgument(prop, optsVec);
  801. this->MergeRccOptions(rccOptions, optsVec,
  802. strcmp(qtVersion, "5") == 0);
  803. }
  804. if (!rccOptions.empty())
  805. {
  806. rccFileFiles += sep;
  807. rccFileFiles += absFile;
  808. rccFileOptions += sep;
  809. }
  810. const char *listSep = "";
  811. for(std::vector<std::string>::const_iterator it = rccOptions.begin();
  812. it != rccOptions.end();
  813. ++it)
  814. {
  815. rccFileOptions += listSep;
  816. rccFileOptions += *it;
  817. listSep = "@list_sep@";
  818. }
  819. sep = ";";
  820. }
  821. }
  822. }
  823. makefile->AddDefinition("_rcc_files",
  824. cmLocalGenerator::EscapeForCMake(_rcc_files.c_str()).c_str());
  825. makefile->AddDefinition("_qt_rcc_options_files",
  826. cmLocalGenerator::EscapeForCMake(rccFileFiles.c_str()).c_str());
  827. makefile->AddDefinition("_qt_rcc_options_options",
  828. cmLocalGenerator::EscapeForCMake(rccFileOptions.c_str()).c_str());
  829. const char* targetName = target->GetName();
  830. if (strcmp(qtVersion, "5") == 0)
  831. {
  832. cmTarget *qt5Rcc = makefile->FindTargetToUse("Qt5::rcc");
  833. if (!qt5Rcc)
  834. {
  835. cmSystemTools::Error("Qt5::rcc target not found ",
  836. targetName);
  837. return;
  838. }
  839. makefile->AddDefinition("_qt_rcc_executable", qt5Rcc->GetLocation(0));
  840. }
  841. else if (strcmp(qtVersion, "4") == 0)
  842. {
  843. cmTarget *qt4Rcc = makefile->FindTargetToUse("Qt4::rcc");
  844. if (!qt4Rcc)
  845. {
  846. cmSystemTools::Error("Qt4::rcc target not found ",
  847. targetName);
  848. return;
  849. }
  850. makefile->AddDefinition("_qt_rcc_executable", qt4Rcc->GetLocation(0));
  851. }
  852. else
  853. {
  854. cmSystemTools::Error("The CMAKE_AUTORCC feature supports only Qt 4 and "
  855. "Qt 5 ", targetName);
  856. }
  857. }
  858. static cmGlobalGenerator* CreateGlobalGenerator(cmake* cm,
  859. const char* targetDirectory)
  860. {
  861. cmGlobalGenerator* gg = new cmGlobalGenerator();
  862. gg->SetCMakeInstance(cm);
  863. cmLocalGenerator* lg = gg->CreateLocalGenerator();
  864. lg->GetMakefile()->SetHomeOutputDirectory(targetDirectory);
  865. lg->GetMakefile()->SetStartOutputDirectory(targetDirectory);
  866. lg->GetMakefile()->SetHomeDirectory(targetDirectory);
  867. lg->GetMakefile()->SetStartDirectory(targetDirectory);
  868. gg->SetCurrentLocalGenerator(lg);
  869. return gg;
  870. }
  871. bool cmQtAutoGenerators::Run(const char* targetDirectory, const char *config)
  872. {
  873. bool success = true;
  874. cmake cm;
  875. cmGlobalGenerator* gg = CreateGlobalGenerator(&cm, targetDirectory);
  876. cmMakefile* makefile = gg->GetCurrentLocalGenerator()->GetMakefile();
  877. this->ReadAutogenInfoFile(makefile, targetDirectory, config);
  878. this->ReadOldMocDefinitionsFile(makefile, targetDirectory);
  879. this->Init();
  880. if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5")
  881. {
  882. success = this->RunAutogen(makefile);
  883. }
  884. this->WriteOldMocDefinitionsFile(targetDirectory);
  885. delete gg;
  886. gg = NULL;
  887. makefile = NULL;
  888. return success;
  889. }
  890. bool cmQtAutoGenerators::ReadAutogenInfoFile(cmMakefile* makefile,
  891. const char* targetDirectory,
  892. const char *config)
  893. {
  894. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  895. cmSystemTools::ConvertToUnixSlashes(filename);
  896. filename += "/AutogenInfo.cmake";
  897. if (!makefile->ReadListFile(0, filename.c_str()))
  898. {
  899. cmSystemTools::Error("Error processing file: ", filename.c_str());
  900. return false;
  901. }
  902. this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
  903. if (this->QtMajorVersion == "")
  904. {
  905. this->QtMajorVersion = makefile->GetSafeDefinition(
  906. "AM_Qt5Core_VERSION_MAJOR");
  907. }
  908. this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
  909. this->RccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
  910. this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
  911. this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
  912. this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
  913. this->IncludeProjectDirsBefore = makefile->IsOn(
  914. "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
  915. this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
  916. this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
  917. this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
  918. this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE");
  919. this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE");
  920. {
  921. std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS";
  922. std::string compileDefsProp = compileDefsPropOrig;
  923. if(config)
  924. {
  925. compileDefsProp += "_";
  926. compileDefsProp += config;
  927. }
  928. const char *compileDefs = makefile->GetDefinition(compileDefsProp.c_str());
  929. this->MocCompileDefinitionsStr = compileDefs ? compileDefs
  930. : makefile->GetSafeDefinition(compileDefsPropOrig.c_str());
  931. }
  932. {
  933. std::string includesPropOrig = "AM_MOC_INCLUDES";
  934. std::string includesProp = includesPropOrig;
  935. if(config)
  936. {
  937. includesProp += "_";
  938. includesProp += config;
  939. }
  940. const char *includes = makefile->GetDefinition(includesProp.c_str());
  941. this->MocIncludesStr = includes ? includes
  942. : makefile->GetSafeDefinition(includesPropOrig.c_str());
  943. }
  944. this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  945. this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
  946. this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
  947. this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
  948. {
  949. const char *uicOptionsFiles
  950. = makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES");
  951. std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS";
  952. std::string uicOptionsProp = uicOptionsPropOrig;
  953. if(config)
  954. {
  955. uicOptionsProp += "_";
  956. uicOptionsProp += config;
  957. }
  958. const char *uicTargetOptions
  959. = makefile->GetSafeDefinition(uicOptionsProp.c_str());
  960. cmSystemTools::ExpandListArgument(
  961. uicTargetOptions ? uicTargetOptions
  962. : makefile->GetSafeDefinition(uicOptionsPropOrig.c_str()),
  963. this->UicTargetOptions);
  964. const char *uicOptionsOptions
  965. = makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS");
  966. std::vector<std::string> uicFilesVec;
  967. cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec);
  968. std::vector<std::string> uicOptionsVec;
  969. cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec);
  970. if (uicFilesVec.size() != uicOptionsVec.size())
  971. {
  972. return false;
  973. }
  974. for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(),
  975. optionIt = uicOptionsVec.begin();
  976. fileIt != uicFilesVec.end();
  977. ++fileIt, ++optionIt)
  978. {
  979. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  980. this->UicOptions[*fileIt] = *optionIt;
  981. }
  982. }
  983. {
  984. const char *rccOptionsFiles
  985. = makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES");
  986. const char *rccOptionsOptions
  987. = makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS");
  988. std::vector<std::string> rccFilesVec;
  989. cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec);
  990. std::vector<std::string> rccOptionsVec;
  991. cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec);
  992. if (rccFilesVec.size() != rccOptionsVec.size())
  993. {
  994. return false;
  995. }
  996. for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(),
  997. optionIt = rccOptionsVec.begin();
  998. fileIt != rccFilesVec.end();
  999. ++fileIt, ++optionIt)
  1000. {
  1001. cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";");
  1002. this->RccOptions[*fileIt] = *optionIt;
  1003. }
  1004. }
  1005. this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
  1006. this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE");
  1007. return true;
  1008. }
  1009. std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile)
  1010. {
  1011. std::string s;
  1012. s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS");
  1013. s += " ~~~ ";
  1014. s += makefile->GetSafeDefinition("AM_MOC_INCLUDES");
  1015. s += " ~~~ ";
  1016. s += makefile->GetSafeDefinition("AM_MOC_OPTIONS");
  1017. s += " ~~~ ";
  1018. s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE"
  1019. : "FALSE";
  1020. s += " ~~~ ";
  1021. return s;
  1022. }
  1023. bool cmQtAutoGenerators::ReadOldMocDefinitionsFile(cmMakefile* makefile,
  1024. const char* targetDirectory)
  1025. {
  1026. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  1027. cmSystemTools::ConvertToUnixSlashes(filename);
  1028. filename += "/AutomocOldMocDefinitions.cmake";
  1029. if (makefile->ReadListFile(0, filename.c_str()))
  1030. {
  1031. this->OldCompileSettingsStr =
  1032. makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
  1033. }
  1034. return true;
  1035. }
  1036. void
  1037. cmQtAutoGenerators::WriteOldMocDefinitionsFile(const char* targetDirectory)
  1038. {
  1039. std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
  1040. cmSystemTools::ConvertToUnixSlashes(filename);
  1041. filename += "/AutomocOldMocDefinitions.cmake";
  1042. std::fstream outfile;
  1043. outfile.open(filename.c_str(),
  1044. std::ios::out | std::ios::trunc);
  1045. outfile << "set(AM_OLD_COMPILE_SETTINGS "
  1046. << cmLocalGenerator::EscapeForCMake(
  1047. this->CurrentCompileSettingsStr.c_str()) << ")\n";
  1048. outfile.close();
  1049. }
  1050. void cmQtAutoGenerators::Init()
  1051. {
  1052. this->OutMocCppFilename = this->Builddir;
  1053. this->OutMocCppFilename += this->TargetName;
  1054. this->OutMocCppFilename += ".cpp";
  1055. std::vector<std::string> cdefList;
  1056. cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
  1057. for(std::vector<std::string>::const_iterator it = cdefList.begin();
  1058. it != cdefList.end();
  1059. ++it)
  1060. {
  1061. this->MocDefinitions.push_back("-D" + (*it));
  1062. }
  1063. cmSystemTools::ExpandListArgument(this->MocOptionsStr, this->MocOptions);
  1064. std::vector<std::string> incPaths;
  1065. cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths);
  1066. std::set<std::string> frameworkPaths;
  1067. for(std::vector<std::string>::const_iterator it = incPaths.begin();
  1068. it != incPaths.end();
  1069. ++it)
  1070. {
  1071. const std::string &path = *it;
  1072. this->MocIncludes.push_back("-I" + path);
  1073. if (this->EndsWith(path, ".framework/Headers"))
  1074. {
  1075. // Go up twice to get to the framework root
  1076. std::vector<std::string> pathComponents;
  1077. cmsys::SystemTools::SplitPath(path.c_str(), pathComponents);
  1078. std::string frameworkPath =cmsys::SystemTools::JoinPath(
  1079. pathComponents.begin(), pathComponents.end() - 2);
  1080. frameworkPaths.insert(frameworkPath);
  1081. }
  1082. }
  1083. for (std::set<std::string>::const_iterator it = frameworkPaths.begin();
  1084. it != frameworkPaths.end(); ++it)
  1085. {
  1086. this->MocIncludes.push_back("-F");
  1087. this->MocIncludes.push_back(*it);
  1088. }
  1089. if (this->IncludeProjectDirsBefore)
  1090. {
  1091. const std::string &binDir = "-I" + this->ProjectBinaryDir;
  1092. const std::string srcDir = "-I" + this->ProjectSourceDir;
  1093. std::list<std::string> sortedMocIncludes;
  1094. std::list<std::string>::iterator it = this->MocIncludes.begin();
  1095. while (it != this->MocIncludes.end())
  1096. {
  1097. if (this->StartsWith(*it, binDir))
  1098. {
  1099. sortedMocIncludes.push_back(*it);
  1100. it = this->MocIncludes.erase(it);
  1101. }
  1102. else
  1103. {
  1104. ++it;
  1105. }
  1106. }
  1107. it = this->MocIncludes.begin();
  1108. while (it != this->MocIncludes.end())
  1109. {
  1110. if (this->StartsWith(*it, srcDir))
  1111. {
  1112. sortedMocIncludes.push_back(*it);
  1113. it = this->MocIncludes.erase(it);
  1114. }
  1115. else
  1116. {
  1117. ++it;
  1118. }
  1119. }
  1120. sortedMocIncludes.insert(sortedMocIncludes.end(),
  1121. this->MocIncludes.begin(), this->MocIncludes.end());
  1122. this->MocIncludes = sortedMocIncludes;
  1123. }
  1124. }
  1125. bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
  1126. {
  1127. if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str())
  1128. || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr))
  1129. {
  1130. this->GenerateAll = true;
  1131. }
  1132. // the program goes through all .cpp files to see which moc files are
  1133. // included. It is not really interesting how the moc file is named, but
  1134. // what file the moc is created from. Once a moc is included the same moc
  1135. // may not be included in the _automoc.cpp file anymore. OTOH if there's a
  1136. // header containing Q_OBJECT where no corresponding moc file is included
  1137. // anywhere a moc_<filename>.cpp file is created and included in
  1138. // the _automoc.cpp file.
  1139. // key = moc source filepath, value = moc output filepath
  1140. std::map<std::string, std::string> includedMocs;
  1141. // collect all headers which may need to be mocced
  1142. std::set<std::string> headerFiles;
  1143. std::vector<std::string> sourceFiles;
  1144. cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
  1145. const std::vector<std::string>& headerExtensions =
  1146. makefile->GetHeaderExtensions();
  1147. std::map<std::string, std::string> includedUis;
  1148. std::map<std::string, std::string> skippedUis;
  1149. std::vector<std::string> uicSkipped;
  1150. cmSystemTools::ExpandListArgument(this->SkipUic, uicSkipped);
  1151. for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
  1152. it != sourceFiles.end();
  1153. ++it)
  1154. {
  1155. const bool skipUic = std::find(uicSkipped.begin(), uicSkipped.end(), *it)
  1156. != uicSkipped.end();
  1157. std::map<std::string, std::string>& uiFiles
  1158. = skipUic ? skippedUis : includedUis;
  1159. const std::string &absFilename = *it;
  1160. if (this->Verbose)
  1161. {
  1162. std::cout << "AUTOGEN: Checking " << absFilename << std::endl;
  1163. }
  1164. if (this->RelaxedMode)
  1165. {
  1166. this->ParseCppFile(absFilename, headerExtensions, includedMocs,
  1167. uiFiles);
  1168. }
  1169. else
  1170. {
  1171. this->StrictParseCppFile(absFilename, headerExtensions, includedMocs,
  1172. uiFiles);
  1173. }
  1174. this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
  1175. }
  1176. {
  1177. std::vector<std::string> mocSkipped;
  1178. cmSystemTools::ExpandListArgument(this->SkipMoc, mocSkipped);
  1179. for (std::vector<std::string>::const_iterator it = mocSkipped.begin();
  1180. it != mocSkipped.end();
  1181. ++it)
  1182. {
  1183. if (std::find(uicSkipped.begin(), uicSkipped.end(), *it)
  1184. != uicSkipped.end())
  1185. {
  1186. const std::string &absFilename = *it;
  1187. if (this->Verbose)
  1188. {
  1189. std::cout << "AUTOGEN: Checking " << absFilename << std::endl;
  1190. }
  1191. this->ParseForUic(absFilename, includedUis);
  1192. }
  1193. }
  1194. }
  1195. std::vector<std::string> headerFilesVec;
  1196. cmSystemTools::ExpandListArgument(this->Headers, headerFilesVec);
  1197. for (std::vector<std::string>::const_iterator it = headerFilesVec.begin();
  1198. it != headerFilesVec.end();
  1199. ++it)
  1200. {
  1201. headerFiles.insert(*it);
  1202. }
  1203. // key = moc source filepath, value = moc output filename
  1204. std::map<std::string, std::string> notIncludedMocs;
  1205. this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
  1206. // run moc on all the moc's that are #included in source files
  1207. for(std::map<std::string, std::string>::const_iterator
  1208. it = includedMocs.begin();
  1209. it != includedMocs.end();
  1210. ++it)
  1211. {
  1212. this->GenerateMoc(it->first, it->second);
  1213. }
  1214. for(std::map<std::string, std::string>::const_iterator
  1215. it = includedUis.begin();
  1216. it != includedUis.end();
  1217. ++it)
  1218. {
  1219. this->GenerateUi(it->first, it->second);
  1220. }
  1221. if(!this->RccExecutable.empty())
  1222. {
  1223. this->GenerateQrc();
  1224. }
  1225. cmsys_ios::stringstream outStream;
  1226. outStream << "/* This file is autogenerated, do not edit*/\n";
  1227. bool automocCppChanged = false;
  1228. if (notIncludedMocs.empty())
  1229. {
  1230. outStream << "enum some_compilers { need_more_than_nothing };\n";
  1231. }
  1232. else
  1233. {
  1234. // run moc on the remaining headers and include them in
  1235. // the _automoc.cpp file
  1236. for(std::map<std::string, std::string>::const_iterator
  1237. it = notIncludedMocs.begin();
  1238. it != notIncludedMocs.end();
  1239. ++it)
  1240. {
  1241. bool mocSuccess = this->GenerateMoc(it->first, it->second);
  1242. if (mocSuccess)
  1243. {
  1244. automocCppChanged = true;
  1245. }
  1246. outStream << "#include \"" << it->second << "\"\n";
  1247. }
  1248. }
  1249. if (this->RunMocFailed)
  1250. {
  1251. std::cerr << "moc failed..." << std::endl;
  1252. return false;
  1253. }
  1254. if (this->RunUicFailed)
  1255. {
  1256. std::cerr << "uic failed..." << std::endl;
  1257. return false;
  1258. }
  1259. if (this->RunRccFailed)
  1260. {
  1261. std::cerr << "rcc failed..." << std::endl;
  1262. return false;
  1263. }
  1264. outStream.flush();
  1265. std::string automocSource = outStream.str();
  1266. if (!automocCppChanged)
  1267. {
  1268. // compare contents of the _automoc.cpp file
  1269. const std::string oldContents = ReadAll(this->OutMocCppFilename);
  1270. if (oldContents == automocSource)
  1271. {
  1272. // nothing changed: don't touch the _automoc.cpp file
  1273. return true;
  1274. }
  1275. }
  1276. // source file that includes all remaining moc files (_automoc.cpp file)
  1277. std::fstream outfile;
  1278. outfile.open(this->OutMocCppFilename.c_str(),
  1279. std::ios::out | std::ios::trunc);
  1280. outfile << automocSource;
  1281. outfile.close();
  1282. return true;
  1283. }
  1284. void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
  1285. const std::vector<std::string>& headerExtensions,
  1286. std::map<std::string, std::string>& includedMocs,
  1287. std::map<std::string, std::string> &includedUis)
  1288. {
  1289. cmsys::RegularExpression mocIncludeRegExp(
  1290. "[\n][ \t]*#[ \t]*include[ \t]+"
  1291. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  1292. const std::string contentsString = ReadAll(absFilename);
  1293. if (contentsString.empty())
  1294. {
  1295. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  1296. << std::endl;
  1297. return;
  1298. }
  1299. this->ParseForUic(absFilename, contentsString, includedUis);
  1300. if (this->MocExecutable.empty())
  1301. {
  1302. return;
  1303. }
  1304. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  1305. cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
  1306. const std::string scannedFileBasename = cmsys::SystemTools::
  1307. GetFilenameWithoutLastExtension(absFilename);
  1308. std::string macroName;
  1309. const bool requiresMoc = requiresMocing(contentsString, macroName);
  1310. bool dotMocIncluded = false;
  1311. bool mocUnderscoreIncluded = false;
  1312. std::string ownMocUnderscoreFile;
  1313. std::string ownDotMocFile;
  1314. std::string ownMocHeaderFile;
  1315. std::string::size_type matchOffset = 0;
  1316. // first a simple string check for "moc" is *much* faster than the regexp,
  1317. // and if the string search already fails, we don't have to try the
  1318. // expensive regexp
  1319. if ((strstr(contentsString.c_str(), "moc") != NULL)
  1320. && (mocIncludeRegExp.find(contentsString)))
  1321. {
  1322. // for every moc include in the file
  1323. do
  1324. {
  1325. const std::string currentMoc = mocIncludeRegExp.match(1);
  1326. //std::cout << "found moc include: " << currentMoc << std::endl;
  1327. std::string basename = cmsys::SystemTools::
  1328. GetFilenameWithoutLastExtension(currentMoc);
  1329. const bool moc_style = this->StartsWith(basename, "moc_");
  1330. // If the moc include is of the moc_foo.cpp style we expect
  1331. // the Q_OBJECT class declaration in a header file.
  1332. // If the moc include is of the foo.moc style we need to look for
  1333. // a Q_OBJECT macro in the current source file, if it contains the
  1334. // macro we generate the moc file from the source file.
  1335. // Q_OBJECT
  1336. if (moc_style)
  1337. {
  1338. // basename should be the part of the moc filename used for
  1339. // finding the correct header, so we need to remove the moc_ part
  1340. basename = basename.substr(4);
  1341. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  1342. std::string headerToMoc = findMatchingHeader(
  1343. absPath, mocSubDir, basename, headerExtensions);
  1344. if (!headerToMoc.empty())
  1345. {
  1346. includedMocs[headerToMoc] = currentMoc;
  1347. if (basename == scannedFileBasename)
  1348. {
  1349. mocUnderscoreIncluded = true;
  1350. ownMocUnderscoreFile = currentMoc;
  1351. ownMocHeaderFile = headerToMoc;
  1352. }
  1353. }
  1354. else
  1355. {
  1356. std::cerr << "AUTOGEN: error: " << absFilename << " The file "
  1357. << "includes the moc file \"" << currentMoc << "\", "
  1358. << "but could not find header \"" << basename
  1359. << '{' << this->Join(headerExtensions, ',') << "}\" ";
  1360. if (mocSubDir.empty())
  1361. {
  1362. std::cerr << "in " << absPath << "\n" << std::endl;
  1363. }
  1364. else
  1365. {
  1366. std::cerr << "neither in " << absPath
  1367. << " nor in " << mocSubDir << "\n" << std::endl;
  1368. }
  1369. ::exit(EXIT_FAILURE);
  1370. }
  1371. }
  1372. else
  1373. {
  1374. std::string fileToMoc = absFilename;
  1375. if ((basename != scannedFileBasename) || (requiresMoc==false))
  1376. {
  1377. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  1378. std::string headerToMoc = findMatchingHeader(
  1379. absPath, mocSubDir, basename, headerExtensions);
  1380. if (!headerToMoc.empty())
  1381. {
  1382. // this is for KDE4 compatibility:
  1383. fileToMoc = headerToMoc;
  1384. if ((requiresMoc==false) &&(basename==scannedFileBasename))
  1385. {
  1386. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  1387. "includes the moc file \"" << currentMoc <<
  1388. "\", but does not contain a " << macroName
  1389. << " macro. Running moc on "
  1390. << "\"" << headerToMoc << "\" ! Include \"moc_"
  1391. << basename << ".cpp\" for a compatiblity with "
  1392. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  1393. << std::endl;
  1394. }
  1395. else
  1396. {
  1397. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  1398. "includes the moc file \"" << currentMoc <<
  1399. "\" instead of \"moc_" << basename << ".cpp\". "
  1400. "Running moc on "
  1401. << "\"" << headerToMoc << "\" ! Include \"moc_"
  1402. << basename << ".cpp\" for compatiblity with "
  1403. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  1404. << std::endl;
  1405. }
  1406. }
  1407. else
  1408. {
  1409. std::cerr <<"AUTOGEN: error: " << absFilename << ": The file "
  1410. "includes the moc file \"" << currentMoc <<
  1411. "\", which seems to be the moc file from a different "
  1412. "source file. CMake also could not find a matching "
  1413. "header.\n" << std::endl;
  1414. ::exit(EXIT_FAILURE);
  1415. }
  1416. }
  1417. else
  1418. {
  1419. dotMocIncluded = true;
  1420. ownDotMocFile = currentMoc;
  1421. }
  1422. includedMocs[fileToMoc] = currentMoc;
  1423. }
  1424. matchOffset += mocIncludeRegExp.end();
  1425. } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  1426. }
  1427. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  1428. // If this is the case, the moc_foo.cpp should probably be generated from
  1429. // foo.cpp instead of foo.h, because otherwise it won't build.
  1430. // But warn, since this is not how it is supposed to be used.
  1431. if ((dotMocIncluded == false) && (requiresMoc == true))
  1432. {
  1433. if (mocUnderscoreIncluded == true)
  1434. {
  1435. // this is for KDE4 compatibility:
  1436. std::cerr << "AUTOGEN: warning: " << absFilename << ": The file "
  1437. << "contains a " << macroName << " macro, but does not "
  1438. "include "
  1439. << "\"" << scannedFileBasename << ".moc\", but instead "
  1440. "includes "
  1441. << "\"" << ownMocUnderscoreFile << "\". Running moc on "
  1442. << "\"" << absFilename << "\" ! Better include \""
  1443. << scannedFileBasename << ".moc\" for compatiblity with "
  1444. "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
  1445. << std::endl;
  1446. includedMocs[absFilename] = ownMocUnderscoreFile;
  1447. includedMocs.erase(ownMocHeaderFile);
  1448. }
  1449. else
  1450. {
  1451. // otherwise always error out since it will not compile:
  1452. std::cerr << "AUTOGEN: error: " << absFilename << ": The file "
  1453. << "contains a " << macroName << " macro, but does not "
  1454. "include "
  1455. << "\"" << scannedFileBasename << ".moc\" !\n"
  1456. << std::endl;
  1457. ::exit(EXIT_FAILURE);
  1458. }
  1459. }
  1460. }
  1461. void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
  1462. const std::vector<std::string>& headerExtensions,
  1463. std::map<std::string, std::string>& includedMocs,
  1464. std::map<std::string, std::string>& includedUis)
  1465. {
  1466. cmsys::RegularExpression mocIncludeRegExp(
  1467. "[\n][ \t]*#[ \t]*include[ \t]+"
  1468. "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
  1469. const std::string contentsString = ReadAll(absFilename);
  1470. if (contentsString.empty())
  1471. {
  1472. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  1473. << std::endl;
  1474. return;
  1475. }
  1476. this->ParseForUic(absFilename, contentsString, includedUis);
  1477. if (this->MocExecutable.empty())
  1478. {
  1479. return;
  1480. }
  1481. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  1482. cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
  1483. const std::string scannedFileBasename = cmsys::SystemTools::
  1484. GetFilenameWithoutLastExtension(absFilename);
  1485. bool dotMocIncluded = false;
  1486. std::string::size_type matchOffset = 0;
  1487. // first a simple string check for "moc" is *much* faster than the regexp,
  1488. // and if the string search already fails, we don't have to try the
  1489. // expensive regexp
  1490. if ((strstr(contentsString.c_str(), "moc") != NULL)
  1491. && (mocIncludeRegExp.find(contentsString)))
  1492. {
  1493. // for every moc include in the file
  1494. do
  1495. {
  1496. const std::string currentMoc = mocIncludeRegExp.match(1);
  1497. std::string basename = cmsys::SystemTools::
  1498. GetFilenameWithoutLastExtension(currentMoc);
  1499. const bool mocUnderscoreStyle = this->StartsWith(basename, "moc_");
  1500. // If the moc include is of the moc_foo.cpp style we expect
  1501. // the Q_OBJECT class declaration in a header file.
  1502. // If the moc include is of the foo.moc style we need to look for
  1503. // a Q_OBJECT macro in the current source file, if it contains the
  1504. // macro we generate the moc file from the source file.
  1505. if (mocUnderscoreStyle)
  1506. {
  1507. // basename should be the part of the moc filename used for
  1508. // finding the correct header, so we need to remove the moc_ part
  1509. basename = basename.substr(4);
  1510. std::string mocSubDir = extractSubDir(absPath, currentMoc);
  1511. std::string headerToMoc = findMatchingHeader(
  1512. absPath, mocSubDir, basename, headerExtensions);
  1513. if (!headerToMoc.empty())
  1514. {
  1515. includedMocs[headerToMoc] = currentMoc;
  1516. }
  1517. else
  1518. {
  1519. std::cerr << "AUTOGEN: error: " << absFilename << " The file "
  1520. << "includes the moc file \"" << currentMoc << "\", "
  1521. << "but could not find header \"" << basename
  1522. << '{' << this->Join(headerExtensions, ',') << "}\" ";
  1523. if (mocSubDir.empty())
  1524. {
  1525. std::cerr << "in " << absPath << "\n" << std::endl;
  1526. }
  1527. else
  1528. {
  1529. std::cerr << "neither in " << absPath
  1530. << " nor in " << mocSubDir << "\n" << std::endl;
  1531. }
  1532. ::exit(EXIT_FAILURE);
  1533. }
  1534. }
  1535. else
  1536. {
  1537. if (basename != scannedFileBasename)
  1538. {
  1539. std::cerr <<"AUTOGEN: error: " << absFilename << ": The file "
  1540. "includes the moc file \"" << currentMoc <<
  1541. "\", which seems to be the moc file from a different "
  1542. "source file. This is not supported. "
  1543. "Include \"" << scannedFileBasename << ".moc\" to run "
  1544. "moc on this source file.\n" << std::endl;
  1545. ::exit(EXIT_FAILURE);
  1546. }
  1547. dotMocIncluded = true;
  1548. includedMocs[absFilename] = currentMoc;
  1549. }
  1550. matchOffset += mocIncludeRegExp.end();
  1551. } while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
  1552. }
  1553. // In this case, check whether the scanned file itself contains a Q_OBJECT.
  1554. // If this is the case, the moc_foo.cpp should probably be generated from
  1555. // foo.cpp instead of foo.h, because otherwise it won't build.
  1556. // But warn, since this is not how it is supposed to be used.
  1557. std::string macroName;
  1558. if ((dotMocIncluded == false) && (requiresMocing(contentsString,
  1559. macroName)))
  1560. {
  1561. // otherwise always error out since it will not compile:
  1562. std::cerr << "AUTOGEN: error: " << absFilename << ": The file "
  1563. << "contains a " << macroName << " macro, but does not include "
  1564. << "\"" << scannedFileBasename << ".moc\" !\n"
  1565. << std::endl;
  1566. ::exit(EXIT_FAILURE);
  1567. }
  1568. }
  1569. void cmQtAutoGenerators::ParseForUic(const std::string& absFilename,
  1570. std::map<std::string, std::string>& includedUis)
  1571. {
  1572. if (this->UicExecutable.empty())
  1573. {
  1574. return;
  1575. }
  1576. const std::string contentsString = ReadAll(absFilename);
  1577. if (contentsString.empty())
  1578. {
  1579. std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
  1580. << std::endl;
  1581. return;
  1582. }
  1583. this->ParseForUic(absFilename, contentsString, includedUis);
  1584. }
  1585. void cmQtAutoGenerators::ParseForUic(const std::string& absFilename,
  1586. const std::string& contentsString,
  1587. std::map<std::string, std::string>& includedUis)
  1588. {
  1589. if (this->UicExecutable.empty())
  1590. {
  1591. return;
  1592. }
  1593. cmsys::RegularExpression uiIncludeRegExp(
  1594. "[\n][ \t]*#[ \t]*include[ \t]+"
  1595. "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
  1596. std::string::size_type matchOffset = 0;
  1597. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  1598. cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
  1599. matchOffset = 0;
  1600. if ((strstr(contentsString.c_str(), "ui_") != NULL)
  1601. && (uiIncludeRegExp.find(contentsString)))
  1602. {
  1603. do
  1604. {
  1605. const std::string currentUi = uiIncludeRegExp.match(1);
  1606. std::string basename = cmsys::SystemTools::
  1607. GetFilenameWithoutLastExtension(currentUi);
  1608. // basename should be the part of the ui filename used for
  1609. // finding the correct header, so we need to remove the ui_ part
  1610. basename = basename.substr(3);
  1611. includedUis[absPath] = basename;
  1612. matchOffset += uiIncludeRegExp.end();
  1613. } while(uiIncludeRegExp.find(contentsString.c_str() + matchOffset));
  1614. }
  1615. }
  1616. void
  1617. cmQtAutoGenerators::SearchHeadersForCppFile(const std::string& absFilename,
  1618. const std::vector<std::string>& headerExtensions,
  1619. std::set<std::string>& absHeaders)
  1620. {
  1621. // search for header files and private header files we may need to moc:
  1622. const std::string basename =
  1623. cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
  1624. const std::string absPath = cmsys::SystemTools::GetFilenamePath(
  1625. cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
  1626. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  1627. ext != headerExtensions.end();
  1628. ++ext)
  1629. {
  1630. const std::string headerName = absPath + basename + "." + (*ext);
  1631. if (cmsys::SystemTools::FileExists(headerName.c_str()))
  1632. {
  1633. absHeaders.insert(headerName);
  1634. break;
  1635. }
  1636. }
  1637. for(std::vector<std::string>::const_iterator ext = headerExtensions.begin();
  1638. ext != headerExtensions.end();
  1639. ++ext)
  1640. {
  1641. const std::string privateHeaderName = absPath+basename+"_p."+(*ext);
  1642. if (cmsys::SystemTools::FileExists(privateHeaderName.c_str()))
  1643. {
  1644. absHeaders.insert(privateHeaderName);
  1645. break;
  1646. }
  1647. }
  1648. }
  1649. void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
  1650. const std::map<std::string, std::string>& includedMocs,
  1651. std::map<std::string, std::string>& notIncludedMocs,
  1652. std::map<std::string, std::string>& includedUis)
  1653. {
  1654. for(std::set<std::string>::const_iterator hIt=absHeaders.begin();
  1655. hIt!=absHeaders.end();
  1656. ++hIt)
  1657. {
  1658. const std::string& headerName = *hIt;
  1659. const std::string contents = ReadAll(headerName);
  1660. if (!this->MocExecutable.empty()
  1661. && includedMocs.find(headerName) == includedMocs.end())
  1662. {
  1663. if (this->Verbose)
  1664. {
  1665. std::cout << "AUTOGEN: Checking " << headerName << std::endl;
  1666. }
  1667. const std::string basename = cmsys::SystemTools::
  1668. GetFilenameWithoutLastExtension(headerName);
  1669. const std::string currentMoc = "moc_" + basename + ".cpp";
  1670. std::string macroName;
  1671. if (requiresMocing(contents, macroName))
  1672. {
  1673. //std::cout << "header contains Q_OBJECT macro";
  1674. notIncludedMocs[headerName] = currentMoc;
  1675. }
  1676. }
  1677. this->ParseForUic(headerName, contents, includedUis);
  1678. }
  1679. }
  1680. bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
  1681. const std::string& mocFileName)
  1682. {
  1683. const std::string mocFilePath = this->Builddir + mocFileName;
  1684. int sourceNewerThanMoc = 0;
  1685. bool success = cmsys::SystemTools::FileTimeCompare(sourceFile.c_str(),
  1686. mocFilePath.c_str(),
  1687. &sourceNewerThanMoc);
  1688. if (this->GenerateAll || !success || sourceNewerThanMoc >= 0)
  1689. {
  1690. // make sure the directory for the resulting moc file exists
  1691. std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/'));
  1692. if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false))
  1693. {
  1694. cmsys::SystemTools::MakeDirectory(mocDir.c_str());
  1695. }
  1696. std::string msg = "Generating ";
  1697. msg += mocFileName;
  1698. cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
  1699. |cmsysTerminal_Color_ForegroundBold,
  1700. msg.c_str(), true, this->ColorOutput);
  1701. std::vector<cmStdString> command;
  1702. command.push_back(this->MocExecutable);
  1703. for (std::list<std::string>::const_iterator it = this->MocIncludes.begin();
  1704. it != this->MocIncludes.end();
  1705. ++it)
  1706. {
  1707. command.push_back(*it);
  1708. }
  1709. for(std::list<std::string>::const_iterator it=this->MocDefinitions.begin();
  1710. it != this->MocDefinitions.end();
  1711. ++it)
  1712. {
  1713. command.push_back(*it);
  1714. }
  1715. for(std::vector<std::string>::const_iterator it=this->MocOptions.begin();
  1716. it != this->MocOptions.end();
  1717. ++it)
  1718. {
  1719. command.push_back(*it);
  1720. }
  1721. #ifdef _WIN32
  1722. command.push_back("-DWIN32");
  1723. #endif
  1724. command.push_back("-o");
  1725. command.push_back(mocFilePath);
  1726. command.push_back(sourceFile);
  1727. if (this->Verbose)
  1728. {
  1729. for(std::vector<cmStdString>::const_iterator cmdIt = command.begin();
  1730. cmdIt != command.end();
  1731. ++cmdIt)
  1732. {
  1733. std::cout << *cmdIt << " ";
  1734. }
  1735. std::cout << std::endl;
  1736. }
  1737. std::string output;
  1738. int retVal = 0;
  1739. bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
  1740. if (!result || retVal)
  1741. {
  1742. std::cerr << "AUTOGEN: error: process for " << mocFilePath <<" failed:\n"
  1743. << output << std::endl;
  1744. this->RunMocFailed = true;
  1745. cmSystemTools::RemoveFile(mocFilePath.c_str());
  1746. }
  1747. return true;
  1748. }
  1749. return false;
  1750. }
  1751. bool cmQtAutoGenerators::GenerateUi(const std::string& path,
  1752. const std::string& uiFileName)
  1753. {
  1754. if (!cmsys::SystemTools::FileExists(this->Builddir.c_str(), false))
  1755. {
  1756. cmsys::SystemTools::MakeDirectory(this->Builddir.c_str());
  1757. }
  1758. std::string ui_output_file = "ui_" + uiFileName + ".h";
  1759. std::string ui_input_file = path + uiFileName + ".ui";
  1760. int sourceNewerThanUi = 0;
  1761. bool success = cmsys::SystemTools::FileTimeCompare(ui_input_file.c_str(),
  1762. (this->Builddir + ui_output_file).c_str(),
  1763. &sourceNewerThanUi);
  1764. if (this->GenerateAll || !success || sourceNewerThanUi >= 0)
  1765. {
  1766. std::string msg = "Generating ";
  1767. msg += ui_output_file;
  1768. cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
  1769. |cmsysTerminal_Color_ForegroundBold,
  1770. msg.c_str(), true, this->ColorOutput);
  1771. std::vector<cmStdString> command;
  1772. command.push_back(this->UicExecutable);
  1773. std::vector<std::string> opts = this->UicTargetOptions;
  1774. std::map<std::string, std::string>::const_iterator optionIt
  1775. = this->UicOptions.find(ui_input_file);
  1776. if (optionIt != this->UicOptions.end())
  1777. {
  1778. std::vector<std::string> fileOpts;
  1779. cmSystemTools::ExpandListArgument(optionIt->second, fileOpts);
  1780. this->MergeUicOptions(opts, fileOpts, this->QtMajorVersion == "5");
  1781. }
  1782. for(std::vector<std::string>::const_iterator optIt = opts.begin();
  1783. optIt != opts.end();
  1784. ++optIt)
  1785. {
  1786. command.push_back(*optIt);
  1787. }
  1788. command.push_back("-o");
  1789. command.push_back(this->Builddir + ui_output_file);
  1790. command.push_back(ui_input_file);
  1791. if (this->Verbose)
  1792. {
  1793. for(std::vector<cmStdString>::const_iterator cmdIt = command.begin();
  1794. cmdIt != command.end();
  1795. ++cmdIt)
  1796. {
  1797. std::cout << *cmdIt << " ";
  1798. }
  1799. std::cout << std::endl;
  1800. }
  1801. std::string output;
  1802. int retVal = 0;
  1803. bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
  1804. if (!result || retVal)
  1805. {
  1806. std::cerr << "AUTOUIC: error: process for " << ui_output_file <<
  1807. " failed:\n" << output << std::endl;
  1808. this->RunUicFailed = true;
  1809. cmSystemTools::RemoveFile(ui_output_file.c_str());
  1810. return false;
  1811. }
  1812. return true;
  1813. }
  1814. return false;
  1815. }
  1816. bool cmQtAutoGenerators::GenerateQrc()
  1817. {
  1818. std::vector<std::string> sourceFiles;
  1819. cmSystemTools::ExpandListArgument(this->RccSources, sourceFiles);
  1820. for(std::vector<std::string>::const_iterator si = sourceFiles.begin();
  1821. si != sourceFiles.end(); ++si)
  1822. {
  1823. std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
  1824. if (ext != ".qrc")
  1825. {
  1826. continue;
  1827. }
  1828. std::vector<cmStdString> command;
  1829. command.push_back(this->RccExecutable);
  1830. std::string basename = cmsys::SystemTools::
  1831. GetFilenameWithoutLastExtension(*si);
  1832. std::string rcc_output_file = this->Builddir + "qrc_" + basename + ".cpp";
  1833. int sourceNewerThanQrc = 0;
  1834. bool success = cmsys::SystemTools::FileTimeCompare(si->c_str(),
  1835. rcc_output_file.c_str(),
  1836. &sourceNewerThanQrc);
  1837. if (this->GenerateAll || !success || sourceNewerThanQrc >= 0)
  1838. {
  1839. std::map<std::string, std::string>::const_iterator optionIt
  1840. = this->RccOptions.find(*si);
  1841. if (optionIt != this->RccOptions.end())
  1842. {
  1843. std::vector<std::string> opts;
  1844. cmSystemTools::ExpandListArgument(optionIt->second, opts);
  1845. for(std::vector<std::string>::const_iterator optIt = opts.begin();
  1846. optIt != opts.end();
  1847. ++optIt)
  1848. {
  1849. command.push_back(*optIt);
  1850. }
  1851. }
  1852. command.push_back("-o");
  1853. command.push_back(rcc_output_file);
  1854. command.push_back(*si);
  1855. if (this->Verbose)
  1856. {
  1857. for(std::vector<cmStdString>::const_iterator cmdIt = command.begin();
  1858. cmdIt != command.end();
  1859. ++cmdIt)
  1860. {
  1861. std::cout << *cmdIt << " ";
  1862. }
  1863. std::cout << std::endl;
  1864. }
  1865. std::string output;
  1866. int retVal = 0;
  1867. bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
  1868. if (!result || retVal)
  1869. {
  1870. std::cerr << "AUTORCC: error: process for " << rcc_output_file <<
  1871. " failed:\n" << output << std::endl;
  1872. this->RunRccFailed = true;
  1873. cmSystemTools::RemoveFile(rcc_output_file.c_str());
  1874. return false;
  1875. }
  1876. }
  1877. }
  1878. return true;
  1879. }
  1880. std::string cmQtAutoGenerators::Join(const std::vector<std::string>& lst,
  1881. char separator)
  1882. {
  1883. if (lst.empty())
  1884. {
  1885. return "";
  1886. }
  1887. std::string result;
  1888. for (std::vector<std::string>::const_iterator it = lst.begin();
  1889. it != lst.end();
  1890. ++it)
  1891. {
  1892. result += "." + (*it) + separator;
  1893. }
  1894. result.erase(result.end() - 1);
  1895. return result;
  1896. }
  1897. bool cmQtAutoGenerators::StartsWith(const std::string& str,
  1898. const std::string& with)
  1899. {
  1900. return (str.substr(0, with.length()) == with);
  1901. }
  1902. bool cmQtAutoGenerators::EndsWith(const std::string& str,
  1903. const std::string& with)
  1904. {
  1905. if (with.length() > (str.length()))
  1906. {
  1907. return false;
  1908. }
  1909. return (str.substr(str.length() - with.length(), with.length()) == with);
  1910. }