blob: 222695411122af76c02cf1552492ae70921d7ddb [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 cmQtAutoGeneratorMocUic_h
#define cmQtAutoGeneratorMocUic_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
#include "cmUVHandlePtr.h"
#include "cm_uv.h"
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <condition_variable>
#include <cstddef>
#include <deque>
#include <map>
#include <memory> // IWYU pragma: keep
#include <mutex>
#include <set>
#include <string>
#include <thread>
#include <vector>
class cmMakefile;
// @brief AUTOMOC and AUTOUIC generator
class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator
{
CM_DISABLE_COPY(cmQtAutoGeneratorMocUic)
public:
cmQtAutoGeneratorMocUic();
~cmQtAutoGeneratorMocUic() override;
public:
// -- Types
class WorkerT;
/// @brief Search key plus regular expression pair
///
struct KeyExpT
{
KeyExpT() = default;
KeyExpT(const char* key, const char* exp)
: Key(key)
, Exp(exp)
{
}
KeyExpT(std::string const& key, std::string const& exp)
: Key(key)
, Exp(exp)
{
}
std::string Key;
cmsys::RegularExpression Exp;
};
/// @brief Common settings
///
class BaseSettingsT
{
CM_DISABLE_COPY(BaseSettingsT)
public:
// -- Volatile methods
BaseSettingsT(FileSystem* fileSystem)
: MultiConfig(false)
, IncludeProjectDirsBefore(false)
, QtVersionMajor(4)
, NumThreads(1)
, FileSys(fileSystem)
{
}
// -- Const methods
std::string AbsoluteBuildPath(std::string const& relativePath) const;
bool FindHeader(std::string& header,
std::string const& testBasePath) const;
// -- Attributes
// - Config
bool MultiConfig;
bool IncludeProjectDirsBefore;
unsigned int QtVersionMajor;
unsigned int NumThreads;
// - Directories
std::string ProjectSourceDir;
std::string ProjectBinaryDir;
std::string CurrentSourceDir;
std::string CurrentBinaryDir;
std::string AutogenBuildDir;
std::string AutogenIncludeDir;
// - Files
std::vector<std::string> HeaderExtensions;
// - File system
FileSystem* FileSys;
};
/// @brief Moc settings
///
class MocSettingsT
{
CM_DISABLE_COPY(MocSettingsT)
public:
MocSettingsT(FileSystem* fileSys)
: FileSys(fileSys)
{
}
// -- Const methods
bool skipped(std::string const& fileName) const;
std::string FindMacro(std::string const& content) const;
std::string MacrosString() const;
std::string FindIncludedFile(std::string const& sourcePath,
std::string const& includeString) const;
void FindDependencies(std::string const& content,
std::set<std::string>& depends) const;
// -- Attributes
bool Enabled = false;
bool SettingsChanged = false;
bool RelaxedMode = false;
std::string Executable;
std::string CompFileAbs;
std::string PredefsFileRel;
std::string PredefsFileAbs;
std::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;
// - File system
FileSystem* FileSys;
};
/// @brief Uic settings
///
class UicSettingsT
{
CM_DISABLE_COPY(UicSettingsT)
public:
UicSettingsT() = default;
// -- Const methods
bool skipped(std::string const& fileName) const;
// -- Attributes
bool Enabled = false;
bool SettingsChanged = false;
std::string Executable;
std::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;
};
/// @brief Abstract job class for threaded processing
///
class JobT
{
CM_DISABLE_COPY(JobT)
public:
JobT() = default;
virtual ~JobT() = default;
// -- Abstract processing interface
virtual void Process(WorkerT& wrk) = 0;
};
/// @brief Deleter for classes derived from Job
///
struct JobDeleterT
{
void operator()(JobT* job);
};
// Job management types
typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT;
typedef std::deque<JobHandleT> JobQueueT;
/// @brief Parse source job
///
class JobParseT : public JobT
{
public:
JobParseT(std::string&& fileName, bool moc, bool uic, bool header = false)
: FileName(std::move(fileName))
, AutoMoc(moc)
, AutoUic(uic)
, Header(header)
{
}
private:
struct MetaT
{
std::string Content;
std::string FileDir;
std::string FileBase;
};
void Process(WorkerT& wrk) override;
bool ParseMocSource(WorkerT& wrk, MetaT const& meta);
bool ParseMocHeader(WorkerT& wrk, MetaT const& meta);
std::string MocStringHeaders(WorkerT& wrk,
std::string const& fileBase) const;
std::string MocFindIncludedHeader(WorkerT& wrk,
std::string const& includerDir,
std::string const& includeBase);
bool ParseUic(WorkerT& wrk, MetaT const& meta);
bool ParseUicInclude(WorkerT& wrk, MetaT const& meta,
std::string&& includeString);
std::string UicFindIncludedFile(WorkerT& wrk, MetaT const& meta,
std::string const& includeString);
private:
std::string FileName;
bool AutoMoc = false;
bool AutoUic = false;
bool Header = false;
};
/// @brief Generate moc_predefs
///
class JobMocPredefsT : public JobT
{
private:
void Process(WorkerT& wrk) override;
};
/// @brief Moc a file job
///
class JobMocT : public JobT
{
public:
JobMocT(std::string&& sourceFile, std::string const& includerFile,
std::string&& includeString)
: SourceFile(std::move(sourceFile))
, IncluderFile(includerFile)
, IncludeString(std::move(includeString))
{
}
void FindDependencies(WorkerT& wrk, std::string const& content);
private:
void Process(WorkerT& wrk) override;
bool UpdateRequired(WorkerT& wrk);
void GenerateMoc(WorkerT& wrk);
public:
std::string SourceFile;
std::string IncluderFile;
std::string IncludeString;
std::string BuildFile;
bool DependsValid = false;
std::set<std::string> Depends;
};
/// @brief Uic a file job
///
class JobUicT : public JobT
{
public:
JobUicT(std::string&& sourceFile, std::string const& includerFile,
std::string&& includeString)
: SourceFile(std::move(sourceFile))
, IncluderFile(includerFile)
, IncludeString(std::move(includeString))
{
}
private:
void Process(WorkerT& wrk) override;
bool UpdateRequired(WorkerT& wrk);
void GenerateUic(WorkerT& wrk);
public:
std::string SourceFile;
std::string IncluderFile;
std::string IncludeString;
std::string BuildFile;
};
/// @brief Worker Thread
///
class WorkerT
{
CM_DISABLE_COPY(WorkerT)
public:
WorkerT(cmQtAutoGeneratorMocUic* gen, uv_loop_t* uvLoop);
~WorkerT();
// -- Const accessors
cmQtAutoGeneratorMocUic& Gen() const { return *Gen_; }
Logger& Log() const { return Gen_->Log(); }
FileSystem& FileSys() const { return Gen_->FileSys(); }
const BaseSettingsT& Base() const { return Gen_->Base(); }
const MocSettingsT& Moc() const { return Gen_->Moc(); }
const UicSettingsT& Uic() const { return Gen_->Uic(); }
// -- Log info
void LogInfo(GeneratorT genType, std::string const& message) const;
// -- Log warning
void LogWarning(GeneratorT genType, std::string const& message) const;
void LogFileWarning(GeneratorT genType, std::string const& filename,
std::string const& message) const;
// -- Log error
void LogError(GeneratorT genType, std::string const& message) const;
void LogFileError(GeneratorT genType, std::string const& filename,
std::string const& message) const;
void LogCommandError(GeneratorT genType, std::string const& message,
std::vector<std::string> const& command,
std::string const& output) const;
// -- External processes
/// @brief Verbose logging version
bool RunProcess(GeneratorT genType, ProcessResultT& result,
std::vector<std::string> const& command);
private:
/// @brief Thread main loop
void Loop();
// -- Libuv callbacks
static void UVProcessStart(uv_async_t* handle);
void UVProcessFinished();
private:
// -- Generator
cmQtAutoGeneratorMocUic* Gen_;
// -- Job handle
JobHandleT JobHandle_;
// -- Process management
std::mutex ProcessMutex_;
cm::uv_async_ptr ProcessRequest_;
std::condition_variable ProcessCondition_;
std::unique_ptr<ReadOnlyProcessT> Process_;
// -- System thread
std::thread Thread_;
};
/// @brief Processing stage
enum class StageT
{
SETTINGS_READ,
CREATE_DIRECTORIES,
PARSE_SOURCES,
PARSE_HEADERS,
MOC_PREDEFS,
MOC_PROCESS,
MOCS_COMPILATION,
UIC_PROCESS,
SETTINGS_WRITE,
FINISH,
END
};
// -- Const settings interface
const BaseSettingsT& Base() const { return this->Base_; }
const MocSettingsT& Moc() const { return this->Moc_; }
const UicSettingsT& Uic() const { return this->Uic_; }
// -- Worker thread interface
void WorkerSwapJob(JobHandleT& jobHandle);
// -- Parallel job processing interface
void ParallelRegisterJobError();
bool ParallelJobPushMoc(JobHandleT& jobHandle);
bool ParallelJobPushUic(JobHandleT& jobHandle);
bool ParallelMocIncluded(std::string const& sourceFile);
void ParallelMocAutoRegister(std::string const& mocFile);
void ParallelMocAutoUpdated();
private:
// -- Abstract processing interface
bool Init(cmMakefile* makefile) override;
bool Process() override;
// -- Process stage
static void UVPollStage(uv_async_t* handle);
void PollStage();
void SetStage(StageT stage);
// -- Settings file
void SettingsFileRead();
void SettingsFileWrite();
// -- Thread processing
bool ThreadsStartJobs(JobQueueT& queue);
bool ThreadsJobsDone();
void ThreadsStop();
void RegisterJobError();
// -- Generation
void CreateDirectories();
void MocGenerateCompilation();
private:
// -- Settings
BaseSettingsT Base_;
MocSettingsT Moc_;
UicSettingsT Uic_;
// -- Progress
StageT Stage_;
// -- Job queues
std::mutex JobsMutex_;
struct
{
JobQueueT Sources;
JobQueueT Headers;
JobQueueT MocPredefs;
JobQueueT Moc;
JobQueueT Uic;
} JobQueues_;
JobQueueT JobQueue_;
std::size_t volatile JobsRemain_;
bool volatile JobError_;
bool volatile JobThreadsAbort_;
std::condition_variable JobsConditionRead_;
// -- Moc meta
std::set<std::string> MocIncludedStrings_;
std::set<std::string> MocIncludedFiles_;
std::set<std::string> MocAutoFiles_;
bool volatile MocAutoFileUpdated_;
// -- Settings file
std::string SettingsFile_;
std::string SettingsStringMoc_;
std::string SettingsStringUic_;
// -- Threads and loops
std::vector<std::unique_ptr<WorkerT>> Workers_;
};
#endif