/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #ifndef cmQtAutoMocUic_h #define cmQtAutoMocUic_h #include "cmConfigure.h" // IWYU pragma: keep #include "cmFileTime.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" #include "cmWorkerPool.h" #include "cm_string_view.hxx" #include "cmsys/RegularExpression.hxx" #include #include #include #include #include #include #include #include #include #include #include class cmMakefile; /** \class cmQtAutoMocUic * \brief AUTOMOC and AUTOUIC generator */ class cmQtAutoMocUic : public cmQtAutoGenerator { public: cmQtAutoMocUic(); ~cmQtAutoMocUic() override; cmQtAutoMocUic(cmQtAutoMocUic const&) = delete; cmQtAutoMocUic& operator=(cmQtAutoMocUic const&) = delete; public: // -- Types /** Search key plus regular expression pair. */ struct KeyExpT { KeyExpT() = default; KeyExpT(const char* key, const char* exp) : Key(key) , Exp(exp) { } KeyExpT(std::string key, std::string const& exp) : Key(std::move(key)) , Exp(exp) { } std::string Key; cmsys::RegularExpression Exp; }; /** Include string with sub parts. */ struct IncludeKeyT { IncludeKeyT(std::string const& key, std::size_t basePrefixLength); std::string Key; // Full include string std::string Dir; // Include directory std::string Base; // Base part of the include file name }; /** Source file parsing cache. */ class ParseCacheT { public: // -- Types /** * Entry of the file parsing cache */ struct FileT { void Clear(); struct MocT { std::string Macro; struct IncludeT { std::vector Underscore; std::vector Dot; } Include; std::vector Depends; } Moc; struct UicT { std::vector Include; std::vector Depends; } Uic; }; using FileHandleT = std::shared_ptr; using GetOrInsertT = std::pair; public: ParseCacheT(); ~ParseCacheT(); void Clear(); bool ReadFromFile(std::string const& fileName); bool WriteToFile(std::string const& fileName); //! Might return an invalid handle FileHandleT Get(std::string const& fileName) const; //! Always returns a valid handle GetOrInsertT GetOrInsert(std::string const& fileName); private: std::unordered_map Map_; }; /** Source file data. */ class SourceFileT { public: SourceFileT(std::string fileName) : FileName(std::move(fileName)) { } public: std::string FileName; cmFileTime FileTime; ParseCacheT::FileHandleT ParseData; std::string BuildPath; bool IsHeader = false; bool Moc = false; bool Uic = false; }; using SourceFileHandleT = std::shared_ptr; using SourceFileMapT = std::map; /** Meta compiler file mapping information. */ struct MappingT { SourceFileHandleT SourceFile; std::string OutputFile; std::string IncludeString; std::vector IncluderFiles; }; using MappingHandleT = std::shared_ptr; using MappingMapT = std::map; /** Common settings. */ class BaseSettingsT { public: // -- Constructors BaseSettingsT(); ~BaseSettingsT(); BaseSettingsT(BaseSettingsT const&) = delete; BaseSettingsT& operator=(BaseSettingsT const&) = delete; // -- Attributes // - Config bool MultiConfig = false; unsigned int QtVersionMajor = 4; // - Directories std::string AutogenBuildDir; std::string AutogenIncludeDir; // - Files std::string CMakeExecutable; cmFileTime CMakeExecutableTime; std::string ParseCacheFile; std::vector HeaderExtensions; }; /** Shared common variables. */ class BaseEvalT { public: // -- Parse Cache bool ParseCacheChanged = false; cmFileTime ParseCacheTime; ParseCacheT ParseCache; // -- Sources SourceFileMapT Headers; SourceFileMapT Sources; }; /** Moc settings. */ class MocSettingsT { public: // -- Constructors MocSettingsT(); ~MocSettingsT(); MocSettingsT(MocSettingsT const&) = delete; MocSettingsT& operator=(MocSettingsT const&) = delete; // -- Const methods bool skipped(std::string const& fileName) const; std::string MacrosString() const; // -- Attributes bool Enabled = false; bool SettingsChanged = false; bool RelaxedMode = false; bool PathPrefix = false; cmFileTime ExecutableTime; std::string Executable; std::string CompFileAbs; std::string PredefsFileAbs; std::unordered_set SkipList; std::vector IncludePaths; std::vector Definitions; std::vector OptionsIncludes; std::vector OptionsDefinitions; std::vector OptionsExtra; std::vector PredefsCmd; std::vector DependFilters; std::vector MacroFilters; cmsys::RegularExpression RegExpInclude; }; /** Moc shared variables. */ class MocEvalT { public: // -- predefines file cmFileTime PredefsTime; // -- Mappings MappingMapT HeaderMappings; MappingMapT SourceMappings; MappingMapT Includes; // -- Discovered files SourceFileMapT HeadersDiscovered; // -- Output directories std::unordered_set OutputDirs; // -- Mocs compilation bool CompUpdated = false; std::vector CompFiles; }; /** Uic settings. */ class UicSettingsT { public: UicSettingsT(); ~UicSettingsT(); UicSettingsT(UicSettingsT const&) = delete; UicSettingsT& operator=(UicSettingsT const&) = delete; // -- Const methods bool skipped(std::string const& fileName) const; // -- Attributes bool Enabled = false; bool SettingsChanged = false; cmFileTime ExecutableTime; std::string Executable; std::unordered_set SkipList; std::vector TargetOptions; std::map> Options; std::vector SearchPaths; cmsys::RegularExpression RegExpInclude; }; /** Uic shared variables. */ class UicEvalT { public: // -- Discovered files SourceFileMapT UiFiles; // -- Mappings MappingMapT Includes; // -- Output directories std::unordered_set OutputDirs; }; /** Abstract job class for concurrent job processing. */ class JobT : public cmWorkerPool::JobT { protected: /** Protected default constructor. */ JobT(bool fence = false) : cmWorkerPool::JobT(fence) { } //! Get the generator. Only valid during Process() call! cmQtAutoMocUic* Gen() const { return static_cast(UserData()); }; // -- Accessors. Only valid during Process() call! Logger const& Log() const { return Gen()->Log(); } BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); } BaseEvalT& BaseEval() const { return Gen()->BaseEval(); } MocSettingsT const& MocConst() const { return Gen()->MocConst(); } MocEvalT& MocEval() const { return Gen()->MocEval(); } UicSettingsT const& UicConst() const { return Gen()->UicConst(); } UicEvalT& UicEval() const { return Gen()->UicEval(); } // -- Logging std::string MessagePath(cm::string_view path) const { return Gen()->MessagePath(path); } // - Error logging with automatic abort void LogError(GenT genType, cm::string_view message) const; void LogCommandError(GenT genType, cm::string_view message, std::vector const& command, std::string const& output) const; /** @brief Run an external process. Use only during Process() call! */ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector const& command, std::string* infoMessage = nullptr); }; /** Fence job utility class. */ class JobFenceT : public JobT { public: JobFenceT() : JobT(true) { } void Process() override{}; }; /** Generate moc_predefs.h. */ class JobMocPredefsT : public JobFenceT { void Process() override; bool Update(std::string* reason) const; }; /** File parse job base class. */ class JobParseT : public JobT { public: JobParseT(SourceFileHandleT fileHandle) : FileHandle(std::move(fileHandle)) { } protected: bool ReadFile(); void CreateKeys(std::vector& container, std::set const& source, std::size_t basePrefixLength); void MocMacro(); void MocDependecies(); void MocIncludes(); void UicIncludes(); protected: SourceFileHandleT FileHandle; std::string Content; }; /** Header file parse job. */ class JobParseHeaderT : public JobParseT { public: using JobParseT::JobParseT; void Process() override; }; /** Source file parse job. */ class JobParseSourceT : public JobParseT { public: using JobParseT::JobParseT; void Process() override; }; /** Evaluate cached file parse data - moc. */ class JobEvalCacheT : public JobT { protected: std::string MessageSearchLocations() const; std::vector SearchLocations; }; /** Evaluate cached file parse data - moc. */ class JobEvalCacheMocT : public JobEvalCacheT { void Process() override; bool EvalHeader(SourceFileHandleT source); bool EvalSource(SourceFileHandleT const& source); bool FindIncludedHeader(SourceFileHandleT& headerHandle, cm::string_view includerDir, cm::string_view includeBase); bool RegisterIncluded(std::string const& includeString, SourceFileHandleT includerFileHandle, SourceFileHandleT sourceFileHandle) const; void RegisterMapping(MappingHandleT mappingHandle) const; std::string MessageHeader(cm::string_view headerBase) const; }; /** Evaluate cached file parse data - uic. */ class JobEvalCacheUicT : public JobEvalCacheT { void Process() override; bool EvalFile(SourceFileHandleT const& sourceFileHandle); bool FindIncludedUi(cm::string_view sourceDirPrefix, cm::string_view includePrefix); bool RegisterMapping(std::string const& includeString, SourceFileHandleT includerFileHandle); std::string UiName; SourceFileHandleT UiFileHandle; }; /** Evaluate cached file parse data - finish */ class JobEvalCacheFinishT : public JobFenceT { void Process() override; }; /** Dependency probing base job. */ class JobProbeDepsT : public JobT { }; /** Probes file dependencies and generates moc compile jobs. */ class JobProbeDepsMocT : public JobProbeDepsT { void Process() override; bool Generate(MappingHandleT const& mapping, bool compFile) const; bool Probe(MappingT const& mapping, std::string* reason) const; std::pair FindDependency( std::string const& sourceDir, std::string const& includeString) const; }; /** Probes file dependencies and generates uic compile jobs. */ class JobProbeDepsUicT : public JobProbeDepsT { void Process() override; bool Probe(MappingT const& mapping, std::string* reason) const; }; /** Dependency probing finish job. */ class JobProbeDepsFinishT : public JobFenceT { void Process() override; }; /** Meta compiler base job. */ class JobCompileT : public JobT { public: JobCompileT(MappingHandleT uicMapping, std::unique_ptr reason) : Mapping(std::move(uicMapping)) , Reason(std::move(reason)) { } protected: MappingHandleT Mapping; std::unique_ptr Reason; }; /** moc compiles a file. */ class JobCompileMocT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; /** uic compiles a file. */ class JobCompileUicT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; /** Generate mocs_compilation.cpp. */ class JobMocsCompilationT : public JobFenceT { private: void Process() override; }; /** @brief The last job. */ class JobFinishT : public JobFenceT { private: void Process() override; }; // -- Const settings interface BaseSettingsT const& BaseConst() const { return this->BaseConst_; } BaseEvalT& BaseEval() { return this->BaseEval_; } MocSettingsT const& MocConst() const { return this->MocConst_; } MocEvalT& MocEval() { return this->MocEval_; } UicSettingsT const& UicConst() const { return this->UicConst_; } UicEvalT& UicEval() { return this->UicEval_; } // -- Parallel job processing interface cmWorkerPool& WorkerPool() { return WorkerPool_; } void AbortError() { Abort(true); } void AbortSuccess() { Abort(false); } // -- Utility std::string AbsoluteBuildPath(cm::string_view relativePath) const; std::string AbsoluteIncludePath(cm::string_view relativePath) const; template void CreateParseJobs(SourceFileMapT const& sourceMap); std::string CollapseFullPathTS(std::string const& path) const; private: // -- Utility accessors Logger const& Log() const { return Logger_; } // -- Abstract processing interface bool Init(cmMakefile* makefile) override; void InitJobs(); bool Process() override; // -- Settings file void SettingsFileRead(); bool SettingsFileWrite(); // -- Parse cache void ParseCacheRead(); bool ParseCacheWrite(); // -- Thread processing void Abort(bool error); // -- Generation bool CreateDirectories(); private: // -- Utility Logger Logger_; // -- Settings BaseSettingsT BaseConst_; BaseEvalT BaseEval_; MocSettingsT MocConst_; MocEvalT MocEval_; UicSettingsT UicConst_; UicEvalT UicEval_; // -- Settings file std::string SettingsFile_; std::string SettingsStringMoc_; std::string SettingsStringUic_; // -- Worker thread pool std::atomic JobError_ = ATOMIC_VAR_INIT(false); cmWorkerPool WorkerPool_; // -- Concurrent processing mutable std::mutex CMakeLibMutex_; }; #endif