blob: 81546cc1891e13a55bd1313d6f7c36191cf8597e [file] [log] [blame]
/* 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 <atomic>
#include <cstddef>
#include <map>
#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
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<IncludeKeyT> Underscore;
std::vector<IncludeKeyT> Dot;
} Include;
std::vector<std::string> Depends;
} Moc;
struct UicT
{
std::vector<IncludeKeyT> Include;
std::vector<std::string> Depends;
} Uic;
};
typedef std::shared_ptr<FileT> FileHandleT;
typedef std::pair<FileHandleT, bool> 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<std::string, FileHandleT> 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<SourceFileT> SourceFileHandleT;
typedef std::map<std::string, SourceFileHandleT> SourceFileMapT;
/**
* Meta compiler file mapping information
*/
struct MappingT
{
SourceFileHandleT SourceFile;
std::string OutputFile;
std::string IncludeString;
std::vector<SourceFileHandleT> IncluderFiles;
};
typedef std::shared_ptr<MappingT> MappingHandleT;
typedef std::map<std::string, MappingHandleT> 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<std::string> 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<std::string> SkipList;
std::vector<std::string> IncludePaths;
std::vector<std::string> Includes;
std::vector<std::string> Definitions;
std::vector<std::string> Options;
std::vector<std::string> AllOptions;
std::vector<std::string> PredefsCmd;
std::vector<KeyExpT> DependFilters;
std::vector<KeyExpT> 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<std::string> 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<std::string> SkipList;
std::vector<std::string> TargetOptions;
std::map<std::string, std::vector<std::string>> Options;
std::vector<std::string> 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<cmQtAutoMocUic*>(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<std::string> 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<std::string> 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<IncludeKeyT>& container,
std::set<std::string> 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 const& 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<std::string, cmFileTime> 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<std::string> reason)
: Mapping(std::move(uicMapping))
, Reason(std::move(reason))
{
}
protected:
MappingHandleT Mapping;
std::unique_ptr<std::string> 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 <class JOBTYPE>
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<bool> JobError_ = ATOMIC_VAR_INIT(false);
cmWorkerPool WorkerPool_;
};
#endif