/* 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 "cmsys/RegularExpression.hxx" #include #include #include #include // IWYU pragma: keep #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; }; typedef std::shared_ptr FileHandleT; typedef std::pair GetOrInsertT; 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 Moc = false; bool Uic = false; }; typedef std::shared_ptr SourceFileHandleT; typedef std::map SourceFileMapT; /** * Meta compiler file mapping information */ struct MappingT { SourceFileHandleT SourceFile; std::string OutputFile; std::string IncludeString; std::vector IncluderFiles; }; typedef std::shared_ptr MappingHandleT; typedef std::map MappingMapT; /** * Common settings */ class BaseSettingsT { public: // -- Constructors BaseSettingsT(); ~BaseSettingsT(); BaseSettingsT(BaseSettingsT const&) = delete; BaseSettingsT& operator=(BaseSettingsT const&) = delete; // -- Attributes // - Config bool MultiConfig = false; bool IncludeProjectDirsBefore = false; unsigned int QtVersionMajor = 4; // - Directories std::string ProjectSourceDir; std::string ProjectBinaryDir; std::string CurrentSourceDir; std::string CurrentBinaryDir; 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; cmFileTime ExecutableTime; std::string Executable; std::string CompFileAbs; std::string PredefsFileRel; std::string PredefsFileAbs; std::unordered_set SkipList; std::vector IncludePaths; std::vector Includes; std::vector Definitions; std::vector Options; std::vector AllOptions; 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; // -- 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: SourceFileMapT UiFiles; MappingMapT Includes; }; /** * Abstract job class for concurrent job processing */ class JobT : public cmWorkerPool::JobT { protected: /** * @brief 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(); } // -- Error logging with automatic abort void LogError(GenT genType, std::string const& message) const; void LogFileError(GenT genType, std::string const& filename, std::string const& message) const; void LogCommandError(GenT genType, std::string const& 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 parsed files */ class JobEvaluateT : public JobFenceT { void Process() override; // -- Moc bool MocEvalHeader(SourceFileHandleT source); bool MocEvalSource(SourceFileHandleT const& source); SourceFileHandleT MocFindIncludedHeader( std::string const& includerDir, std::string const& includeBase) const; SourceFileHandleT MocFindHeader(std::string const& basePath) const; std::string MocMessageTestHeaders(std::string const& fileBase) const; bool MocRegisterIncluded(std::string const& includeString, SourceFileHandleT includerFileHandle, SourceFileHandleT sourceFileHandle, bool sourceIsHeader) const; void MocRegisterMapping(MappingHandleT mappingHandle, bool sourceIsHeader) const; // -- Uic bool UicEval(SourceFileMapT const& fileMap); bool UicEvalFile(SourceFileHandleT sourceFileHandle); SourceFileHandleT UicFindIncludedUi(std::string const& sourceFile, std::string const& sourceDir, IncludeKeyT const& incKey) const; bool UicRegisterMapping(std::string const& includeString, SourceFileHandleT uiFileHandle, SourceFileHandleT includerFileHandle); }; /** * Generates moc/uic jobs */ class JobGenerateT : public JobFenceT { void Process() override; // -- Moc bool MocGenerate(MappingHandleT const& mapping, bool compFile) const; bool MocUpdate(MappingT const& mapping, std::string* reason) const; std::pair MocFindDependency( std::string const& sourceDir, std::string const& includeString) const; // -- Uic bool UicGenerate(MappingHandleT const& mapping) const; bool UicUpdate(MappingT const& mapping, std::string* reason) const; }; /** * File compiling 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 JobMocT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; /** * uic compiles a file */ class JobUicT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; /// @brief 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(std::string const& relativePath) const; std::string AbsoluteIncludePath(std::string const& relativePath) const; template void CreateParseJobs(SourceFileMapT const& sourceMap); 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_; }; #endif