| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmQtAutoGeneratorMocUic.h"
- #include <algorithm>
- #include <array>
- #include <cstddef>
- #include <list>
- #include <memory>
- #include <set>
- #include <sstream>
- #include <utility>
- #include "cmAlgorithms.h"
- #include "cmCryptoHash.h"
- #include "cmMakefile.h"
- #include "cmQtAutoGen.h"
- #include "cmSystemTools.h"
- #include "cmake.h"
- #if defined(__APPLE__)
- # include <unistd.h>
- #endif
- // -- Class methods
- std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
- std::string const& relativePath) const
- {
- return FileSys->CollapseFullPath(relativePath, AutogenBuildDir);
- }
- /**
- * @brief Tries to find the header file to the given file base path by
- * appending different header extensions
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader(
- std::string& header, std::string const& testBasePath) const
- {
- for (std::string const& ext : HeaderExtensions) {
- std::string testFilePath(testBasePath);
- testFilePath.push_back('.');
- testFilePath += ext;
- if (FileSys->FileExists(testFilePath)) {
- header = testFilePath;
- return true;
- }
- }
- return false;
- }
- bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped(
- std::string const& fileName) const
- {
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
- }
- /**
- * @brief Returns the first relevant Qt macro name found in the given C++ code
- * @return The name of the Qt macro or an empty string
- */
- std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindMacro(
- std::string const& content) const
- {
- for (KeyExpT const& filter : MacroFilters) {
- // Run a simple find string operation before the expensive
- // regular expression check
- if (content.find(filter.Key) != std::string::npos) {
- cmsys::RegularExpressionMatch match;
- if (filter.Exp.find(content.c_str(), match)) {
- // Return macro name on demand
- return filter.Key;
- }
- }
- }
- return std::string();
- }
- std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const
- {
- std::string res;
- const auto itB = MacroFilters.cbegin();
- const auto itE = MacroFilters.cend();
- const auto itL = itE - 1;
- auto itC = itB;
- for (; itC != itE; ++itC) {
- // Separator
- if (itC != itB) {
- if (itC != itL) {
- res += ", ";
- } else {
- res += " or ";
- }
- }
- // Key
- res += itC->Key;
- }
- return res;
- }
- std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile(
- std::string const& sourcePath, std::string const& includeString) const
- {
- // Search in vicinity of the source
- {
- std::string testPath = sourcePath;
- testPath += includeString;
- if (FileSys->FileExists(testPath)) {
- return FileSys->GetRealPath(testPath);
- }
- }
- // Search in include directories
- for (std::string const& path : IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeString;
- if (FileSys->FileExists(fullPath)) {
- return FileSys->GetRealPath(fullPath);
- }
- }
- // Return empty string
- return std::string();
- }
- void cmQtAutoGeneratorMocUic::MocSettingsT::FindDependencies(
- std::string const& content, std::set<std::string>& depends) const
- {
- if (!DependFilters.empty() && !content.empty()) {
- for (KeyExpT const& filter : DependFilters) {
- // Run a simple find string check
- if (content.find(filter.Key) != std::string::npos) {
- // Run the expensive regular expression check loop
- const char* contentChars = content.c_str();
- cmsys::RegularExpressionMatch match;
- while (filter.Exp.find(contentChars, match)) {
- {
- std::string dep = match.match(1);
- if (!dep.empty()) {
- depends.emplace(std::move(dep));
- }
- }
- contentChars += match.end();
- }
- }
- }
- }
- }
- bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped(
- std::string const& fileName) const
- {
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
- }
- void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk)
- {
- if (AutoMoc && Header) {
- // Don't parse header for moc if the file is included by a source already
- if (wrk.Gen().ParallelMocIncluded(FileName)) {
- AutoMoc = false;
- }
- }
- if (AutoMoc || AutoUic) {
- std::string error;
- MetaT meta;
- if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) {
- if (!meta.Content.empty()) {
- meta.FileDir = wrk.FileSys().SubDirPrefix(FileName);
- meta.FileBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(FileName);
- bool success = true;
- if (AutoMoc) {
- if (Header) {
- success = ParseMocHeader(wrk, meta);
- } else {
- success = ParseMocSource(wrk, meta);
- }
- }
- if (AutoUic && success) {
- ParseUic(wrk, meta);
- }
- } else {
- wrk.LogFileWarning(GenT::GEN, FileName, "The source file is empty");
- }
- } else {
- wrk.LogFileError(GenT::GEN, FileName,
- "Could not read the file: " + error);
- }
- }
- }
- bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk,
- MetaT const& meta)
- {
- struct JobPre
- {
- bool self; // source file is self
- bool underscore; // "moc_" style include
- std::string SourceFile;
- std::string IncludeString;
- };
- struct MocInclude
- {
- std::string Inc; // full include string
- std::string Dir; // include string directory
- std::string Base; // include string file base
- };
- // Check if this source file contains a relevant macro
- std::string const ownMacro = wrk.Moc().FindMacro(meta.Content);
- // Extract moc includes from file
- std::deque<MocInclude> mocIncsUsc;
- std::deque<MocInclude> mocIncsDot;
- {
- if (meta.Content.find("moc") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Moc().RegExpInclude.find(contentChars, match)) {
- std::string incString = match.match(2);
- std::string incDir(wrk.FileSys().SubDirPrefix(incString));
- std::string incBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(incString);
- if (cmHasLiteralPrefix(incBase, "moc_")) {
- // moc_<BASE>.cxx
- // Remove the moc_ part from the base name
- mocIncsUsc.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), incBase.substr(4) });
- } else {
- // <BASE>.moc
- mocIncsDot.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), std::move(incBase) });
- }
- // Forward content pointer
- contentChars += match.end();
- }
- }
- }
- // Check if there is anything to do
- if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
- return true;
- }
- bool ownDotMocIncluded = false;
- bool ownMocUscIncluded = false;
- std::deque<JobPre> jobs;
- // Process moc_<BASE>.cxx includes
- for (const MocInclude& mocInc : mocIncsUsc) {
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc });
- // Store meta information for relaxed mode
- if (ownMoc) {
- ownMocUscIncluded = true;
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but the header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GenT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- // Process <BASE>.moc includes
- for (const MocInclude& mocInc : mocIncsDot) {
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- if (wrk.Moc().RelaxedMode) {
- // Relaxed mode
- if (!ownMacro.empty() && ownMoc) {
- // Add self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- } else {
- // In relaxed mode try to find a header instead but issue a warning.
- // This is for KDE4 compatibility
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc });
- if (ownMacro.empty()) {
- if (ownMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for a compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GenT::MOC, FileName, emsg);
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += " instead of ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GenT::MOC, FileName, emsg);
- }
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a "
- "matching header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GenT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- } else {
- // Strict mode
- if (ownMoc) {
- // Include self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- // Accept but issue a warning if moc isn't required
- if (ownMacro.empty()) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.";
- wrk.LogFileWarning(GenT::MOC, FileName, emsg);
- }
- } else {
- // Don't allow <BASE>.moc include other than self in strict mode
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nThis is not supported. Include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " to run moc on this source file.";
- wrk.LogFileError(GenT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- }
- if (!ownMacro.empty() && !ownDotMocIncluded) {
- // In this case, check whether the scanned file itself contains a
- // Q_OBJECT.
- // If this is the case, the moc_foo.cpp should probably be generated from
- // foo.cpp instead of foo.h, because otherwise it won't build.
- // But warn, since this is not how it is supposed to be used.
- // This is for KDE4 compatibility.
- if (wrk.Moc().RelaxedMode && ownMocUscIncluded) {
- JobPre uscJobPre;
- // Remove underscore job request
- {
- auto itC = jobs.begin();
- auto itE = jobs.end();
- for (; itC != itE; ++itC) {
- JobPre& job(*itC);
- if (job.self && job.underscore) {
- uscJobPre = std::move(job);
- jobs.erase(itC);
- break;
- }
- }
- }
- // Issue a warning
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += ". Instead it includes ";
- emsg += Quoted(uscJobPre.IncludeString);
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(FileName);
- emsg += "!\nBetter include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
- wrk.LogFileWarning(GenT::MOC, FileName, emsg);
- }
- // Add own source job
- jobs.emplace_back(
- JobPre{ true, false, FileName, uscJobPre.IncludeString });
- } else {
- // Otherwise always error out since it will not compile.
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += "!\nConsider to\n - add #include \"";
- emsg += meta.FileBase;
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
- wrk.LogFileError(GenT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- // Convert pre jobs to actual jobs
- for (JobPre& jobPre : jobs) {
- JobHandleT jobHandle = cm::make_unique<JobMocT>(
- std::move(jobPre.SourceFile), FileName, std::move(jobPre.IncludeString));
- if (jobPre.self) {
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- }
- if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) {
- return false;
- }
- }
- return true;
- }
- bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk,
- MetaT const& meta)
- {
- bool success = true;
- std::string const macroName = wrk.Moc().FindMacro(meta.Content);
- if (!macroName.empty()) {
- JobHandleT jobHandle = cm::make_unique<JobMocT>(
- std::string(FileName), std::string(), std::string());
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- success = wrk.Gen().ParallelJobPushMoc(jobHandle);
- }
- return success;
- }
- std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders(
- WorkerT& wrk, std::string const& fileBase) const
- {
- std::string res = fileBase;
- res += ".{";
- res += cmJoin(wrk.Base().HeaderExtensions, ",");
- res += "}";
- return res;
- }
- std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader(
- WorkerT& wrk, std::string const& includerDir, std::string const& includeBase)
- {
- std::string header;
- // Search in vicinity of the source
- if (!wrk.Base().FindHeader(header, includerDir + includeBase)) {
- // Search in include directories
- for (std::string const& path : wrk.Moc().IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeBase;
- if (wrk.Base().FindHeader(header, fullPath)) {
- break;
- }
- }
- }
- // Sanitize
- if (!header.empty()) {
- header = wrk.FileSys().GetRealPath(header);
- }
- return header;
- }
- bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk,
- MetaT const& meta)
- {
- bool success = true;
- if (meta.Content.find("ui_") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Uic().RegExpInclude.find(contentChars, match)) {
- if (!ParseUicInclude(wrk, meta, match.match(2))) {
- success = false;
- break;
- }
- contentChars += match.end();
- }
- }
- return success;
- }
- bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude(
- WorkerT& wrk, MetaT const& meta, std::string&& includeString)
- {
- bool success = false;
- std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
- if (!uiInputFile.empty()) {
- if (!wrk.Uic().skipped(uiInputFile)) {
- JobHandleT jobHandle = cm::make_unique<JobUicT>(
- std::move(uiInputFile), FileName, std::move(includeString));
- success = wrk.Gen().ParallelJobPushUic(jobHandle);
- } else {
- // A skipped file is successful
- success = true;
- }
- }
- return success;
- }
- std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile(
- WorkerT& wrk, MetaT const& meta, std::string const& includeString)
- {
- std::string res;
- std::string searchFile =
- wrk.FileSys().GetFilenameWithoutLastExtension(includeString).substr(3);
- searchFile += ".ui";
- // Collect search paths list
- std::deque<std::string> testFiles;
- {
- std::string const searchPath = wrk.FileSys().SubDirPrefix(includeString);
- std::string searchFileFull;
- if (!searchPath.empty()) {
- searchFileFull = searchPath;
- searchFileFull += searchFile;
- }
- // Vicinity of the source
- {
- std::string const sourcePath = meta.FileDir;
- testFiles.push_back(sourcePath + searchFile);
- if (!searchPath.empty()) {
- testFiles.push_back(sourcePath + searchFileFull);
- }
- }
- // AUTOUIC search paths
- if (!wrk.Uic().SearchPaths.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFile));
- }
- if (!searchPath.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFileFull));
- }
- }
- }
- }
- // Search for the .ui file!
- for (std::string const& testFile : testFiles) {
- if (wrk.FileSys().FileExists(testFile)) {
- res = wrk.FileSys().GetRealPath(testFile);
- break;
- }
- }
- // Log error
- if (res.empty()) {
- std::string emsg = "Could not find ";
- emsg += Quoted(searchFile);
- emsg += " in\n";
- for (std::string const& testFile : testFiles) {
- emsg += " ";
- emsg += Quoted(testFile);
- emsg += "\n";
- }
- wrk.LogFileError(GenT::UIC, FileName, emsg);
- }
- return res;
- }
- void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk)
- {
- // (Re)generate moc_predefs.h on demand
- bool generate(false);
- bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs));
- if (!fileExists) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because it doesn't exist";
- wrk.LogInfo(GenT::MOC, reason);
- }
- generate = true;
- } else if (wrk.Moc().SettingsChanged) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because the settings changed.";
- wrk.LogInfo(GenT::MOC, reason);
- }
- generate = true;
- }
- if (generate) {
- ProcessResultT result;
- {
- // Compose command
- std::vector<std::string> cmd = wrk.Moc().PredefsCmd;
- // Add includes
- cmd.insert(cmd.end(), wrk.Moc().Includes.begin(),
- wrk.Moc().Includes.end());
- // Add definitions
- for (std::string const& def : wrk.Moc().Definitions) {
- cmd.push_back("-D" + def);
- }
- // Execute command
- if (!wrk.RunProcess(GenT::MOC, result, cmd)) {
- std::string emsg = "The content generation command for ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
- }
- }
- // (Re)write predefs file only on demand
- if (!result.error()) {
- if (!fileExists ||
- wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
- if (wrk.FileSys().FileWrite(GenT::MOC, wrk.Moc().PredefsFileAbs,
- result.StdOut)) {
- // Success
- } else {
- std::string emsg = "Writing ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.";
- wrk.LogFileError(GenT::MOC, wrk.Moc().PredefsFileAbs, emsg);
- }
- } else {
- // Touch to update the time stamp
- if (wrk.Log().Verbose()) {
- std::string msg = "Touching ";
- msg += Quoted(wrk.Moc().PredefsFileRel);
- msg += ".";
- wrk.LogInfo(GenT::MOC, msg);
- }
- wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
- }
- }
- }
- }
- void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies(
- WorkerT& wrk, std::string const& content)
- {
- wrk.Moc().FindDependencies(content, Depends);
- DependsValid = true;
- }
- void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk)
- {
- // Compute build file name
- if (!IncludeString.empty()) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
- } else {
- // Relative build path
- std::string relPath = wrk.FileSys().GetFilePathChecksum(SourceFile);
- relPath += "/moc_";
- relPath += wrk.FileSys().GetFilenameWithoutLastExtension(SourceFile);
- // Register relative file path with duplication check
- relPath = wrk.Gen().ParallelMocAutoRegister(relPath);
- // Absolute build path
- if (wrk.Base().MultiConfig) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += relPath;
- } else {
- BuildFile = wrk.Base().AbsoluteBuildPath(relPath);
- }
- }
- if (UpdateRequired(wrk)) {
- GenerateMoc(wrk);
- }
- }
- bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk)
- {
- bool const verbose = wrk.Gen().Log().Verbose();
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GenT::MOC, reason);
- }
- return true;
- }
- // Test if any setting changed
- if (wrk.Moc().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the MOC settings changed";
- wrk.LogInfo(GenT::MOC, reason);
- }
- return true;
- }
- // Test if the moc_predefs file is newer
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(
- BuildFile, wrk.Moc().PredefsFileAbs, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GenT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than: ";
- reason += Quoted(wrk.Moc().PredefsFileAbs);
- wrk.LogInfo(GenT::MOC, reason);
- }
- return true;
- }
- }
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GenT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GenT::MOC, reason);
- }
- return true;
- }
- }
- // Test if a dependency file is newer
- {
- // Read dependencies on demand
- if (!DependsValid) {
- std::string content;
- {
- std::string error;
- if (!wrk.FileSys().FileRead(content, SourceFile, &error)) {
- std::string emsg = "Could not read file\n ";
- emsg += Quoted(SourceFile);
- emsg += "\nrequired by moc include ";
- emsg += Quoted(IncludeString);
- emsg += " in\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += error;
- wrk.LogError(GenT::MOC, emsg);
- return false;
- }
- }
- FindDependencies(wrk, content);
- }
- // Check dependency timestamps
- std::string error;
- std::string sourceDir = wrk.FileSys().SubDirPrefix(SourceFile);
- for (std::string const& depFileRel : Depends) {
- std::string depFileAbs =
- wrk.Moc().FindIncludedFile(sourceDir, depFileRel);
- if (!depFileAbs.empty()) {
- if (wrk.FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because it is older than it's dependency file ";
- reason += Quoted(depFileAbs);
- wrk.LogInfo(GenT::MOC, reason);
- }
- return true;
- }
- if (!error.empty()) {
- wrk.LogError(GenT::MOC, error);
- return false;
- }
- } else {
- std::string message = "Could not find dependency file ";
- message += Quoted(depFileRel);
- wrk.LogFileWarning(GenT::MOC, SourceFile, message);
- }
- }
- }
- return false;
- }
- void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
- {
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GenT::MOC, BuildFile)) {
- // Compose moc command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Moc().Executable);
- // Add options
- cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(),
- wrk.Moc().AllOptions.end());
- // Add predefs include
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- cmd.emplace_back("--include");
- cmd.push_back(wrk.Moc().PredefsFileAbs);
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
- // Execute moc command
- ProcessResultT result;
- if (wrk.RunProcess(GenT::MOC, result, cmd)) {
- // Moc command success
- // Print moc output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GenT::MOC, result.StdOut);
- }
- // Notify the generator that a not included file changed (on demand)
- if (IncludeString.empty()) {
- wrk.Gen().ParallelMocAutoUpdated();
- }
- } else {
- // Moc command failed
- {
- std::string emsg = "The moc process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
- }
- void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk)
- {
- // Compute build file name
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
- if (UpdateRequired(wrk)) {
- GenerateUic(wrk);
- }
- }
- bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk)
- {
- bool const verbose = wrk.Gen().Log().Verbose();
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GenT::UIC, reason);
- }
- return true;
- }
- // Test if the uic settings changed
- if (wrk.Uic().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the UIC settings changed";
- wrk.LogInfo(GenT::UIC, reason);
- }
- return true;
- }
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GenT::UIC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GenT::UIC, reason);
- }
- return true;
- }
- }
- return false;
- }
- void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
- {
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GenT::UIC, BuildFile)) {
- // Compose uic command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Uic().Executable);
- {
- std::vector<std::string> allOpts = wrk.Uic().TargetOptions;
- auto optionIt = wrk.Uic().Options.find(SourceFile);
- if (optionIt != wrk.Uic().Options.end()) {
- UicMergeOptions(allOpts, optionIt->second,
- (wrk.Base().QtVersionMajor == 5));
- }
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
- ProcessResultT result;
- if (wrk.RunProcess(GenT::UIC, result, cmd)) {
- // Uic command success
- // Print uic output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GenT::UIC, result.StdOut);
- }
- } else {
- // Uic command failed
- {
- std::string emsg = "The uic process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += "\nincluded by\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GenT::UIC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
- }
- cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
- uv_loop_t* uvLoop)
- : Gen_(gen)
- {
- // Initialize uv asynchronous callback for process starting
- ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this);
- // Start thread
- Thread_ = std::thread(&WorkerT::Loop, this);
- }
- cmQtAutoGeneratorMocUic::WorkerT::~WorkerT()
- {
- // Join thread
- if (Thread_.joinable()) {
- Thread_.join();
- }
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
- GenT genType, std::string const& message) const
- {
- Log().Info(genType, message);
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
- GenT genType, std::string const& message) const
- {
- Log().Warning(genType, message);
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
- GenT genType, std::string const& filename, std::string const& message) const
- {
- Log().WarningFile(genType, filename, message);
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogError(
- GenT genType, std::string const& message) const
- {
- Gen().ParallelRegisterJobError();
- Log().Error(genType, message);
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
- GenT genType, std::string const& filename, std::string const& message) const
- {
- Gen().ParallelRegisterJobError();
- Log().ErrorFile(genType, filename, message);
- }
- void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
- GenT genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output) const
- {
- Gen().ParallelRegisterJobError();
- Log().ErrorCommand(genType, message, command, output);
- }
- bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
- GenT genType, ProcessResultT& result,
- std::vector<std::string> const& command)
- {
- if (command.empty()) {
- return false;
- }
- // Create process instance
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- Process_ = cm::make_unique<ReadOnlyProcessT>();
- Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir);
- }
- // Send asynchronous process start request to libuv loop
- ProcessRequest_.send();
- // Log command
- if (this->Log().Verbose()) {
- std::string msg = "Running command:\n";
- msg += QuotedCommand(command);
- msg += '\n';
- this->LogInfo(genType, msg);
- }
- // Wait until the process has been finished and destroyed
- {
- std::unique_lock<std::mutex> ulock(ProcessMutex_);
- while (Process_) {
- ProcessCondition_.wait(ulock);
- }
- }
- return !result.error();
- }
- void cmQtAutoGeneratorMocUic::WorkerT::Loop()
- {
- while (true) {
- Gen().WorkerSwapJob(JobHandle_);
- if (JobHandle_) {
- JobHandle_->Process(*this);
- } else {
- break;
- }
- }
- }
- void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle)
- {
- auto& wrk = *reinterpret_cast<WorkerT*>(handle->data);
- {
- std::lock_guard<std::mutex> lock(wrk.ProcessMutex_);
- if (wrk.Process_ && !wrk.Process_->IsStarted()) {
- wrk.Process_->start(handle->loop, [&wrk] { wrk.UVProcessFinished(); });
- }
- }
- if (!wrk.Process_->IsStarted()) {
- wrk.UVProcessFinished();
- }
- }
- void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
- {
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- if (Process_ && (Process_->IsFinished() || !Process_->IsStarted())) {
- Process_.reset();
- }
- }
- // Notify idling thread
- ProcessCondition_.notify_one();
- }
- cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
- : Base_(&FileSys())
- , Moc_(&FileSys())
- {
- // Precompile regular expressions
- Moc_.RegExpInclude.compile(
- "(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
- Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
- // Initialize libuv asynchronous iteration request
- UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
- }
- cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() = default;
- bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
- {
- // -- Meta
- Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
- // Utility lambdas
- auto InfoGet = [makefile](const char* key) {
- return makefile->GetSafeDefinition(key);
- };
- auto InfoGetBool = [makefile](const char* key) {
- return makefile->IsOn(key);
- };
- auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
- return list;
- };
- auto InfoGetLists =
- [makefile](const char* key) -> std::vector<std::vector<std::string>> {
- std::vector<std::vector<std::string>> lists;
- {
- std::string const value = makefile->GetSafeDefinition(key);
- std::string::size_type pos = 0;
- while (pos < value.size()) {
- std::string::size_type next = value.find(ListSep, pos);
- std::string::size_type length =
- (next != std::string::npos) ? next - pos : value.size() - pos;
- // Remove enclosing braces
- if (length >= 2) {
- std::string::const_iterator itBeg = value.begin() + (pos + 1);
- std::string::const_iterator itEnd = itBeg + (length - 2);
- {
- std::string subValue(itBeg, itEnd);
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(subValue, list);
- lists.push_back(std::move(list));
- }
- }
- pos += length;
- pos += ListSep.size();
- }
- }
- return lists;
- };
- auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += InfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- return makefile->GetSafeDefinition(key);
- }
- return std::string(valueConf);
- };
- auto InfoGetConfigList =
- [&InfoGetConfig](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
- return list;
- };
- // -- Read info file
- if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GenT::GEN, InfoFile(), "File processing failed");
- return false;
- }
- // -- Meta
- Log().RaiseVerbosity(InfoGet("AM_VERBOSITY"));
- Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
- {
- unsigned long num = Base_.NumThreads;
- if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
- num = std::max<unsigned long>(num, 1);
- num = std::min<unsigned long>(num, ParallelMax);
- Base_.NumThreads = static_cast<unsigned int>(num);
- }
- }
- // - Files and directories
- Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
- Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
- Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
- Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
- Base_.IncludeProjectDirsBefore =
- InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
- Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
- if (Base_.AutogenBuildDir.empty()) {
- Log().ErrorFile(GenT::GEN, InfoFile(), "Autogen build directory missing");
- return false;
- }
- // include directory
- Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
- if (Base_.AutogenIncludeDir.empty()) {
- Log().ErrorFile(GenT::GEN, InfoFile(),
- "Autogen include directory missing");
- return false;
- }
- // - Files
- SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
- if (SettingsFile_.empty()) {
- Log().ErrorFile(GenT::GEN, InfoFile(), "Settings file name missing");
- return false;
- }
- // - Qt environment
- {
- unsigned long qtv = Base_.QtVersionMajor;
- if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
- &qtv)) {
- Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
- }
- }
- // - Moc
- Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
- Moc_.Enabled = !Moc().Executable.empty();
- if (Moc().Enabled) {
- for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
- Moc_.SkipList.insert(std::move(sfl));
- }
- Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
- Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
- Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
- Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
- for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
- Moc_.MacroFilters.emplace_back(
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
- }
- {
- auto pushFilter = [this](std::string const& key, std::string const& exp,
- std::string& error) {
- if (!key.empty()) {
- if (!exp.empty()) {
- Moc_.DependFilters.emplace_back();
- KeyExpT& filter(Moc_.DependFilters.back());
- if (filter.Exp.compile(exp)) {
- filter.Key = key;
- } else {
- error = "Regular expression compiling failed";
- }
- } else {
- error = "Regular expression is empty";
- }
- } else {
- error = "Key is empty";
- }
- if (!error.empty()) {
- error = ("AUTOMOC_DEPEND_FILTERS: " + error);
- error += "\n";
- error += " Key: ";
- error += Quoted(key);
- error += "\n";
- error += " Exp: ";
- error += Quoted(exp);
- error += "\n";
- }
- };
- std::string error;
- // Insert default filter for Q_PLUGIN_METADATA
- if (Base().QtVersionMajor != 4) {
- pushFilter("Q_PLUGIN_METADATA",
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"",
- error);
- }
- // Insert user defined dependency filters
- {
- std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
- if ((flts.size() % 2) == 0) {
- for (std::vector<std::string>::iterator itC = flts.begin(),
- itE = flts.end();
- itC != itE; itC += 2) {
- pushFilter(*itC, *(itC + 1), error);
- if (!error.empty()) {
- break;
- }
- }
- } else {
- Log().ErrorFile(
- GenT::MOC, InfoFile(),
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
- return false;
- }
- }
- if (!error.empty()) {
- Log().ErrorFile(GenT::MOC, InfoFile(), error);
- return false;
- }
- }
- Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
- // Install moc predefs job
- if (!Moc().PredefsCmd.empty()) {
- JobQueues_.MocPredefs.emplace_back(cm::make_unique<JobMocPredefsT>());
- }
- }
- // - Uic
- Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
- Uic_.Enabled = !Uic().Executable.empty();
- if (Uic().Enabled) {
- for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
- Uic_.SkipList.insert(std::move(sfl));
- }
- Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
- Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
- {
- auto sources = InfoGetList("AM_UIC_OPTIONS_FILES");
- auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS");
- // Compare list sizes
- if (sources.size() != options.size()) {
- std::ostringstream ost;
- ost << "files/options lists sizes mismatch (" << sources.size() << "/"
- << options.size() << ")";
- Log().ErrorFile(GenT::UIC, InfoFile(), ost.str());
- return false;
- }
- auto fitEnd = sources.cend();
- auto fit = sources.begin();
- auto oit = options.begin();
- while (fit != fitEnd) {
- Uic_.Options[*fit] = std::move(*oit);
- ++fit;
- ++oit;
- }
- }
- }
- // - Headers and sources
- {
- auto addHeader = [this](std::string&& hdr, bool moc, bool uic) {
- this->JobQueues_.Headers.emplace_back(
- cm::make_unique<JobParseT>(std::move(hdr), moc, uic, true));
- };
- auto addSource = [this](std::string&& src, bool moc, bool uic) {
- this->JobQueues_.Sources.emplace_back(
- cm::make_unique<JobParseT>(std::move(src), moc, uic, false));
- };
- // Add headers
- for (std::string& hdr : InfoGetList("AM_HEADERS")) {
- addHeader(std::move(hdr), true, true);
- }
- if (Moc().Enabled) {
- for (std::string& hdr : InfoGetList("AM_MOC_HEADERS")) {
- addHeader(std::move(hdr), true, false);
- }
- }
- if (Uic().Enabled) {
- for (std::string& hdr : InfoGetList("AM_UIC_HEADERS")) {
- addHeader(std::move(hdr), false, true);
- }
- }
- // Add sources
- for (std::string& src : InfoGetList("AM_SOURCES")) {
- addSource(std::move(src), true, true);
- }
- if (Moc().Enabled) {
- for (std::string& src : InfoGetList("AM_MOC_SOURCES")) {
- addSource(std::move(src), true, false);
- }
- }
- if (Uic().Enabled) {
- for (std::string& src : InfoGetList("AM_UIC_SOURCES")) {
- addSource(std::move(src), false, true);
- }
- }
- }
- // Init derived information
- // ------------------------
- // Init file path checksum generator
- FileSys().setupFilePathChecksum(
- Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
- Base().ProjectBinaryDir);
- // Moc variables
- if (Moc().Enabled) {
- // Mocs compilation file
- Moc_.CompFileAbs = Base().AbsoluteBuildPath("mocs_compilation.cpp");
- // Moc predefs file
- if (!Moc_.PredefsCmd.empty()) {
- Moc_.PredefsFileRel = "moc_predefs";
- if (Base_.MultiConfig) {
- Moc_.PredefsFileRel += '_';
- Moc_.PredefsFileRel += InfoConfig();
- }
- Moc_.PredefsFileRel += ".h";
- Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
- }
- // Sort include directories on demand
- if (Base().IncludeProjectDirsBefore) {
- // Move strings to temporary list
- std::list<std::string> includes;
- includes.insert(includes.end(), Moc().IncludePaths.begin(),
- Moc().IncludePaths.end());
- Moc_.IncludePaths.clear();
- Moc_.IncludePaths.reserve(includes.size());
- // Append project directories only
- {
- std::array<std::string const*, 2> const movePaths = {
- { &Base().ProjectBinaryDir, &Base().ProjectSourceDir }
- };
- for (std::string const* ppath : movePaths) {
- std::list<std::string>::iterator it = includes.begin();
- while (it != includes.end()) {
- std::string const& path = *it;
- if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
- Moc_.IncludePaths.push_back(path);
- it = includes.erase(it);
- } else {
- ++it;
- }
- }
- }
- }
- // Append remaining directories
- Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(),
- includes.end());
- }
- // Compose moc includes list
- {
- std::set<std::string> frameworkPaths;
- for (std::string const& path : Moc().IncludePaths) {
- Moc_.Includes.push_back("-I" + path);
- // Extract framework path
- if (cmHasLiteralSuffix(path, ".framework/Headers")) {
- // Go up twice to get to the framework root
- std::vector<std::string> pathComponents;
- FileSys().SplitPath(path, pathComponents);
- std::string frameworkPath = FileSys().JoinPath(
- pathComponents.begin(), pathComponents.end() - 2);
- frameworkPaths.insert(frameworkPath);
- }
- }
- // Append framework includes
- for (std::string const& path : frameworkPaths) {
- Moc_.Includes.emplace_back("-F");
- Moc_.Includes.push_back(path);
- }
- }
- // Setup single list with all options
- {
- // Add includes
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
- Moc().Includes.end());
- // Add definitions
- for (std::string const& def : Moc().Definitions) {
- Moc_.AllOptions.push_back("-D" + def);
- }
- // Add options
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
- Moc().Options.end());
- }
- }
- return true;
- }
- bool cmQtAutoGeneratorMocUic::Process()
- {
- // Run libuv event loop
- UVRequest().send();
- if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
- if (JobError_) {
- return false;
- }
- } else {
- return false;
- }
- return true;
- }
- void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle)
- {
- reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage();
- }
- void cmQtAutoGeneratorMocUic::PollStage()
- {
- switch (Stage_) {
- case StageT::SETTINGS_READ:
- SettingsFileRead();
- SetStage(StageT::CREATE_DIRECTORIES);
- break;
- case StageT::CREATE_DIRECTORIES:
- CreateDirectories();
- SetStage(StageT::PARSE_SOURCES);
- break;
- case StageT::PARSE_SOURCES:
- if (ThreadsStartJobs(JobQueues_.Sources)) {
- SetStage(StageT::PARSE_HEADERS);
- }
- break;
- case StageT::PARSE_HEADERS:
- if (ThreadsStartJobs(JobQueues_.Headers)) {
- SetStage(StageT::MOC_PREDEFS);
- }
- break;
- case StageT::MOC_PREDEFS:
- if (ThreadsStartJobs(JobQueues_.MocPredefs)) {
- SetStage(StageT::MOC_PROCESS);
- }
- break;
- case StageT::MOC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Moc)) {
- SetStage(StageT::MOCS_COMPILATION);
- }
- break;
- case StageT::MOCS_COMPILATION:
- if (ThreadsJobsDone()) {
- MocGenerateCompilation();
- SetStage(StageT::UIC_PROCESS);
- }
- break;
- case StageT::UIC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Uic)) {
- SetStage(StageT::SETTINGS_WRITE);
- }
- break;
- case StageT::SETTINGS_WRITE:
- SettingsFileWrite();
- SetStage(StageT::FINISH);
- break;
- case StageT::FINISH:
- if (ThreadsJobsDone()) {
- // Clear all libuv handles
- ThreadsStop();
- UVRequest().reset();
- // Set highest END stage manually
- Stage_ = StageT::END;
- }
- break;
- case StageT::END:
- break;
- }
- }
- void cmQtAutoGeneratorMocUic::SetStage(StageT stage)
- {
- if (JobError_) {
- stage = StageT::FINISH;
- }
- // Only allow to increase the stage
- if (Stage_ < stage) {
- Stage_ = stage;
- UVRequest().send();
- }
- }
- void cmQtAutoGeneratorMocUic::SettingsFileRead()
- {
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- if (Moc_.Enabled) {
- std::string str;
- str += Moc().Executable;
- str += sep;
- str += cmJoin(Moc().AllOptions, ";");
- str += sep;
- str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE";
- str += sep;
- str += cmJoin(Moc().PredefsCmd, ";");
- str += sep;
- SettingsStringMoc_ = crypt.HashString(str);
- }
- if (Uic().Enabled) {
- std::string str;
- str += Uic().Executable;
- str += sep;
- str += cmJoin(Uic().TargetOptions, ";");
- for (const auto& item : Uic().Options) {
- str += sep;
- str += item.first;
- str += sep;
- str += cmJoin(item.second, ";");
- }
- str += sep;
- SettingsStringUic_ = crypt.HashString(str);
- }
- }
- // Read old settings and compare
- {
- std::string content;
- if (FileSys().FileRead(content, SettingsFile_)) {
- if (Moc().Enabled) {
- if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
- Moc_.SettingsChanged = true;
- }
- }
- if (Uic().Enabled) {
- if (SettingsStringUic_ != SettingsFind(content, "uic")) {
- Uic_.SettingsChanged = true;
- }
- }
- // In case any setting changed remove the old settings file.
- // This triggers a full rebuild on the next run if the current
- // build is aborted before writing the current settings in the end.
- if (Moc().SettingsChanged || Uic().SettingsChanged) {
- FileSys().FileRemove(SettingsFile_);
- }
- } else {
- // Settings file read failed
- if (Moc().Enabled) {
- Moc_.SettingsChanged = true;
- }
- if (Uic().Enabled) {
- Uic_.SettingsChanged = true;
- }
- }
- }
- }
- void cmQtAutoGeneratorMocUic::SettingsFileWrite()
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Only write if any setting changed
- if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
- if (Log().Verbose()) {
- Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_));
- }
- // Compose settings file content
- std::string content;
- {
- auto SettingAppend = [&content](const char* key,
- std::string const& value) {
- if (!value.empty()) {
- content += key;
- content += ':';
- content += value;
- content += '\n';
- }
- };
- SettingAppend("moc", SettingsStringMoc_);
- SettingAppend("uic", SettingsStringUic_);
- }
- // Write settings file
- if (!FileSys().FileWrite(GenT::GEN, SettingsFile_, content)) {
- Log().ErrorFile(GenT::GEN, SettingsFile_,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- FileSys().FileRemove(SettingsFile_);
- RegisterJobError();
- }
- }
- }
- void cmQtAutoGeneratorMocUic::CreateDirectories()
- {
- // Create AUTOGEN include directory
- if (!FileSys().MakeDirectory(GenT::GEN, Base().AutogenIncludeDir)) {
- RegisterJobError();
- }
- }
- bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue)
- {
- bool done = false;
- std::size_t queueSize = queue.size();
- // Change the active queue
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Check if there are still unfinished jobs from the previous queue
- if (JobsRemain_ == 0) {
- if (!JobThreadsAbort_) {
- JobQueue_.swap(queue);
- JobsRemain_ = queueSize;
- } else {
- // Abort requested
- queue.clear();
- queueSize = 0;
- }
- done = true;
- }
- }
- if (done && (queueSize != 0)) {
- // Start new threads on demand
- if (Workers_.empty()) {
- Workers_.resize(Base().NumThreads);
- for (auto& item : Workers_) {
- item = cm::make_unique<WorkerT>(this, UVLoop());
- }
- } else {
- // Notify threads
- if (queueSize == 1) {
- JobsConditionRead_.notify_one();
- } else {
- JobsConditionRead_.notify_all();
- }
- }
- }
- return done;
- }
- void cmQtAutoGeneratorMocUic::ThreadsStop()
- {
- if (!Workers_.empty()) {
- // Clear all jobs
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- JobThreadsAbort_ = true;
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
- JobQueues_.Sources.clear();
- JobQueues_.Headers.clear();
- JobQueues_.MocPredefs.clear();
- JobQueues_.Moc.clear();
- JobQueues_.Uic.clear();
- }
- // Wake threads
- JobsConditionRead_.notify_all();
- // Join and clear threads
- Workers_.clear();
- }
- }
- bool cmQtAutoGeneratorMocUic::ThreadsJobsDone()
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- return (JobsRemain_ == 0);
- }
- void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle)
- {
- bool const jobProcessed(jobHandle);
- if (jobProcessed) {
- jobHandle.reset();
- }
- {
- std::unique_lock<std::mutex> jobsLock(JobsMutex_);
- // Reduce the remaining job count and notify the libuv loop
- // when all jobs are done
- if (jobProcessed) {
- --JobsRemain_;
- if (JobsRemain_ == 0) {
- UVRequest().send();
- }
- }
- // Wait for new jobs
- while (!JobThreadsAbort_ && JobQueue_.empty()) {
- JobsConditionRead_.wait(jobsLock);
- }
- // Try to pick up a new job handle
- if (!JobThreadsAbort_ && !JobQueue_.empty()) {
- jobHandle = std::move(JobQueue_.front());
- JobQueue_.pop_front();
- }
- }
- }
- void cmQtAutoGeneratorMocUic::ParallelRegisterJobError()
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- RegisterJobError();
- }
- // Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be
- // locked
- void cmQtAutoGeneratorMocUic::RegisterJobError()
- {
- JobError_ = true;
- if (!JobThreadsAbort_) {
- JobThreadsAbort_ = true;
- // Clear remaining jobs
- if (JobsRemain_ != 0) {
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
- }
- }
- }
- bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle)
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Do additional tests if this is an included moc job
- const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle));
- if (!mocJob.IncludeString.empty()) {
- // Register included moc file and look for collisions
- MocIncludedFiles_.emplace(mocJob.SourceFile);
- if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) {
- // Another source file includes the same moc file!
- for (const JobHandleT& otherHandle : JobQueues_.Moc) {
- const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle));
- if (otherJob.IncludeString == mocJob.IncludeString) {
- // Check if the same moc file would be generated from different
- // source files which is an error.
- if (otherJob.SourceFile != mocJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(mocJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same moc include string ";
- error += Quoted(mocJob.IncludeString);
- error += "\nbut the moc file would be generated from different "
- "source files\n ";
- error += Quoted(mocJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error += ".\nConsider to\n"
- "- not include the \"moc_<NAME>.cpp\" file\n"
- "- add a directory prefix to a \"<NAME>.moc\" include "
- "(e.g \"sub/<NAME>.moc\")\n"
- "- rename the source file(s)\n";
- Log().Error(GenT::MOC, error);
- RegisterJobError();
- }
- // Do not push this job in since the included moc file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- }
- }
- // Push job on demand
- if (pushJobHandle) {
- JobQueues_.Moc.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
- }
- bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle)
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Look for include collisions.
- const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
- for (const JobHandleT& otherHandle : JobQueues_.Uic) {
- const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle));
- if (otherJob.IncludeString == uicJob.IncludeString) {
- // Check if the same uic file would be generated from different
- // source files which would be an error.
- if (otherJob.SourceFile != uicJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(uicJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same uic include string ";
- error += Quoted(uicJob.IncludeString);
- error += "\nbut the uic file would be generated from different "
- "source files\n ";
- error += Quoted(uicJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error +=
- ".\nConsider to\n"
- "- add a directory prefix to a \"ui_<NAME>.h\" include "
- "(e.g \"sub/ui_<NAME>.h\")\n"
- "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
- "include(s)\n";
- Log().Error(GenT::UIC, error);
- RegisterJobError();
- }
- // Do not push this job in since the uic file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- if (pushJobHandle) {
- JobQueues_.Uic.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
- }
- bool cmQtAutoGeneratorMocUic::ParallelMocIncluded(
- std::string const& sourceFile)
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
- }
- std::string cmQtAutoGeneratorMocUic::ParallelMocAutoRegister(
- std::string const& baseName)
- {
- std::string res;
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- res = baseName;
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- } else {
- // Append number suffix to the file name
- for (unsigned int ii = 2; ii != 1024; ++ii) {
- res = baseName;
- res += '_';
- res += std::to_string(ii);
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- break;
- }
- }
- }
- }
- return res;
- }
- void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated()
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- MocAutoFileUpdated_ = true;
- }
- void cmQtAutoGeneratorMocUic::MocGenerateCompilation()
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- if (!JobError_ && Moc().Enabled) {
- // Write mocs compilation build file
- {
- // Compose mocs compilation file content
- std::string content =
- "// This file is autogenerated. Changes will be overwritten.\n";
- if (MocAutoFiles_.empty()) {
- // Placeholder content
- content += "// No files found that require moc or the moc files are "
- "included\n";
- content += "enum some_compilers { need_more_than_nothing };\n";
- } else {
- // Valid content
- char const sbeg = Base().MultiConfig ? '<' : '"';
- char const send = Base().MultiConfig ? '>' : '"';
- for (std::string const& mocfile : MocAutoFiles_) {
- content += "#include ";
- content += sbeg;
- content += mocfile;
- content += send;
- content += '\n';
- }
- }
- std::string const& compAbs = Moc().CompFileAbs;
- if (FileSys().FileDiffers(compAbs, content)) {
- // Actually write mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs);
- }
- if (!FileSys().FileWrite(GenT::MOC, compAbs, content)) {
- Log().ErrorFile(GenT::MOC, compAbs,
- "mocs compilation file writing failed");
- RegisterJobError();
- return;
- }
- } else if (MocAutoFileUpdated_) {
- // Only touch mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs);
- }
- FileSys().Touch(compAbs);
- }
- }
- // Write mocs compilation wrapper file
- if (Base().MultiConfig) {
- }
- }
- }
|