| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmQtAutoGen.h"
- #include "cmQtAutoGeneratorMocUic.h"
- #include <algorithm>
- #include <array>
- #include <list>
- #include <memory>
- #include <sstream>
- #include <string.h>
- #include <utility>
- #include "cmAlgorithms.h"
- #include "cmCryptoHash.h"
- #include "cmMakefile.h"
- #include "cmOutputConverter.h"
- #include "cmSystemTools.h"
- #include "cmake.h"
- #if defined(__APPLE__)
- #include <unistd.h>
- #endif
- // -- Static variables
- static const char* SettingsKeyMoc = "AM_MOC_SETTINGS_HASH";
- static const char* SettingsKeyUic = "AM_UIC_SETTINGS_HASH";
- // -- Static functions
- static std::string SubDirPrefix(std::string const& fileName)
- {
- std::string res(cmSystemTools::GetFilenamePath(fileName));
- if (!res.empty()) {
- res += '/';
- }
- return res;
- }
- static bool ListContains(std::vector<std::string> const& list,
- std::string const& entry)
- {
- return (std::find(list.begin(), list.end(), entry) != list.end());
- }
- // -- Class methods
- cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
- : MultiConfig(cmQtAutoGen::WRAP)
- , IncludeProjectDirsBefore(false)
- , QtVersionMajor(4)
- , MocSettingsChanged(false)
- , MocPredefsChanged(false)
- , MocRelaxedMode(false)
- , UicSettingsChanged(false)
- {
- // Precompile regular expressions
- this->MocRegExpInclude.compile(
- "[\n][ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
- this->UicRegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
- }
- bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
- {
- // -- Meta
- this->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(cmQtAutoGen::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 += cmQtAutoGen::listSep.size();
- }
- }
- return lists;
- };
- auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += this->GetInfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- valueConf = 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(this->GetInfoFile().c_str())) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "File processing failed");
- return false;
- }
- // -- Meta
- this->MultiConfig = cmQtAutoGen::MultiConfigType(InfoGet("AM_MULTI_CONFIG"));
- this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
- if (this->ConfigSuffix.empty()) {
- this->ConfigSuffix = "_";
- this->ConfigSuffix += this->GetInfoConfig();
- }
- this->SettingsFile = InfoGetConfig("AM_SETTINGS_FILE");
- if (this->SettingsFile.empty()) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "Settings file name missing");
- return false;
- }
- // - Files and directories
- this->ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
- this->ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
- this->CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
- this->CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
- this->IncludeProjectDirsBefore =
- InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
- this->AutogenBuildDir = InfoGet("AM_BUILD_DIR");
- if (this->AutogenBuildDir.empty()) {
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
- "Autogen build directory missing");
- return false;
- }
- // - Qt environment
- if (!cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"),
- &this->QtVersionMajor)) {
- this->QtVersionMajor = 4;
- }
- this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE");
- this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE");
- // - Moc
- if (this->MocEnabled()) {
- this->MocSkipList = InfoGetList("AM_MOC_SKIP");
- this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
- #ifdef _WIN32
- {
- std::string const win32("WIN32");
- if (!ListContains(this->MocDefinitions, win32)) {
- this->MocDefinitions.push_back(win32);
- }
- }
- #endif
- this->MocIncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
- this->MocOptions = InfoGetList("AM_MOC_OPTIONS");
- this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
- {
- std::vector<std::string> const MocMacroNames =
- InfoGetList("AM_MOC_MACRO_NAMES");
- for (std::string const& item : MocMacroNames) {
- this->MocMacroFilters.emplace_back(
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
- }
- }
- {
- std::vector<std::string> const mocDependFilters =
- InfoGetList("AM_MOC_DEPEND_FILTERS");
- // Insert Q_PLUGIN_METADATA dependency filter
- if (this->QtVersionMajor != 4) {
- this->MocDependFilterPush("Q_PLUGIN_METADATA",
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
- }
- // Insert user defined dependency filters
- if ((mocDependFilters.size() % 2) == 0) {
- for (std::vector<std::string>::const_iterator
- dit = mocDependFilters.begin(),
- ditEnd = mocDependFilters.end();
- dit != ditEnd; dit += 2) {
- if (!this->MocDependFilterPush(*dit, *(dit + 1))) {
- return false;
- }
- }
- } else {
- this->LogFileError(
- cmQtAutoGen::MOC, this->GetInfoFile(),
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
- return false;
- }
- }
- this->MocPredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
- }
- // - Uic
- if (this->UicEnabled()) {
- this->UicSkipList = InfoGetList("AM_UIC_SKIP");
- this->UicSearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
- this->UicTargetOptions = 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() << ")";
- this->LogFileError(cmQtAutoGen::UIC, this->GetInfoFile(), ost.str());
- return false;
- }
- auto fitEnd = sources.cend();
- auto fit = sources.begin();
- auto oit = options.begin();
- while (fit != fitEnd) {
- this->UicOptions[*fit] = std::move(*oit);
- ++fit;
- ++oit;
- }
- }
- }
- // Initialize source file jobs
- {
- // Utility lambdas
- auto AddJob = [this](std::map<std::string, SourceJob>& jobs,
- std::string&& sourceFile) {
- const bool moc = !this->MocSkip(sourceFile);
- const bool uic = !this->UicSkip(sourceFile);
- if (moc || uic) {
- SourceJob& job = jobs[std::move(sourceFile)];
- job.Moc = moc;
- job.Uic = uic;
- }
- };
- // Add header jobs
- for (std::string& hdr : InfoGetList("AM_HEADERS")) {
- AddJob(this->HeaderJobs, std::move(hdr));
- }
- // Add source jobs
- {
- std::vector<std::string> sources = InfoGetList("AM_SOURCES");
- // Add header(s) for the source file
- for (std::string const& src : sources) {
- const bool srcMoc = !this->MocSkip(src);
- const bool srcUic = !this->UicSkip(src);
- if (!srcMoc && !srcUic) {
- continue;
- }
- // Search for the default header file and a private header
- std::array<std::string, 2> headerBases;
- headerBases[0] = SubDirPrefix(src);
- headerBases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src);
- headerBases[1] = headerBases[0];
- headerBases[1] += "_p";
- for (std::string const& headerBase : headerBases) {
- std::string header;
- if (this->FindHeader(header, headerBase)) {
- const bool moc = srcMoc && !this->MocSkip(header);
- const bool uic = srcUic && !this->UicSkip(header);
- if (moc || uic) {
- SourceJob& job = this->HeaderJobs[std::move(header)];
- job.Moc = moc;
- job.Uic = uic;
- }
- }
- }
- }
- // Add Source jobs
- for (std::string& src : sources) {
- AddJob(this->SourceJobs, std::move(src));
- }
- }
- }
- // Init derived information
- // ------------------------
- // Init file path checksum generator
- this->FilePathChecksum.setupParentDirs(
- this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir,
- this->ProjectBinaryDir);
- // include directory
- this->AutogenIncludeDir = "include";
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- this->AutogenIncludeDir += this->ConfigSuffix;
- }
- this->AutogenIncludeDir += "/";
- // Moc variables
- if (this->MocEnabled()) {
- // Mocs compilation file
- this->MocCompFileRel = "mocs_compilation";
- if (this->MultiConfig == cmQtAutoGen::FULL) {
- this->MocCompFileRel += this->ConfigSuffix;
- }
- this->MocCompFileRel += ".cpp";
- this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->MocCompFileRel);
- // Moc predefs file
- if (!this->MocPredefsCmd.empty()) {
- this->MocPredefsFileRel = "moc_predefs";
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- this->MocPredefsFileRel += this->ConfigSuffix;
- }
- this->MocPredefsFileRel += ".h";
- this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->MocPredefsFileRel);
- }
- // Sort include directories on demand
- if (this->IncludeProjectDirsBefore) {
- // Move strings to temporary list
- std::list<std::string> includes;
- includes.insert(includes.end(), this->MocIncludePaths.begin(),
- this->MocIncludePaths.end());
- this->MocIncludePaths.clear();
- this->MocIncludePaths.reserve(includes.size());
- // Append project directories only
- {
- std::array<std::string const*, 2> const movePaths = {
- { &this->ProjectBinaryDir, &this->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())) {
- this->MocIncludePaths.push_back(path);
- it = includes.erase(it);
- } else {
- ++it;
- }
- }
- }
- }
- // Append remaining directories
- this->MocIncludePaths.insert(this->MocIncludePaths.end(),
- includes.begin(), includes.end());
- }
- // Compose moc includes list
- {
- std::set<std::string> frameworkPaths;
- for (std::string const& path : this->MocIncludePaths) {
- this->MocIncludes.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;
- cmSystemTools::SplitPath(path, pathComponents);
- std::string frameworkPath = cmSystemTools::JoinPath(
- pathComponents.begin(), pathComponents.end() - 2);
- frameworkPaths.insert(frameworkPath);
- }
- }
- // Append framework includes
- for (std::string const& path : frameworkPaths) {
- this->MocIncludes.push_back("-F");
- this->MocIncludes.push_back(path);
- }
- }
- // Setup single list with all options
- {
- // Add includes
- this->MocAllOptions.insert(this->MocAllOptions.end(),
- this->MocIncludes.begin(),
- this->MocIncludes.end());
- // Add definitions
- for (std::string const& def : this->MocDefinitions) {
- this->MocAllOptions.push_back("-D" + def);
- }
- // Add options
- this->MocAllOptions.insert(this->MocAllOptions.end(),
- this->MocOptions.begin(),
- this->MocOptions.end());
- }
- }
- return true;
- }
- void cmQtAutoGeneratorMocUic::SettingsFileRead(cmMakefile* makefile)
- {
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- if (this->MocEnabled()) {
- std::string str;
- str += this->MocExecutable;
- str += sep;
- str += cmJoin(this->MocAllOptions, ";");
- str += sep;
- str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE";
- str += sep;
- str += cmJoin(this->MocPredefsCmd, ";");
- str += sep;
- this->SettingsStringMoc = crypt.HashString(str);
- }
- if (this->UicEnabled()) {
- std::string str;
- str += this->UicExecutable;
- str += sep;
- str += cmJoin(this->UicTargetOptions, ";");
- for (const auto& item : this->UicOptions) {
- str += sep;
- str += item.first;
- str += sep;
- str += cmJoin(item.second, ";");
- }
- str += sep;
- this->SettingsStringUic = crypt.HashString(str);
- }
- }
- // Read old settings
- if (makefile->ReadListFile(this->SettingsFile.c_str())) {
- {
- auto SMatch = [makefile](const char* key, std::string const& value) {
- return (value == makefile->GetSafeDefinition(key));
- };
- if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) {
- this->MocSettingsChanged = true;
- }
- if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) {
- this->UicSettingsChanged = 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 (this->SettingsChanged()) {
- cmSystemTools::RemoveFile(this->SettingsFile);
- }
- } else {
- // If the file could not be read re-generate everythiung.
- this->MocSettingsChanged = true;
- this->UicSettingsChanged = true;
- }
- }
- bool cmQtAutoGeneratorMocUic::SettingsFileWrite()
- {
- bool success = true;
- // Only write if any setting changed
- if (this->SettingsChanged()) {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " +
- cmQtAutoGen::Quoted(this->SettingsFile));
- }
- // Compose settings file content
- std::string settings;
- {
- auto SettingAppend = [&settings](const char* key,
- std::string const& value) {
- settings += "set(";
- settings += key;
- settings += " ";
- settings += cmOutputConverter::EscapeForCMake(value);
- settings += ")\n";
- };
- SettingAppend(SettingsKeyMoc, this->SettingsStringMoc);
- SettingAppend(SettingsKeyUic, this->SettingsStringUic);
- }
- // Write settings file
- if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) {
- this->LogFileError(cmQtAutoGen::GEN, this->SettingsFile,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- cmSystemTools::RemoveFile(this->SettingsFile);
- success = false;
- }
- }
- return success;
- }
- bool cmQtAutoGeneratorMocUic::Process(cmMakefile* makefile)
- {
- // the program goes through all .cpp files to see which moc files are
- // included. It is not really interesting how the moc file is named, but
- // what file the moc is created from. Once a moc is included the same moc
- // may not be included in the mocs_compilation.cpp file anymore.
- // OTOH if there's a header containing Q_OBJECT where no corresponding
- // moc file is included anywhere a moc_<filename>.cpp file is created and
- // included in the mocs_compilation.cpp file.
- if (!this->InitInfoFile(makefile)) {
- return false;
- }
- // Read latest settings
- this->SettingsFileRead(makefile);
- // Create AUTOGEN include directory
- {
- std::string const incDirAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, this->AutogenIncludeDir);
- if (!cmSystemTools::MakeDirectory(incDirAbs)) {
- this->LogFileError(cmQtAutoGen::GEN, incDirAbs,
- "Could not create directory");
- return false;
- }
- }
- // Parse source files
- for (const auto& item : this->SourceJobs) {
- if (!this->ParseSourceFile(item.first, item.second)) {
- return false;
- }
- }
- // Parse header files
- for (const auto& item : this->HeaderJobs) {
- if (!this->ParseHeaderFile(item.first, item.second)) {
- return false;
- }
- }
- // Read missing dependency information
- if (!this->ParsePostprocess()) {
- return false;
- }
- // Generate files
- if (!this->MocGenerateAll()) {
- return false;
- }
- if (!this->UicGenerateAll()) {
- return false;
- }
- if (!this->SettingsFileWrite()) {
- return false;
- }
- return true;
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::ParseSourceFile(std::string const& absFilename,
- const SourceJob& job)
- {
- std::string contentText;
- std::string error;
- bool success = this->FileRead(contentText, absFilename, &error);
- if (success) {
- if (!contentText.empty()) {
- if (job.Moc) {
- success = this->MocParseSourceContent(absFilename, contentText);
- }
- if (success && job.Uic) {
- success = this->UicParseContent(absFilename, contentText);
- }
- } else {
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
- "The source file is empty");
- }
- } else {
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
- "Could not read the source file: " + error);
- }
- return success;
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::ParseHeaderFile(std::string const& absFilename,
- const SourceJob& job)
- {
- std::string contentText;
- std::string error;
- bool success = this->FileRead(contentText, absFilename, &error);
- if (success) {
- if (!contentText.empty()) {
- if (job.Moc) {
- this->MocParseHeaderContent(absFilename, contentText);
- }
- if (job.Uic) {
- success = this->UicParseContent(absFilename, contentText);
- }
- } else {
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
- "The header file is empty");
- }
- } else {
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
- "Could not read the header file: " + error);
- }
- return success;
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::ParsePostprocess()
- {
- bool success = true;
- // Read missing dependencies
- for (auto& item : this->MocJobsIncluded) {
- if (!item->DependsValid) {
- std::string content;
- std::string error;
- if (this->FileRead(content, item->SourceFile, &error)) {
- this->MocFindDepends(item->SourceFile, content, item->Depends);
- item->DependsValid = true;
- } else {
- std::string emsg = "Could not read file\n ";
- emsg += item->SourceFile;
- emsg += "\nrequired by moc include \"";
- emsg += item->IncludeString;
- emsg += "\".\n";
- emsg += error;
- this->LogFileError(cmQtAutoGen::MOC, item->Includer, emsg);
- success = false;
- break;
- }
- }
- }
- return success;
- }
- /**
- * @brief Tests if the file should be ignored for moc scanning
- * @return True if the file should be ignored
- */
- bool cmQtAutoGeneratorMocUic::MocSkip(std::string const& absFilename) const
- {
- if (this->MocEnabled()) {
- // Test if the file name is on the skip list
- if (!ListContains(this->MocSkipList, absFilename)) {
- return false;
- }
- }
- return true;
- }
- /**
- * @brief Tests if the C++ content requires moc processing
- * @return True if moc is required
- */
- bool cmQtAutoGeneratorMocUic::MocRequired(std::string const& contentText,
- std::string* macroName)
- {
- for (KeyRegExp& filter : this->MocMacroFilters) {
- // Run a simple find string operation before the expensive
- // regular expression check
- if (contentText.find(filter.Key) != std::string::npos) {
- if (filter.RegExp.find(contentText)) {
- // Return macro name on demand
- if (macroName != nullptr) {
- *macroName = filter.Key;
- }
- return true;
- }
- }
- }
- return false;
- }
- std::string cmQtAutoGeneratorMocUic::MocStringMacros() const
- {
- std::string res;
- const auto itB = this->MocMacroFilters.cbegin();
- const auto itE = this->MocMacroFilters.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::MocStringHeaders(
- std::string const& fileBase) const
- {
- std::string res = fileBase;
- res += ".{";
- res += cmJoin(this->HeaderExtensions, ",");
- res += "}";
- return res;
- }
- std::string cmQtAutoGeneratorMocUic::MocFindIncludedHeader(
- std::string const& sourcePath, std::string const& includeBase) const
- {
- std::string header;
- // Search in vicinity of the source
- if (!this->FindHeader(header, sourcePath + includeBase)) {
- // Search in include directories
- for (std::string const& path : this->MocIncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeBase;
- if (this->FindHeader(header, fullPath)) {
- break;
- }
- }
- }
- // Sanitize
- if (!header.empty()) {
- header = cmSystemTools::GetRealPath(header);
- }
- return header;
- }
- bool cmQtAutoGeneratorMocUic::MocFindIncludedFile(
- std::string& absFile, std::string const& sourcePath,
- std::string const& includeString) const
- {
- bool success = false;
- // Search in vicinity of the source
- {
- std::string testPath = sourcePath;
- testPath += includeString;
- if (cmSystemTools::FileExists(testPath.c_str())) {
- absFile = cmSystemTools::GetRealPath(testPath);
- success = true;
- }
- }
- // Search in include directories
- if (!success) {
- for (std::string const& path : this->MocIncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeString;
- if (cmSystemTools::FileExists(fullPath.c_str())) {
- absFile = cmSystemTools::GetRealPath(fullPath);
- success = true;
- break;
- }
- }
- }
- return success;
- }
- bool cmQtAutoGeneratorMocUic::MocDependFilterPush(std::string const& key,
- std::string const& regExp)
- {
- std::string error;
- if (!key.empty()) {
- if (!regExp.empty()) {
- KeyRegExp filter;
- filter.Key = key;
- if (filter.RegExp.compile(regExp)) {
- this->MocDependFilters.push_back(std::move(filter));
- } else {
- error = "Regular expression compiling failed";
- }
- } else {
- error = "Regular expression is empty";
- }
- } else {
- error = "Key is empty";
- }
- if (!error.empty()) {
- std::string emsg = "AUTOMOC_DEPEND_FILTERS: ";
- emsg += error;
- emsg += "\n";
- emsg += " Key: ";
- emsg += cmQtAutoGen::Quoted(key);
- emsg += "\n";
- emsg += " RegExp: ";
- emsg += cmQtAutoGen::Quoted(regExp);
- emsg += "\n";
- this->LogError(cmQtAutoGen::MOC, emsg);
- return false;
- }
- return true;
- }
- void cmQtAutoGeneratorMocUic::MocFindDepends(std::string const& absFilename,
- std::string const& contentText,
- std::set<std::string>& depends)
- {
- if (this->MocDependFilters.empty() && contentText.empty()) {
- return;
- }
- std::vector<std::string> matches;
- for (KeyRegExp& filter : this->MocDependFilters) {
- // Run a simple find string check
- if (contentText.find(filter.Key) != std::string::npos) {
- // Run the expensive regular expression check loop
- const char* contentChars = contentText.c_str();
- while (filter.RegExp.find(contentChars)) {
- std::string match = filter.RegExp.match(1);
- if (!match.empty()) {
- matches.emplace_back(std::move(match));
- }
- contentChars += filter.RegExp.end();
- }
- }
- }
- if (!matches.empty()) {
- std::string const sourcePath = SubDirPrefix(absFilename);
- for (std::string const& match : matches) {
- // Find the dependency file
- std::string incFile;
- if (this->MocFindIncludedFile(incFile, sourcePath, match)) {
- depends.insert(incFile);
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " +
- cmQtAutoGen::Quoted(absFilename) + "\n " +
- cmQtAutoGen::Quoted(incFile));
- }
- } else {
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename,
- "Could not find dependency file " +
- cmQtAutoGen::Quoted(match));
- }
- }
- }
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::MocParseSourceContent(
- std::string const& absFilename, std::string const& contentText)
- {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
- }
- auto AddJob = [this, &absFilename](std::string const& sourceFile,
- std::string const& includeString,
- std::string const* content) {
- auto job = cm::make_unique<MocJobIncluded>();
- job->SourceFile = sourceFile;
- job->BuildFileRel = this->AutogenIncludeDir;
- job->BuildFileRel += includeString;
- job->Includer = absFilename;
- job->IncludeString = includeString;
- job->DependsValid = (content != nullptr);
- if (job->DependsValid) {
- this->MocFindDepends(sourceFile, *content, job->Depends);
- }
- this->MocJobsIncluded.push_back(std::move(job));
- };
- struct MocInc
- {
- std::string Inc; // full include string
- std::string Dir; // include string directory
- std::string Base; // include string file base
- };
- // Extract moc includes from file
- std::vector<MocInc> mocIncsUsc;
- std::vector<MocInc> mocIncsDot;
- {
- const char* contentChars = contentText.c_str();
- if (strstr(contentChars, "moc") != nullptr) {
- while (this->MocRegExpInclude.find(contentChars)) {
- std::string incString = this->MocRegExpInclude.match(1);
- std::string incDir(SubDirPrefix(incString));
- std::string incBase =
- cmSystemTools::GetFilenameWithoutLastExtension(incString);
- if (cmHasLiteralPrefix(incBase, "moc_")) {
- // moc_<BASE>.cxx
- // Remove the moc_ part from the base name
- mocIncsUsc.push_back(MocInc{ std::move(incString), std::move(incDir),
- incBase.substr(4) });
- } else {
- // <BASE>.moc
- mocIncsDot.push_back(MocInc{ std::move(incString), std::move(incDir),
- std::move(incBase) });
- }
- // Forward content pointer
- contentChars += this->MocRegExpInclude.end();
- }
- }
- }
- std::string selfMacroName;
- const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName);
- // Check if there is anything to do
- if (!selfRequiresMoc && mocIncsUsc.empty() && mocIncsDot.empty()) {
- return true;
- }
- // Scan file variables
- std::string const scanFileDir = SubDirPrefix(absFilename);
- std::string const scanFileBase =
- cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
- // Relaxed mode variables
- bool ownDotMocIncluded = false;
- std::string ownMocUscInclude;
- std::string ownMocUscHeader;
- // Process moc_<BASE>.cxx includes
- for (const MocInc& mocInc : mocIncsUsc) {
- std::string const header =
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (this->MocSkip(header)) {
- continue;
- }
- // Register moc job
- AddJob(header, mocInc.Inc, nullptr);
- // Store meta information for relaxed mode
- if (this->MocRelaxedMode && (mocInc.Base == scanFileBase)) {
- ownMocUscInclude = mocInc.Inc;
- ownMocUscHeader = header;
- }
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but could not find the header ";
- emsg += cmQtAutoGen::Quoted(this->MocStringHeaders(mocInc.Base));
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- // Process <BASE>.moc includes
- for (const MocInc& mocInc : mocIncsDot) {
- const bool ownMoc = (mocInc.Base == scanFileBase);
- if (this->MocRelaxedMode) {
- // Relaxed mode
- if (selfRequiresMoc && ownMoc) {
- // Add self
- AddJob(absFilename, mocInc.Inc, &contentText);
- 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 =
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (this->MocSkip(header)) {
- continue;
- }
- // Register moc job
- AddJob(header, mocInc.Inc, nullptr);
- if (!selfRequiresMoc) {
- if (ownMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += this->MocStringMacros();
- emsg += " macro.\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(header);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for a compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += " instead of ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += ".\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(header);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- }
- }
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file. CMake also could not find a matching "
- "header.";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- } else {
- // Strict mode
- if (ownMoc) {
- // Include self
- AddJob(absFilename, mocInc.Inc, &contentText);
- ownDotMocIncluded = true;
- // Accept but issue a warning if moc isn't required
- if (!selfRequiresMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += this->MocStringMacros();
- emsg += " macro.";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- }
- } else {
- // Don't allow <BASE>.moc include other than self in strict mode
- std::string emsg = "The file includes the moc file ";
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nThis is not supported. Include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += " to run moc on this source file.";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- }
- if (selfRequiresMoc && !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.
- if (this->MocRelaxedMode && !ownMocUscInclude.empty()) {
- // This is for KDE4 compatibility:
- std::string emsg = "The file contains a ";
- emsg += selfMacroName;
- emsg += " macro, but does not include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += ". Instead it includes ";
- emsg += cmQtAutoGen::Quoted(ownMocUscInclude);
- emsg += ".\nRunning moc on\n ";
- emsg += cmQtAutoGen::Quoted(absFilename);
- emsg += "!\nBetter include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
- // Remove own header job
- {
- auto itC = this->MocJobsIncluded.begin();
- auto itE = this->MocJobsIncluded.end();
- for (; itC != itE; ++itC) {
- if ((*itC)->SourceFile == ownMocUscHeader) {
- if ((*itC)->IncludeString == ownMocUscInclude) {
- this->MocJobsIncluded.erase(itC);
- break;
- }
- }
- }
- }
- // Add own source job
- AddJob(absFilename, ownMocUscInclude, &contentText);
- } else {
- // Otherwise always error out since it will not compile:
- std::string emsg = "The file contains a ";
- emsg += selfMacroName;
- emsg += " macro, but does not include ";
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
- emsg += "!\nConsider to\n - add #include \"";
- emsg += scanFileBase;
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
- return false;
- }
- }
- return true;
- }
- void cmQtAutoGeneratorMocUic::MocParseHeaderContent(
- std::string const& absFilename, std::string const& contentText)
- {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
- }
- auto const fit =
- std::find_if(this->MocJobsIncluded.cbegin(), this->MocJobsIncluded.cend(),
- [&absFilename](std::unique_ptr<MocJobIncluded> const& job) {
- return job->SourceFile == absFilename;
- });
- if (fit == this->MocJobsIncluded.cend()) {
- if (this->MocRequired(contentText)) {
- auto job = cm::make_unique<MocJobAuto>();
- job->SourceFile = absFilename;
- {
- std::string& bld = job->BuildFileRel;
- bld = this->FilePathChecksum.getPart(absFilename);
- bld += '/';
- bld += "moc_";
- bld += cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
- bld += this->ConfigSuffix;
- }
- bld += ".cpp";
- }
- this->MocFindDepends(absFilename, contentText, job->Depends);
- this->MocJobsAuto.push_back(std::move(job));
- }
- }
- }
- bool cmQtAutoGeneratorMocUic::MocGenerateAll()
- {
- if (!this->MocEnabled()) {
- return true;
- }
- // Look for name collisions in included moc files
- {
- bool collision = false;
- std::map<std::string, std::vector<MocJobIncluded const*>> collisions;
- for (auto const& job : this->MocJobsIncluded) {
- auto& list = collisions[job->IncludeString];
- if (!list.empty()) {
- collision = true;
- }
- list.push_back(job.get());
- }
- if (collision) {
- std::string emsg =
- "Included moc files with the same name will be "
- "generated from different sources.\n"
- "Consider 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"
- "Include conflicts\n"
- "-----------------\n";
- const auto& colls = collisions;
- for (auto const& coll : colls) {
- if (coll.second.size() > 1) {
- emsg += cmQtAutoGen::Quoted(coll.first);
- emsg += " included in\n";
- for (const MocJobIncluded* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->Includer);
- emsg += "\n";
- }
- emsg += "would be generated from\n";
- for (const MocJobIncluded* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
- emsg += "\n";
- }
- }
- }
- this->LogError(cmQtAutoGen::MOC, emsg);
- return false;
- }
- }
- // (Re)generate moc_predefs.h on demand
- if (!this->MocPredefsCmd.empty()) {
- if (this->MocSettingsChanged ||
- !cmSystemTools::FileExists(this->MocPredefsFileAbs)) {
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel);
- }
- std::string output;
- {
- // Compose command
- std::vector<std::string> cmd = this->MocPredefsCmd;
- // Add includes
- cmd.insert(cmd.end(), this->MocIncludes.begin(),
- this->MocIncludes.end());
- // Add definitions
- for (std::string const& def : this->MocDefinitions) {
- cmd.push_back("-D" + def);
- }
- // Execute command
- if (!this->RunCommand(cmd, output)) {
- this->LogCommandError(cmQtAutoGen::MOC,
- "moc_predefs generation failed", cmd, output);
- return false;
- }
- }
- // (Re)write predefs file only on demand
- if (this->FileDiffers(this->MocPredefsFileAbs, output)) {
- if (this->FileWrite(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
- output)) {
- this->MocPredefsChanged = true;
- } else {
- this->LogFileError(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
- "moc_predefs file writing failed");
- return false;
- }
- } else {
- // Touch to update the time stamp
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC,
- "Touching moc_predefs " + this->MocPredefsFileRel);
- }
- cmSystemTools::Touch(this->MocPredefsFileAbs, false);
- }
- }
- // Add moc_predefs.h to moc file dependencies
- for (auto const& item : this->MocJobsIncluded) {
- item->Depends.insert(this->MocPredefsFileAbs);
- }
- for (auto const& item : this->MocJobsAuto) {
- item->Depends.insert(this->MocPredefsFileAbs);
- }
- }
- // Generate moc files that are included by source files.
- for (auto const& item : this->MocJobsIncluded) {
- if (!this->MocGenerateFile(*item)) {
- return false;
- }
- }
- // Generate moc files that are _not_ included by source files.
- bool autoNameGenerated = false;
- for (auto const& item : this->MocJobsAuto) {
- if (!this->MocGenerateFile(*item, &autoNameGenerated)) {
- return false;
- }
- }
- // Compose mocs compilation file content
- {
- std::string mocs =
- "// This file is autogenerated. Changes will be overwritten.\n";
- if (this->MocJobsAuto.empty()) {
- // Placeholder content
- mocs +=
- "// No files found that require moc or the moc files are included\n";
- mocs += "enum some_compilers { need_more_than_nothing };\n";
- } else {
- // Valid content
- for (const auto& item : this->MocJobsAuto) {
- mocs += "#include \"";
- mocs += item->BuildFileRel;
- mocs += "\"\n";
- }
- }
- if (this->FileDiffers(this->MocCompFileAbs, mocs)) {
- // Actually write mocs compilation file
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC compilation " + this->MocCompFileRel);
- }
- if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) {
- this->LogFileError(cmQtAutoGen::MOC, this->MocCompFileAbs,
- "mocs compilation file writing failed");
- return false;
- }
- } else if (autoNameGenerated) {
- // Only touch mocs compilation file
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::MOC,
- "Touching mocs compilation " + this->MocCompFileRel);
- }
- cmSystemTools::Touch(this->MocCompFileAbs, false);
- }
- }
- return true;
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::MocGenerateFile(const MocJobAuto& mocJob,
- bool* generated)
- {
- bool success = true;
- std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, mocJob.BuildFileRel);
- bool generate = false;
- std::string generateReason;
- if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from its source file ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because it doesn't exist";
- }
- generate = true;
- }
- if (!generate && this->MocSettingsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because the MOC settings changed";
- }
- generate = true;
- }
- if (!generate && this->MocPredefsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because moc_predefs.h changed";
- }
- generate = true;
- }
- if (!generate) {
- std::string error;
- if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " because it's older than its source file ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- }
- generate = true;
- } else {
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::MOC, error);
- success = false;
- }
- }
- }
- if (success && !generate) {
- // Test if a dependency file is newer
- std::string error;
- for (std::string const& depFile : mocJob.Depends) {
- if (FileIsOlderThan(mocFileAbs, depFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
- generateReason += " because it is older than ";
- generateReason += cmQtAutoGen::Quoted(depFile);
- }
- generate = true;
- break;
- }
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::MOC, error);
- success = false;
- break;
- }
- }
- }
- if (generate) {
- // Log
- if (this->GetVerbose()) {
- this->LogBold("Generating MOC source " + mocJob.BuildFileRel);
- this->LogInfo(cmQtAutoGen::MOC, generateReason);
- }
- // Make sure the parent directory exists
- if (this->MakeParentDirectory(cmQtAutoGen::MOC, mocFileAbs)) {
- // Compose moc command
- std::vector<std::string> cmd;
- cmd.push_back(this->MocExecutable);
- // Add options
- cmd.insert(cmd.end(), this->MocAllOptions.begin(),
- this->MocAllOptions.end());
- // Add predefs include
- if (!this->MocPredefsFileAbs.empty()) {
- cmd.push_back("--include");
- cmd.push_back(this->MocPredefsFileAbs);
- }
- cmd.push_back("-o");
- cmd.push_back(mocFileAbs);
- cmd.push_back(mocJob.SourceFile);
- // Execute moc command
- std::string output;
- if (this->RunCommand(cmd, output)) {
- // Success
- if (generated != nullptr) {
- *generated = true;
- }
- } else {
- // Moc command failed
- {
- std::string emsg = "moc failed for\n ";
- emsg += cmQtAutoGen::Quoted(mocJob.SourceFile);
- this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output);
- }
- cmSystemTools::RemoveFile(mocFileAbs);
- success = false;
- }
- } else {
- // Parent directory creation failed
- success = false;
- }
- }
- return success;
- }
- /**
- * @brief Tests if the file name is in the skip list
- */
- bool cmQtAutoGeneratorMocUic::UicSkip(std::string const& absFilename) const
- {
- if (this->UicEnabled()) {
- // Test if the file name is on the skip list
- if (!ListContains(this->UicSkipList, absFilename)) {
- return false;
- }
- }
- return true;
- }
- bool cmQtAutoGeneratorMocUic::UicParseContent(std::string const& absFilename,
- std::string const& contentText)
- {
- if (this->GetVerbose()) {
- this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename);
- }
- std::vector<std::string> includes;
- // Extracte includes
- {
- const char* contentChars = contentText.c_str();
- if (strstr(contentChars, "ui_") != nullptr) {
- while (this->UicRegExpInclude.find(contentChars)) {
- includes.push_back(this->UicRegExpInclude.match(1));
- contentChars += this->UicRegExpInclude.end();
- }
- }
- }
- for (std::string const& includeString : includes) {
- std::string uiInputFile;
- if (!UicFindIncludedFile(uiInputFile, absFilename, includeString)) {
- return false;
- }
- // Check if this file should be skipped
- if (this->UicSkip(uiInputFile)) {
- continue;
- }
- // Check if the job already exists
- bool jobExists = false;
- for (const auto& job : this->UicJobs) {
- if ((job->SourceFile == uiInputFile) &&
- (job->IncludeString == includeString)) {
- jobExists = true;
- break;
- }
- }
- if (!jobExists) {
- auto job = cm::make_unique<UicJob>();
- job->SourceFile = uiInputFile;
- job->BuildFileRel = this->AutogenIncludeDir;
- job->BuildFileRel += includeString;
- job->Includer = absFilename;
- job->IncludeString = includeString;
- this->UicJobs.push_back(std::move(job));
- }
- }
- return true;
- }
- bool cmQtAutoGeneratorMocUic::UicFindIncludedFile(
- std::string& absFile, std::string const& sourceFile,
- std::string const& includeString)
- {
- bool success = false;
- std::string searchFile =
- cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3);
- searchFile += ".ui";
- // Collect search paths list
- std::vector<std::string> testFiles;
- {
- std::string const searchPath = SubDirPrefix(includeString);
- std::string searchFileFull;
- if (!searchPath.empty()) {
- searchFileFull = searchPath;
- searchFileFull += searchFile;
- }
- // Vicinity of the source
- {
- std::string const sourcePath = SubDirPrefix(sourceFile);
- testFiles.push_back(sourcePath + searchFile);
- if (!searchPath.empty()) {
- testFiles.push_back(sourcePath + searchFileFull);
- }
- }
- // AUTOUIC search paths
- if (!this->UicSearchPaths.empty()) {
- for (std::string const& sPath : this->UicSearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFile));
- }
- if (!searchPath.empty()) {
- for (std::string const& sPath : this->UicSearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFileFull));
- }
- }
- }
- }
- // Search for the .ui file!
- for (std::string const& testFile : testFiles) {
- if (cmSystemTools::FileExists(testFile.c_str())) {
- absFile = cmSystemTools::GetRealPath(testFile);
- success = true;
- break;
- }
- }
- // Log error
- if (!success) {
- std::string emsg = "Could not find ";
- emsg += cmQtAutoGen::Quoted(searchFile);
- emsg += " in\n";
- for (std::string const& testFile : testFiles) {
- emsg += " ";
- emsg += cmQtAutoGen::Quoted(testFile);
- emsg += "\n";
- }
- this->LogFileError(cmQtAutoGen::UIC, sourceFile, emsg);
- }
- return success;
- }
- bool cmQtAutoGeneratorMocUic::UicGenerateAll()
- {
- if (!this->UicEnabled()) {
- return true;
- }
- // Look for name collisions in included uic files
- {
- bool collision = false;
- std::map<std::string, std::vector<UicJob const*>> collisions;
- for (auto const& job : this->UicJobs) {
- auto& list = collisions[job->IncludeString];
- if (!list.empty()) {
- collision = true;
- }
- list.push_back(job.get());
- }
- if (collision) {
- std::string emsg =
- "Included uic files with the same name will be "
- "generated from different sources.\n"
- "Consider 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"
- "Include conflicts\n"
- "-----------------\n";
- const auto& colls = collisions;
- for (auto const& coll : colls) {
- if (coll.second.size() > 1) {
- emsg += cmQtAutoGen::Quoted(coll.first);
- emsg += " included in\n";
- for (const UicJob* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->Includer);
- emsg += "\n";
- }
- emsg += "would be generated from\n";
- for (const UicJob* job : coll.second) {
- emsg += " - ";
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
- emsg += "\n";
- }
- }
- }
- this->LogError(cmQtAutoGen::UIC, emsg);
- return false;
- }
- }
- // Generate ui header files
- for (const auto& item : this->UicJobs) {
- if (!this->UicGenerateFile(*item)) {
- return false;
- }
- }
- return true;
- }
- /**
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::UicGenerateFile(const UicJob& uicJob)
- {
- bool success = true;
- std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath(
- this->AutogenBuildDir, uicJob.BuildFileRel);
- bool generate = false;
- std::string generateReason;
- if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " from its source file ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- generateReason += " because it doesn't exist";
- }
- generate = true;
- }
- if (!generate && this->UicSettingsChanged) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " from ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- generateReason += " because the UIC settings changed";
- }
- generate = true;
- }
- if (!generate) {
- std::string error;
- if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) {
- if (this->GetVerbose()) {
- generateReason = "Generating ";
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
- generateReason += " because it's older than its source file ";
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
- }
- generate = true;
- } else {
- if (!error.empty()) {
- this->LogError(cmQtAutoGen::UIC, error);
- success = false;
- }
- }
- }
- if (generate) {
- // Log
- if (this->GetVerbose()) {
- this->LogBold("Generating UIC header " + uicJob.BuildFileRel);
- this->LogInfo(cmQtAutoGen::UIC, generateReason);
- }
- // Make sure the parent directory exists
- if (this->MakeParentDirectory(cmQtAutoGen::UIC, uicFileAbs)) {
- // Compose uic command
- std::vector<std::string> cmd;
- cmd.push_back(this->UicExecutable);
- {
- std::vector<std::string> allOpts = this->UicTargetOptions;
- auto optionIt = this->UicOptions.find(uicJob.SourceFile);
- if (optionIt != this->UicOptions.end()) {
- cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second,
- (this->QtVersionMajor == 5));
- }
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
- }
- cmd.push_back("-o");
- cmd.push_back(uicFileAbs);
- cmd.push_back(uicJob.SourceFile);
- std::string output;
- if (this->RunCommand(cmd, output)) {
- // Success
- } else {
- // Command failed
- {
- std::string emsg = "uic failed for\n ";
- emsg += cmQtAutoGen::Quoted(uicJob.SourceFile);
- emsg += "\nincluded by\n ";
- emsg += cmQtAutoGen::Quoted(uicJob.Includer);
- this->LogCommandError(cmQtAutoGen::UIC, emsg, cmd, output);
- }
- cmSystemTools::RemoveFile(uicFileAbs);
- success = false;
- }
- } else {
- // Parent directory creation failed
- success = false;
- }
- }
- return success;
- }
- /**
- * @brief Tries to find the header file to the given file base path by
- * appending different header extensions
- * @return True on success
- */
- bool cmQtAutoGeneratorMocUic::FindHeader(std::string& header,
- std::string const& testBasePath) const
- {
- for (std::string const& ext : this->HeaderExtensions) {
- std::string testFilePath(testBasePath);
- testFilePath.push_back('.');
- testFilePath += ext;
- if (cmSystemTools::FileExists(testFilePath.c_str())) {
- header = testFilePath;
- return true;
- }
- }
- return false;
- }
|