mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-28 04:09:35 +03:00
Autogen: Refactor AUTOMOC and AUTOUIC and add source file parse data caching
New features ------------ CMake's `AUTOMOC` and `AUTOUIC` now cache information extracted when parsing source files in `CMakeFiles/<ORIGIN>_autogen.dir/ParseCache.txt`. This leads to faster `<ORIGIN>_autogen` target rebuilds, because source files will be parsed again only if they're newer than the `ParseCache.txt` file. The parse cache will be recomputed if it is older than the CMake executable. `AUTOMOC` and `AUTOUIC` now check if `moc` or `uic` output files are older than the `moc` or `uic` executable. If an output file is older than the compiler, it will be regenerated. Therefore if a new `moc` or `uic` version is installed, all output files will be regenerated. `AUTOMOC` and `AUTOUIC` error and warning messages are more detailed. Internal changes ---------------- `moc` and `uic` output file names are not computed in the `_autogen` target anymore but in `cmQtAutoGenInitializer`. This makes the available at the configuration stage for improved dependency computations (to be done). In `AutogenInfo.cmake`, equally sized lists for "source file names", "source file flags" and "compiler output file names" are passed to the `_autogen` target. This replaces the separate file lists for `AUTOMOC` and `AUTOUIC`. Files times are read from the file system only once by using `cmFileTime` instances instead of `cmQtAutoGenerator::FileSystem::FileIsOlderThan` calls. All calls to not thread safe file system functions are moved to non concurrent fence jobs (see `cmWorkerPool::JobT::IsFence()`). This renders the `cmQtAutoGenerator::FileSystem` wrapper class obsolete and it is removed. Instead of composing a single large settings string that is fed to the `cmCryptoHash`, now all setting sub strings are fed one by one to the `cmCryptoHash` and the finalized result is stored. The `std::mutex` in `cmQtAutoGenerator::Logger` is tagged `mutable` and most `cmQtAutoGenerator::Logger` methods become `const`. Outlook ------- This patch provides the framework required to - extract dependencies from `.ui` files in `AUTOUIC`. These will help to address issue #15420 "AUTOUIC: Track uic external inputs". - generate adaptive `make` and `ninja` files in the `_autogen` target. These will help to address issue #16776 "AUTOUIC: Ninja needs two passes to correctly build Qt project". - generate (possibly empty) `moc` and `uic` files for all headers instead of a `mocs_compilation.cpp` file. This will help to address issue #17277 "AUTOMOC: Provide a option to allow AUTOMOC to compile individual " "moc_x.cxx instead of including all in mocs_compilation.cxx"
This commit is contained in:
@@ -194,11 +194,11 @@ std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
|
||||
|
||||
std::string cmQtAutoGen::SubDirPrefix(std::string const& filename)
|
||||
{
|
||||
std::string res(cmSystemTools::GetFilenamePath(filename));
|
||||
if (!res.empty()) {
|
||||
res += '/';
|
||||
std::string::size_type slash_pos = filename.rfind('/');
|
||||
if (slash_pos == std::string::npos) {
|
||||
return std::string();
|
||||
}
|
||||
return res;
|
||||
return filename.substr(0, slash_pos + 1);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -77,7 +78,8 @@ static std::string FileProjectRelativePath(cmMakefile* makefile,
|
||||
return res;
|
||||
}
|
||||
|
||||
/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its
|
||||
/**
|
||||
* Tests if targetDepend is a STATIC_LIBRARY and if any of its
|
||||
* recursive STATIC_LIBRARY dependencies depends on targetOrigin
|
||||
* (STATIC_LIBRARY cycle).
|
||||
*/
|
||||
@@ -384,6 +386,10 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
|
||||
} else {
|
||||
AddCleanFile(makefile, this->AutogenTarget.SettingsFile);
|
||||
}
|
||||
|
||||
this->AutogenTarget.ParseCacheFile = this->Dir.Info;
|
||||
this->AutogenTarget.ParseCacheFile += "/ParseCache.txt";
|
||||
AddCleanFile(makefile, this->AutogenTarget.ParseCacheFile);
|
||||
}
|
||||
|
||||
// Autogen target: Compute user defined dependencies
|
||||
@@ -1255,53 +1261,107 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
||||
ofs.Write("AM_INCLUDE_DIR", this->Dir.Include);
|
||||
ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude);
|
||||
|
||||
// Use sorted sets
|
||||
std::set<std::string> headers;
|
||||
std::set<std::string> sources;
|
||||
std::set<std::string> moc_headers;
|
||||
std::set<std::string> moc_sources;
|
||||
std::vector<std::string> headers;
|
||||
std::vector<std::string> headersFlags;
|
||||
std::vector<std::string> headersBuildPaths;
|
||||
std::vector<std::string> sources;
|
||||
std::vector<std::string> sourcesFlags;
|
||||
std::set<std::string> moc_skip;
|
||||
std::set<std::string> uic_headers;
|
||||
std::set<std::string> uic_sources;
|
||||
std::set<std::string> uic_skip;
|
||||
|
||||
// Filter headers
|
||||
for (auto const& pair : this->AutogenTarget.Headers) {
|
||||
MUFile const& muf = *pair.second;
|
||||
if (muf.Generated && !this->CMP0071Accept) {
|
||||
continue;
|
||||
{
|
||||
auto headerCount = this->AutogenTarget.Headers.size();
|
||||
headers.reserve(headerCount);
|
||||
headersFlags.reserve(headerCount);
|
||||
|
||||
std::vector<MUFile const*> sortedHeaders;
|
||||
{
|
||||
sortedHeaders.reserve(headerCount);
|
||||
for (auto const& pair : this->AutogenTarget.Headers) {
|
||||
sortedHeaders.emplace_back(pair.second.get());
|
||||
}
|
||||
std::sort(sortedHeaders.begin(), sortedHeaders.end(),
|
||||
[](MUFile const* a, MUFile const* b) {
|
||||
return (a->RealPath < b->RealPath);
|
||||
});
|
||||
}
|
||||
if (muf.SkipMoc) {
|
||||
moc_skip.insert(muf.RealPath);
|
||||
}
|
||||
if (muf.SkipUic) {
|
||||
uic_skip.insert(muf.RealPath);
|
||||
}
|
||||
if (muf.MocIt && muf.UicIt) {
|
||||
headers.insert(muf.RealPath);
|
||||
} else if (muf.MocIt) {
|
||||
moc_headers.insert(muf.RealPath);
|
||||
} else if (muf.UicIt) {
|
||||
uic_headers.insert(muf.RealPath);
|
||||
|
||||
for (MUFile const* const muf : sortedHeaders) {
|
||||
if (muf->Generated && !this->CMP0071Accept) {
|
||||
continue;
|
||||
}
|
||||
if (muf->SkipMoc) {
|
||||
moc_skip.insert(muf->RealPath);
|
||||
}
|
||||
if (muf->SkipUic) {
|
||||
uic_skip.insert(muf->RealPath);
|
||||
}
|
||||
if (muf->MocIt || muf->UicIt) {
|
||||
headers.emplace_back(muf->RealPath);
|
||||
std::string flags;
|
||||
flags += muf->MocIt ? 'M' : 'm';
|
||||
flags += muf->UicIt ? 'U' : 'u';
|
||||
headersFlags.emplace_back(std::move(flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Header build paths
|
||||
{
|
||||
cmFilePathChecksum const fpathCheckSum(makefile);
|
||||
std::unordered_set<std::string> emitted;
|
||||
for (std::string const& hdr : headers) {
|
||||
std::string basePath = fpathCheckSum.getPart(hdr);
|
||||
basePath += "/moc_";
|
||||
basePath += cmSystemTools::GetFilenameWithoutLastExtension(hdr);
|
||||
for (unsigned int ii = 1; ii != 1024; ++ii) {
|
||||
std::string path = basePath;
|
||||
if (ii > 1) {
|
||||
path += '_';
|
||||
path += std::to_string(ii);
|
||||
}
|
||||
path += ".cpp";
|
||||
if (emitted.emplace(path).second) {
|
||||
headersBuildPaths.emplace_back(std::move(path));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter sources
|
||||
for (auto const& pair : this->AutogenTarget.Sources) {
|
||||
MUFile const& muf = *pair.second;
|
||||
if (muf.Generated && !this->CMP0071Accept) {
|
||||
continue;
|
||||
{
|
||||
auto sourcesCount = this->AutogenTarget.Sources.size();
|
||||
sources.reserve(sourcesCount);
|
||||
sourcesFlags.reserve(sourcesCount);
|
||||
|
||||
std::vector<MUFile const*> sorted;
|
||||
sorted.reserve(sourcesCount);
|
||||
for (auto const& pair : this->AutogenTarget.Sources) {
|
||||
sorted.emplace_back(pair.second.get());
|
||||
}
|
||||
if (muf.SkipMoc) {
|
||||
moc_skip.insert(muf.RealPath);
|
||||
}
|
||||
if (muf.SkipUic) {
|
||||
uic_skip.insert(muf.RealPath);
|
||||
}
|
||||
if (muf.MocIt && muf.UicIt) {
|
||||
sources.insert(muf.RealPath);
|
||||
} else if (muf.MocIt) {
|
||||
moc_sources.insert(muf.RealPath);
|
||||
} else if (muf.UicIt) {
|
||||
uic_sources.insert(muf.RealPath);
|
||||
std::sort(sorted.begin(), sorted.end(),
|
||||
[](MUFile const* a, MUFile const* b) {
|
||||
return (a->RealPath < b->RealPath);
|
||||
});
|
||||
|
||||
for (MUFile const* const muf : sorted) {
|
||||
if (muf->Generated && !this->CMP0071Accept) {
|
||||
continue;
|
||||
}
|
||||
if (muf->SkipMoc) {
|
||||
moc_skip.insert(muf->RealPath);
|
||||
}
|
||||
if (muf->SkipUic) {
|
||||
uic_skip.insert(muf->RealPath);
|
||||
}
|
||||
if (muf->MocIt || muf->UicIt) {
|
||||
sources.emplace_back(muf->RealPath);
|
||||
std::string flags;
|
||||
flags += muf->MocIt ? 'M' : 'm';
|
||||
flags += muf->UicIt ? 'U' : 'u';
|
||||
sourcesFlags.emplace_back(std::move(flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,17 +1371,20 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
||||
ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable);
|
||||
|
||||
ofs.Write("# Files\n");
|
||||
ofs.Write("AM_CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
|
||||
ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
|
||||
ofs.WriteConfig("AM_SETTINGS_FILE",
|
||||
this->AutogenTarget.ConfigSettingsFile);
|
||||
ofs.Write("AM_PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
|
||||
ofs.WriteStrings("AM_HEADERS", headers);
|
||||
ofs.WriteStrings("AM_HEADERS_FLAGS", headersFlags);
|
||||
ofs.WriteStrings("AM_HEADERS_BUILD_PATHS", headersBuildPaths);
|
||||
ofs.WriteStrings("AM_SOURCES", sources);
|
||||
ofs.WriteStrings("AM_SOURCES_FLAGS", sourcesFlags);
|
||||
|
||||
// Write moc settings
|
||||
if (this->Moc.Enabled) {
|
||||
ofs.Write("# MOC settings\n");
|
||||
ofs.WriteStrings("AM_MOC_HEADERS", moc_headers);
|
||||
ofs.WriteStrings("AM_MOC_SOURCES", moc_sources);
|
||||
ofs.WriteStrings("AM_MOC_SKIP", moc_skip);
|
||||
ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines);
|
||||
ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines);
|
||||
@@ -1343,8 +1406,6 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
||||
uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
|
||||
|
||||
ofs.Write("# UIC settings\n");
|
||||
ofs.WriteStrings("AM_UIC_HEADERS", uic_headers);
|
||||
ofs.WriteStrings("AM_UIC_SOURCES", uic_sources);
|
||||
ofs.WriteStrings("AM_UIC_SKIP", uic_skip);
|
||||
ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options);
|
||||
ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions);
|
||||
|
||||
@@ -183,6 +183,7 @@ private:
|
||||
// Configuration files
|
||||
std::string InfoFile;
|
||||
std::string SettingsFile;
|
||||
std::string ParseCacheFile;
|
||||
std::map<std::string, std::string> ConfigSettingsFile;
|
||||
// Dependencies
|
||||
bool DependOrigin = false;
|
||||
|
||||
+25
-176
@@ -66,7 +66,8 @@ std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title)
|
||||
return head;
|
||||
}
|
||||
|
||||
void cmQtAutoGenerator::Logger::Info(GenT genType, std::string const& message)
|
||||
void cmQtAutoGenerator::Logger::Info(GenT genType,
|
||||
std::string const& message) const
|
||||
{
|
||||
std::string msg = GeneratorName(genType);
|
||||
msg += ": ";
|
||||
@@ -81,7 +82,7 @@ void cmQtAutoGenerator::Logger::Info(GenT genType, std::string const& message)
|
||||
}
|
||||
|
||||
void cmQtAutoGenerator::Logger::Warning(GenT genType,
|
||||
std::string const& message)
|
||||
std::string const& message) const
|
||||
{
|
||||
std::string msg;
|
||||
if (message.find('\n') == std::string::npos) {
|
||||
@@ -106,7 +107,7 @@ void cmQtAutoGenerator::Logger::Warning(GenT genType,
|
||||
|
||||
void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
|
||||
std::string const& filename,
|
||||
std::string const& message)
|
||||
std::string const& message) const
|
||||
{
|
||||
std::string msg = " ";
|
||||
msg += Quoted(filename);
|
||||
@@ -116,7 +117,8 @@ void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
|
||||
Warning(genType, msg);
|
||||
}
|
||||
|
||||
void cmQtAutoGenerator::Logger::Error(GenT genType, std::string const& message)
|
||||
void cmQtAutoGenerator::Logger::Error(GenT genType,
|
||||
std::string const& message) const
|
||||
{
|
||||
std::string msg;
|
||||
msg += HeadLine(GeneratorName(genType) + " error");
|
||||
@@ -134,7 +136,7 @@ void cmQtAutoGenerator::Logger::Error(GenT genType, std::string const& message)
|
||||
|
||||
void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
|
||||
std::string const& filename,
|
||||
std::string const& message)
|
||||
std::string const& message) const
|
||||
{
|
||||
std::string emsg = " ";
|
||||
emsg += Quoted(filename);
|
||||
@@ -146,7 +148,7 @@ void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
|
||||
|
||||
void cmQtAutoGenerator::Logger::ErrorCommand(
|
||||
GenT genType, std::string const& message,
|
||||
std::vector<std::string> const& command, std::string const& output)
|
||||
std::vector<std::string> const& command, std::string const& output) const
|
||||
{
|
||||
std::string msg;
|
||||
msg.push_back('\n');
|
||||
@@ -191,7 +193,7 @@ bool cmQtAutoGenerator::FileRead(std::string& content,
|
||||
content.clear();
|
||||
if (!cmSystemTools::FileExists(filename, true)) {
|
||||
if (error != nullptr) {
|
||||
error->append("Not a file.");
|
||||
*error = "Not a file.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -203,7 +205,7 @@ bool cmQtAutoGenerator::FileRead(std::string& content,
|
||||
return [&ifs, length, &content, error]() -> bool {
|
||||
if (!ifs) {
|
||||
if (error != nullptr) {
|
||||
error->append("Opening the file for reading failed.");
|
||||
*error = "Opening the file for reading failed.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -213,7 +215,7 @@ bool cmQtAutoGenerator::FileRead(std::string& content,
|
||||
if (!ifs) {
|
||||
content.clear();
|
||||
if (error != nullptr) {
|
||||
error->append("Reading from the file failed.");
|
||||
*error = "Reading from the file failed.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -228,7 +230,7 @@ bool cmQtAutoGenerator::FileWrite(std::string const& filename,
|
||||
// Make sure the parent directory exists
|
||||
if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
|
||||
if (error != nullptr) {
|
||||
error->assign("Could not create parent directory.");
|
||||
*error = "Could not create parent directory.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -240,14 +242,14 @@ bool cmQtAutoGenerator::FileWrite(std::string const& filename,
|
||||
return [&ofs, &content, error]() -> bool {
|
||||
if (!ofs) {
|
||||
if (error != nullptr) {
|
||||
error->assign("Opening file for writing failed.");
|
||||
*error = "Opening file for writing failed.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ofs << content;
|
||||
if (!ofs.good()) {
|
||||
if (error != nullptr) {
|
||||
error->assign("File writing failed.");
|
||||
*error = "File writing failed.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -255,176 +257,17 @@ bool cmQtAutoGenerator::FileWrite(std::string const& filename,
|
||||
}();
|
||||
}
|
||||
|
||||
cmQtAutoGenerator::FileSystem::FileSystem() = default;
|
||||
|
||||
cmQtAutoGenerator::FileSystem::~FileSystem() = default;
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::GetRealPath(
|
||||
std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::GetRealPath(filename);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::CollapseFullPath(
|
||||
std::string const& file, std::string const& dir)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::CollapseFullPath(file, dir);
|
||||
}
|
||||
|
||||
void cmQtAutoGenerator::FileSystem::SplitPath(
|
||||
const std::string& p, std::vector<std::string>& components,
|
||||
bool expand_home_dir)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
cmSystemTools::SplitPath(p, components, expand_home_dir);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::JoinPath(
|
||||
const std::vector<std::string>& components)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::JoinPath(components);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::JoinPath(
|
||||
std::vector<std::string>::const_iterator first,
|
||||
std::vector<std::string>::const_iterator last)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::JoinPath(first, last);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::GetFilenameWithoutLastExtension(
|
||||
const std::string& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::GetFilenameWithoutLastExtension(filename);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::SubDirPrefix(
|
||||
std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmQtAutoGen::SubDirPrefix(filename);
|
||||
}
|
||||
|
||||
void cmQtAutoGenerator::FileSystem::setupFilePathChecksum(
|
||||
std::string const& currentSrcDir, std::string const& currentBinDir,
|
||||
std::string const& projectSrcDir, std::string const& projectBinDir)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
FilePathChecksum_.setupParentDirs(currentSrcDir, currentBinDir,
|
||||
projectSrcDir, projectBinDir);
|
||||
}
|
||||
|
||||
std::string cmQtAutoGenerator::FileSystem::GetFilePathChecksum(
|
||||
std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return FilePathChecksum_.getPart(filename);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::FileExists(filename);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename,
|
||||
bool isFile)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::FileExists(filename, isFile);
|
||||
}
|
||||
|
||||
unsigned long cmQtAutoGenerator::FileSystem::FileLength(
|
||||
std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::FileLength(filename);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileIsOlderThan(
|
||||
std::string const& buildFile, std::string const& sourceFile,
|
||||
std::string* error)
|
||||
{
|
||||
bool res(false);
|
||||
int result = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result);
|
||||
}
|
||||
if (res) {
|
||||
res = (result < 0);
|
||||
} else {
|
||||
if (error != nullptr) {
|
||||
error->append(
|
||||
"File modification time comparison failed for the files\n ");
|
||||
error->append(Quoted(buildFile));
|
||||
error->append("\nand\n ");
|
||||
error->append(Quoted(sourceFile));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
|
||||
std::string const& filename,
|
||||
std::string* error)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmQtAutoGenerator::FileRead(content, filename, error);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
|
||||
std::string const& content,
|
||||
std::string* error)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmQtAutoGenerator::FileWrite(filename, content, error);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
|
||||
std::string const& content)
|
||||
bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
|
||||
std::string const& content)
|
||||
{
|
||||
bool differs = true;
|
||||
{
|
||||
std::string oldContents;
|
||||
if (FileRead(oldContents, filename)) {
|
||||
differs = (oldContents != content);
|
||||
}
|
||||
std::string oldContents;
|
||||
if (FileRead(oldContents, filename) && (oldContents == content)) {
|
||||
differs = false;
|
||||
}
|
||||
return differs;
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::RemoveFile(filename);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename,
|
||||
bool create)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::Touch(filename, create);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmSystemTools::MakeDirectory(dirname);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
|
||||
std::string const& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex_);
|
||||
return cmQtAutoGenerator::MakeParentDirectory(filename);
|
||||
}
|
||||
|
||||
cmQtAutoGenerator::cmQtAutoGenerator() = default;
|
||||
|
||||
cmQtAutoGenerator::~cmQtAutoGenerator() = default;
|
||||
@@ -435,6 +278,12 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
|
||||
// Info settings
|
||||
InfoFile_ = infoFile;
|
||||
cmSystemTools::ConvertToUnixSlashes(InfoFile_);
|
||||
if (!InfoFileTime_.Load(InfoFile_)) {
|
||||
std::string msg = "Autogen: The info file ";
|
||||
msg += Quoted(InfoFile_);
|
||||
msg += " is not readable\n";
|
||||
cmSystemTools::Stderr(msg);
|
||||
}
|
||||
InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
|
||||
InfoConfig_ = config;
|
||||
|
||||
|
||||
+19
-75
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmFilePathChecksum.h"
|
||||
#include "cmFileTime.h"
|
||||
#include "cmQtAutoGen.h"
|
||||
|
||||
#include <mutex>
|
||||
@@ -14,13 +14,17 @@
|
||||
|
||||
class cmMakefile;
|
||||
|
||||
/// @brief Base class for QtAutoGen gernerators
|
||||
/** \class cmQtAutoGenerator
|
||||
* \brief Base class for QtAutoGen generators
|
||||
*/
|
||||
class cmQtAutoGenerator : public cmQtAutoGen
|
||||
{
|
||||
public:
|
||||
// -- Types
|
||||
|
||||
/// @brief Thread safe logging
|
||||
/**
|
||||
* Thread safe logger
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
@@ -37,24 +41,24 @@ public:
|
||||
bool ColorOutput() const { return this->ColorOutput_; }
|
||||
void SetColorOutput(bool value);
|
||||
// -- Log info
|
||||
void Info(GenT genType, std::string const& message);
|
||||
void Info(GenT genType, std::string const& message) const;
|
||||
// -- Log warning
|
||||
void Warning(GenT genType, std::string const& message);
|
||||
void Warning(GenT genType, std::string const& message) const;
|
||||
void WarningFile(GenT genType, std::string const& filename,
|
||||
std::string const& message);
|
||||
std::string const& message) const;
|
||||
// -- Log error
|
||||
void Error(GenT genType, std::string const& message);
|
||||
void Error(GenT genType, std::string const& message) const;
|
||||
void ErrorFile(GenT genType, std::string const& filename,
|
||||
std::string const& message);
|
||||
std::string const& message) const;
|
||||
void ErrorCommand(GenT genType, std::string const& message,
|
||||
std::vector<std::string> const& command,
|
||||
std::string const& output);
|
||||
std::string const& output) const;
|
||||
|
||||
private:
|
||||
static std::string HeadLine(std::string const& title);
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
mutable std::mutex Mutex_;
|
||||
unsigned int Verbosity_ = 0;
|
||||
bool ColorOutput_ = false;
|
||||
};
|
||||
@@ -66,70 +70,8 @@ public:
|
||||
static bool FileWrite(std::string const& filename,
|
||||
std::string const& content,
|
||||
std::string* error = nullptr);
|
||||
|
||||
/// @brief Thread safe file system interface
|
||||
class FileSystem
|
||||
{
|
||||
public:
|
||||
FileSystem();
|
||||
~FileSystem();
|
||||
|
||||
// -- Paths
|
||||
/// @brief Wrapper for cmSystemTools::GetRealPath
|
||||
std::string GetRealPath(std::string const& filename);
|
||||
/// @brief Wrapper for cmSystemTools::CollapseFullPath
|
||||
std::string CollapseFullPath(std::string const& file,
|
||||
std::string const& dir);
|
||||
/// @brief Wrapper for cmSystemTools::SplitPath
|
||||
void SplitPath(const std::string& p, std::vector<std::string>& components,
|
||||
bool expand_home_dir = true);
|
||||
/// @brief Wrapper for cmSystemTools::JoinPath
|
||||
std::string JoinPath(const std::vector<std::string>& components);
|
||||
/// @brief Wrapper for cmSystemTools::JoinPath
|
||||
std::string JoinPath(std::vector<std::string>::const_iterator first,
|
||||
std::vector<std::string>::const_iterator last);
|
||||
/// @brief Wrapper for cmSystemTools::GetFilenameWithoutLastExtension
|
||||
std::string GetFilenameWithoutLastExtension(const std::string& filename);
|
||||
/// @brief Wrapper for cmQtAutoGen::SubDirPrefix
|
||||
std::string SubDirPrefix(std::string const& filename);
|
||||
/// @brief Wrapper for cmFilePathChecksum::setupParentDirs
|
||||
void setupFilePathChecksum(std::string const& currentSrcDir,
|
||||
std::string const& currentBinDir,
|
||||
std::string const& projectSrcDir,
|
||||
std::string const& projectBinDir);
|
||||
/// @brief Wrapper for cmFilePathChecksum::getPart
|
||||
std::string GetFilePathChecksum(std::string const& filename);
|
||||
|
||||
// -- File access
|
||||
/// @brief Wrapper for cmSystemTools::FileExists
|
||||
bool FileExists(std::string const& filename);
|
||||
/// @brief Wrapper for cmSystemTools::FileExists
|
||||
bool FileExists(std::string const& filename, bool isFile);
|
||||
/// @brief Wrapper for cmSystemTools::FileLength
|
||||
unsigned long FileLength(std::string const& filename);
|
||||
bool FileIsOlderThan(std::string const& buildFile,
|
||||
std::string const& sourceFile,
|
||||
std::string* error = nullptr);
|
||||
|
||||
bool FileRead(std::string& content, std::string const& filename,
|
||||
std::string* error = nullptr);
|
||||
|
||||
bool FileWrite(std::string const& filename, std::string const& content,
|
||||
std::string* error = nullptr);
|
||||
|
||||
bool FileDiffers(std::string const& filename, std::string const& content);
|
||||
|
||||
bool FileRemove(std::string const& filename);
|
||||
bool Touch(std::string const& filename, bool create = false);
|
||||
|
||||
// -- Directory access
|
||||
bool MakeDirectory(std::string const& dirname);
|
||||
bool MakeParentDirectory(std::string const& filename);
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
cmFilePathChecksum FilePathChecksum_;
|
||||
};
|
||||
static bool FileDiffers(std::string const& filename,
|
||||
std::string const& content);
|
||||
|
||||
public:
|
||||
// -- Constructors
|
||||
@@ -142,8 +84,9 @@ public:
|
||||
// -- Run
|
||||
bool Run(std::string const& infoFile, std::string const& config);
|
||||
|
||||
// InfoFile
|
||||
// -- InfoFile
|
||||
std::string const& InfoFile() const { return InfoFile_; }
|
||||
cmFileTime const& InfoFileTime() const { return InfoFileTime_; }
|
||||
std::string const& InfoDir() const { return InfoDir_; }
|
||||
std::string const& InfoConfig() const { return InfoConfig_; }
|
||||
|
||||
@@ -158,6 +101,7 @@ protected:
|
||||
private:
|
||||
// -- Info settings
|
||||
std::string InfoFile_;
|
||||
cmFileTime InfoFileTime_;
|
||||
std::string InfoDir_;
|
||||
std::string InfoConfig_;
|
||||
};
|
||||
|
||||
+1676
-1225
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -13,69 +12,189 @@
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmCryptoHash.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmQtAutoGen.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmake.h"
|
||||
#include "cmsys/FStream.hxx"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// -- Class methods
|
||||
static constexpr std::size_t MocUnderscoreLength = 4; // Length of "moc_"
|
||||
static constexpr std::size_t UiUnderscoreLength = 3; // Length of "ui_"
|
||||
|
||||
std::string cmQtAutoMocUic::BaseSettingsT::AbsoluteBuildPath(
|
||||
std::string const& relativePath) const
|
||||
cmQtAutoMocUic::IncludeKeyT::IncludeKeyT(std::string const& key,
|
||||
std::size_t basePrefixLength)
|
||||
: Key(key)
|
||||
, Dir(SubDirPrefix(key))
|
||||
, Base(cmSystemTools::GetFilenameWithoutLastExtension(key))
|
||||
{
|
||||
return FileSys->CollapseFullPath(relativePath, AutogenBuildDir);
|
||||
if (basePrefixLength != 0) {
|
||||
Base = Base.substr(basePrefixLength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to find the header file to the given file base path by
|
||||
* appending different header extensions
|
||||
* @return True on success
|
||||
*/
|
||||
bool cmQtAutoMocUic::BaseSettingsT::FindHeader(
|
||||
std::string& header, std::string const& testBasePath) const
|
||||
void cmQtAutoMocUic::ParseCacheT::FileT::Clear()
|
||||
{
|
||||
for (std::string const& ext : HeaderExtensions) {
|
||||
std::string testFilePath(testBasePath);
|
||||
testFilePath.push_back('.');
|
||||
testFilePath += ext;
|
||||
if (FileSys->FileExists(testFilePath)) {
|
||||
header = testFilePath;
|
||||
return true;
|
||||
Moc.Macro.clear();
|
||||
Moc.Include.Underscore.clear();
|
||||
Moc.Include.Dot.clear();
|
||||
Moc.Depends.clear();
|
||||
|
||||
Uic.Include.clear();
|
||||
Uic.Depends.clear();
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::ParseCacheT::FileHandleT cmQtAutoMocUic::ParseCacheT::Get(
|
||||
std::string const& fileName) const
|
||||
{
|
||||
auto it = Map_.find(fileName);
|
||||
if (it != Map_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return FileHandleT();
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::ParseCacheT::GetOrInsertT
|
||||
cmQtAutoMocUic::ParseCacheT::GetOrInsert(std::string const& fileName)
|
||||
{
|
||||
// Find existing entry
|
||||
{
|
||||
auto it = Map_.find(fileName);
|
||||
if (it != Map_.end()) {
|
||||
return GetOrInsertT{ it->second, false };
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// Insert new entry
|
||||
return GetOrInsertT{
|
||||
Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
|
||||
};
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::ParseCacheT::ParseCacheT() = default;
|
||||
cmQtAutoMocUic::ParseCacheT::~ParseCacheT() = default;
|
||||
|
||||
void cmQtAutoMocUic::ParseCacheT::Clear()
|
||||
{
|
||||
Map_.clear();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParseCacheT::ReadFromFile(std::string const& fileName)
|
||||
{
|
||||
cmsys::ifstream fin(fileName.c_str());
|
||||
if (!fin) {
|
||||
return false;
|
||||
}
|
||||
FileHandleT fileHandle;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(fin, line)) {
|
||||
// Check if this an empty or a comment line
|
||||
if (line.empty() || line.front() == '#') {
|
||||
continue;
|
||||
}
|
||||
// Drop carriage return character at the end
|
||||
if (line.back() == '\r') {
|
||||
line.pop_back();
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Check if this a file name line
|
||||
if (line.front() != ' ') {
|
||||
fileHandle = GetOrInsert(line).first;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bad line or bad file handle
|
||||
if (!fileHandle || (line.size() < 6)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr std::size_t offset = 5;
|
||||
if (cmHasLiteralPrefix(line, " mmc:")) {
|
||||
fileHandle->Moc.Macro = line.substr(offset);
|
||||
continue;
|
||||
}
|
||||
if (cmHasLiteralPrefix(line, " miu:")) {
|
||||
fileHandle->Moc.Include.Underscore.emplace_back(line.substr(offset),
|
||||
MocUnderscoreLength);
|
||||
continue;
|
||||
}
|
||||
if (cmHasLiteralPrefix(line, " mid:")) {
|
||||
fileHandle->Moc.Include.Dot.emplace_back(line.substr(offset), 0);
|
||||
continue;
|
||||
}
|
||||
if (cmHasLiteralPrefix(line, " mdp:")) {
|
||||
fileHandle->Moc.Depends.emplace_back(line.substr(offset));
|
||||
continue;
|
||||
}
|
||||
if (cmHasLiteralPrefix(line, " uic:")) {
|
||||
fileHandle->Uic.Include.emplace_back(line.substr(offset),
|
||||
UiUnderscoreLength);
|
||||
continue;
|
||||
}
|
||||
if (cmHasLiteralPrefix(line, " udp:")) {
|
||||
fileHandle->Uic.Depends.emplace_back(line.substr(offset));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParseCacheT::WriteToFile(std::string const& fileName)
|
||||
{
|
||||
cmGeneratedFileStream ofs(fileName);
|
||||
if (!ofs) {
|
||||
return false;
|
||||
}
|
||||
ofs << "# Generated by CMake. Changes will be overwritten." << std::endl;
|
||||
for (auto const& pair : Map_) {
|
||||
ofs << pair.first << std::endl;
|
||||
FileT const& file = *pair.second;
|
||||
if (!file.Moc.Macro.empty()) {
|
||||
ofs << " mmc:" << file.Moc.Macro << std::endl;
|
||||
}
|
||||
for (IncludeKeyT const& item : file.Moc.Include.Underscore) {
|
||||
ofs << " miu:" << item.Key << std::endl;
|
||||
}
|
||||
for (IncludeKeyT const& item : file.Moc.Include.Dot) {
|
||||
ofs << " mid:" << item.Key << std::endl;
|
||||
}
|
||||
for (std::string const& item : file.Moc.Depends) {
|
||||
ofs << " mdp:" << item << std::endl;
|
||||
}
|
||||
for (IncludeKeyT const& item : file.Uic.Include) {
|
||||
ofs << " uic:" << item.Key << std::endl;
|
||||
}
|
||||
for (std::string const& item : file.Uic.Depends) {
|
||||
ofs << " udp:" << item << std::endl;
|
||||
}
|
||||
}
|
||||
return ofs.Close();
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::BaseSettingsT::BaseSettingsT() = default;
|
||||
cmQtAutoMocUic::BaseSettingsT::~BaseSettingsT() = default;
|
||||
|
||||
cmQtAutoMocUic::MocSettingsT::MocSettingsT()
|
||||
{
|
||||
RegExpInclude.compile(
|
||||
"(^|\n)[ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::MocSettingsT::~MocSettingsT() = default;
|
||||
|
||||
bool cmQtAutoMocUic::MocSettingsT::skipped(std::string const& fileName) const
|
||||
{
|
||||
return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first relevant Qt macro name found in the given C++ code
|
||||
* @return The name of the Qt macro or an empty string
|
||||
*/
|
||||
std::string cmQtAutoMocUic::MocSettingsT::FindMacro(
|
||||
std::string const& content) const
|
||||
{
|
||||
for (KeyExpT const& filter : MacroFilters) {
|
||||
// Run a simple find string operation before the expensive
|
||||
// regular expression check
|
||||
if (content.find(filter.Key) != std::string::npos) {
|
||||
cmsys::RegularExpressionMatch match;
|
||||
if (filter.Exp.find(content.c_str(), match)) {
|
||||
// Return macro name on demand
|
||||
return filter.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const
|
||||
{
|
||||
std::string res;
|
||||
@@ -98,53 +217,13 @@ std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::MocSettingsT::FindIncludedFile(
|
||||
std::string const& sourcePath, std::string const& includeString) const
|
||||
cmQtAutoMocUic::UicSettingsT::UicSettingsT()
|
||||
{
|
||||
// Search in vicinity of the source
|
||||
{
|
||||
std::string testPath = sourcePath;
|
||||
testPath += includeString;
|
||||
if (FileSys->FileExists(testPath)) {
|
||||
return FileSys->GetRealPath(testPath);
|
||||
}
|
||||
}
|
||||
// Search in include directories
|
||||
for (std::string const& path : IncludePaths) {
|
||||
std::string fullPath = path;
|
||||
fullPath.push_back('/');
|
||||
fullPath += includeString;
|
||||
if (FileSys->FileExists(fullPath)) {
|
||||
return FileSys->GetRealPath(fullPath);
|
||||
}
|
||||
}
|
||||
// Return empty string
|
||||
return std::string();
|
||||
RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::MocSettingsT::FindDependencies(
|
||||
std::string const& content, std::set<std::string>& depends) const
|
||||
{
|
||||
if (!DependFilters.empty() && !content.empty()) {
|
||||
for (KeyExpT const& filter : DependFilters) {
|
||||
// Run a simple find string check
|
||||
if (content.find(filter.Key) != std::string::npos) {
|
||||
// Run the expensive regular expression check loop
|
||||
const char* contentChars = content.c_str();
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (filter.Exp.find(contentChars, match)) {
|
||||
{
|
||||
std::string dep = match.match(1);
|
||||
if (!dep.empty()) {
|
||||
depends.emplace(std::move(dep));
|
||||
}
|
||||
}
|
||||
contentChars += match.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cmQtAutoMocUic::UicSettingsT::~UicSettingsT() = default;
|
||||
|
||||
bool cmQtAutoMocUic::UicSettingsT::skipped(std::string const& fileName) const
|
||||
{
|
||||
@@ -176,498 +255,844 @@ void cmQtAutoMocUic::JobT::LogCommandError(
|
||||
|
||||
bool cmQtAutoMocUic::JobT::RunProcess(GenT genType,
|
||||
cmWorkerPool::ProcessResultT& result,
|
||||
std::vector<std::string> const& command)
|
||||
std::vector<std::string> const& command,
|
||||
std::string* infoMessage)
|
||||
{
|
||||
// Log command
|
||||
if (Log().Verbose()) {
|
||||
std::string msg = "Running command:\n";
|
||||
std::string msg;
|
||||
if ((infoMessage != nullptr) && !infoMessage->empty()) {
|
||||
msg = *infoMessage;
|
||||
if (msg.back() != '\n') {
|
||||
msg += '\n';
|
||||
}
|
||||
}
|
||||
msg += QuotedCommand(command);
|
||||
msg += '\n';
|
||||
Log().Info(genType, msg);
|
||||
}
|
||||
return cmWorkerPool::JobT::RunProcess(result, command,
|
||||
Gen()->Base().AutogenBuildDir);
|
||||
BaseConst().AutogenBuildDir);
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocPredefsT::Process()
|
||||
{
|
||||
// (Re)generate moc_predefs.h on demand
|
||||
bool generate(false);
|
||||
bool fileExists(FileSys().FileExists(Gen()->Moc().PredefsFileAbs));
|
||||
if (!fileExists) {
|
||||
if (Log().Verbose()) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(Gen()->Moc().PredefsFileRel);
|
||||
reason += " because it doesn't exist";
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
generate = true;
|
||||
} else if (Gen()->Moc().SettingsChanged) {
|
||||
if (Log().Verbose()) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(Gen()->Moc().PredefsFileRel);
|
||||
reason += " because the settings changed.";
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
generate = true;
|
||||
std::unique_ptr<std::string> reason;
|
||||
if (Log().Verbose()) {
|
||||
reason = cm::make_unique<std::string>();
|
||||
}
|
||||
if (generate) {
|
||||
if (!Update(reason.get())) {
|
||||
return;
|
||||
}
|
||||
std::string const& predefsFileRel = MocConst().PredefsFileRel;
|
||||
std::string const& predefsFileAbs = MocConst().PredefsFileAbs;
|
||||
{
|
||||
cmWorkerPool::ProcessResultT result;
|
||||
{
|
||||
// Compose command
|
||||
std::vector<std::string> cmd = Gen()->Moc().PredefsCmd;
|
||||
std::vector<std::string> cmd = MocConst().PredefsCmd;
|
||||
// Add includes
|
||||
cmd.insert(cmd.end(), Gen()->Moc().Includes.begin(),
|
||||
Gen()->Moc().Includes.end());
|
||||
cmd.insert(cmd.end(), MocConst().Includes.begin(),
|
||||
MocConst().Includes.end());
|
||||
// Add definitions
|
||||
for (std::string const& def : Gen()->Moc().Definitions) {
|
||||
for (std::string const& def : MocConst().Definitions) {
|
||||
cmd.push_back("-D" + def);
|
||||
}
|
||||
// Execute command
|
||||
if (!RunProcess(GenT::MOC, result, cmd)) {
|
||||
std::string emsg = "The content generation command for ";
|
||||
emsg += Quoted(Gen()->Moc().PredefsFileRel);
|
||||
emsg += " failed.\n";
|
||||
emsg += result.ErrorMessage;
|
||||
LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
|
||||
if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
|
||||
std::string msg = "The content generation command for ";
|
||||
msg += Quoted(predefsFileRel);
|
||||
msg += " failed.\n";
|
||||
msg += result.ErrorMessage;
|
||||
LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// (Re)write predefs file only on demand
|
||||
if (!result.error()) {
|
||||
if (!fileExists ||
|
||||
FileSys().FileDiffers(Gen()->Moc().PredefsFileAbs, result.StdOut)) {
|
||||
if (FileSys().FileWrite(Gen()->Moc().PredefsFileAbs, result.StdOut)) {
|
||||
// Success
|
||||
} else {
|
||||
std::string emsg = "Writing ";
|
||||
emsg += Quoted(Gen()->Moc().PredefsFileRel);
|
||||
emsg += " failed.";
|
||||
LogFileError(GenT::MOC, Gen()->Moc().PredefsFileAbs, emsg);
|
||||
}
|
||||
} else {
|
||||
// Touch to update the time stamp
|
||||
if (Log().Verbose()) {
|
||||
std::string msg = "Touching ";
|
||||
msg += Quoted(Gen()->Moc().PredefsFileRel);
|
||||
msg += ".";
|
||||
Log().Info(GenT::MOC, msg);
|
||||
}
|
||||
FileSys().Touch(Gen()->Moc().PredefsFileAbs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::Process()
|
||||
{
|
||||
if (AutoMoc && Header) {
|
||||
// Don't parse header for moc if the file is included by a source already
|
||||
if (Gen()->ParallelMocIncluded(FileName)) {
|
||||
AutoMoc = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AutoMoc || AutoUic) {
|
||||
std::string error;
|
||||
MetaT meta;
|
||||
if (FileSys().FileRead(meta.Content, FileName, &error)) {
|
||||
if (!meta.Content.empty()) {
|
||||
meta.FileDir = FileSys().SubDirPrefix(FileName);
|
||||
meta.FileBase = FileSys().GetFilenameWithoutLastExtension(FileName);
|
||||
|
||||
bool success = true;
|
||||
if (AutoMoc) {
|
||||
if (Header) {
|
||||
success = ParseMocHeader(meta);
|
||||
} else {
|
||||
success = ParseMocSource(meta);
|
||||
}
|
||||
}
|
||||
if (AutoUic && success) {
|
||||
ParseUic(meta);
|
||||
}
|
||||
} else {
|
||||
Log().WarningFile(GenT::GEN, FileName, "The source file is empty");
|
||||
if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) {
|
||||
if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) {
|
||||
std::string msg = "Writing ";
|
||||
msg += Quoted(predefsFileRel);
|
||||
msg += " failed.";
|
||||
LogFileError(GenT::MOC, predefsFileAbs, msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
LogFileError(GenT::GEN, FileName, "Could not read the file: " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobParseT::ParseMocSource(MetaT const& meta)
|
||||
{
|
||||
struct JobPre
|
||||
{
|
||||
bool self; // source file is self
|
||||
bool underscore; // "moc_" style include
|
||||
std::string SourceFile;
|
||||
std::string IncludeString;
|
||||
};
|
||||
|
||||
struct MocInclude
|
||||
{
|
||||
std::string Inc; // full include string
|
||||
std::string Dir; // include string directory
|
||||
std::string Base; // include string file base
|
||||
};
|
||||
|
||||
// Check if this source file contains a relevant macro
|
||||
std::string const ownMacro = Gen()->Moc().FindMacro(meta.Content);
|
||||
|
||||
// Extract moc includes from file
|
||||
std::deque<MocInclude> mocIncsUsc;
|
||||
std::deque<MocInclude> mocIncsDot;
|
||||
{
|
||||
if (meta.Content.find("moc") != std::string::npos) {
|
||||
const char* contentChars = meta.Content.c_str();
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (Gen()->Moc().RegExpInclude.find(contentChars, match)) {
|
||||
std::string incString = match.match(2);
|
||||
std::string incDir(FileSys().SubDirPrefix(incString));
|
||||
std::string incBase =
|
||||
FileSys().GetFilenameWithoutLastExtension(incString);
|
||||
if (cmHasLiteralPrefix(incBase, "moc_")) {
|
||||
// moc_<BASE>.cxx
|
||||
// Remove the moc_ part from the base name
|
||||
mocIncsUsc.emplace_back(MocInclude{
|
||||
std::move(incString), std::move(incDir), incBase.substr(4) });
|
||||
} else {
|
||||
// <BASE>.moc
|
||||
mocIncsDot.emplace_back(MocInclude{
|
||||
std::move(incString), std::move(incDir), std::move(incBase) });
|
||||
}
|
||||
// Forward content pointer
|
||||
contentChars += match.end();
|
||||
// Touch to update the time stamp
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::MOC, "Touching " + Quoted(predefsFileRel));
|
||||
}
|
||||
if (!cmSystemTools::Touch(predefsFileAbs, false)) {
|
||||
std::string msg = "Touching ";
|
||||
msg += Quoted(predefsFileAbs);
|
||||
msg += " failed.";
|
||||
LogFileError(GenT::MOC, predefsFileAbs, msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is anything to do
|
||||
if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
|
||||
// Read file time afterwards
|
||||
if (!MocEval().PredefsTime.Load(predefsFileAbs)) {
|
||||
LogFileError(GenT::MOC, predefsFileAbs, "File time reading failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const
|
||||
{
|
||||
// Test if the file exists
|
||||
if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(MocConst().PredefsFileRel);
|
||||
*reason += ", because it doesn't exist.";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ownDotMocIncluded = false;
|
||||
bool ownMocUscIncluded = false;
|
||||
std::deque<JobPre> jobs;
|
||||
// Test if the settings changed
|
||||
if (MocConst().SettingsChanged) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(MocConst().PredefsFileRel);
|
||||
*reason += ", because the moc settings changed.";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process moc_<BASE>.cxx includes
|
||||
for (const MocInclude& mocInc : mocIncsUsc) {
|
||||
std::string const header =
|
||||
MocFindIncludedHeader(meta.FileDir, mocInc.Dir + mocInc.Base);
|
||||
if (!header.empty()) {
|
||||
// Check if header is skipped
|
||||
if (Gen()->Moc().skipped(header)) {
|
||||
continue;
|
||||
// Test if the executable is newer
|
||||
{
|
||||
std::string const& exec = MocConst().PredefsCmd.at(0);
|
||||
cmFileTime execTime;
|
||||
if (execTime.Load(exec)) {
|
||||
if (MocEval().PredefsTime.Older(execTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(MocConst().PredefsFileRel);
|
||||
*reason += " because it is older than ";
|
||||
*reason += Quoted(exec);
|
||||
*reason += ".";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Register moc job
|
||||
const bool ownMoc = (mocInc.Base == meta.FileBase);
|
||||
jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc });
|
||||
// Store meta information for relaxed mode
|
||||
if (ownMoc) {
|
||||
ownMocUscIncluded = true;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobParseT::ReadFile()
|
||||
{
|
||||
// Clear old parse information
|
||||
FileHandle->ParseData->Clear();
|
||||
std::string const& fileName = FileHandle->FileName;
|
||||
// Write info
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::GEN, "Parsing " + Quoted(fileName));
|
||||
}
|
||||
// Read file content
|
||||
{
|
||||
std::string error;
|
||||
if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) {
|
||||
LogFileError(GenT::GEN, fileName, "Could not read the file: " + error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Warn if empty
|
||||
if (Content.empty()) {
|
||||
Log().WarningFile(GenT::GEN, fileName, "The file is empty.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::CreateKeys(std::vector<IncludeKeyT>& container,
|
||||
std::set<std::string> const& source,
|
||||
std::size_t basePrefixLength)
|
||||
{
|
||||
if (source.empty()) {
|
||||
return;
|
||||
}
|
||||
container.reserve(source.size());
|
||||
for (std::string const& src : source) {
|
||||
container.emplace_back(src, basePrefixLength);
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::MocMacro()
|
||||
{
|
||||
for (KeyExpT const& filter : MocConst().MacroFilters) {
|
||||
// Run a simple find string check
|
||||
if (Content.find(filter.Key) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
// Run the expensive regular expression check loop
|
||||
cmsys::RegularExpressionMatch match;
|
||||
if (filter.Exp.find(Content.c_str(), match)) {
|
||||
// Keep detected macro name
|
||||
FileHandle->ParseData->Moc.Macro = filter.Key;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::MocDependecies()
|
||||
{
|
||||
if (MocConst().DependFilters.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find dependency strings
|
||||
std::set<std::string> parseDepends;
|
||||
for (KeyExpT const& filter : MocConst().DependFilters) {
|
||||
// Run a simple find string check
|
||||
if (Content.find(filter.Key) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
// Run the expensive regular expression check loop
|
||||
const char* contentChars = Content.c_str();
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (filter.Exp.find(contentChars, match)) {
|
||||
{
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += ", but the header ";
|
||||
emsg += Quoted(MocStringHeaders(mocInc.Base));
|
||||
emsg += " could not be found.";
|
||||
LogFileError(GenT::MOC, FileName, emsg);
|
||||
std::string dep = match.match(1);
|
||||
if (!dep.empty()) {
|
||||
parseDepends.emplace(std::move(dep));
|
||||
}
|
||||
}
|
||||
contentChars += match.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Store dependency strings
|
||||
{
|
||||
auto& Depends = FileHandle->ParseData->Moc.Depends;
|
||||
Depends.reserve(parseDepends.size());
|
||||
for (std::string const& item : parseDepends) {
|
||||
Depends.emplace_back(item);
|
||||
// Replace end of line characters in filenames
|
||||
std::string& path = Depends.back();
|
||||
std::replace(path.begin(), path.end(), '\n', ' ');
|
||||
std::replace(path.begin(), path.end(), '\r', ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::MocIncludes()
|
||||
{
|
||||
if (Content.find("moc") == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> underscore;
|
||||
std::set<std::string> dot;
|
||||
{
|
||||
const char* contentChars = Content.c_str();
|
||||
cmsys::RegularExpression const& regExp = MocConst().RegExpInclude;
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (regExp.find(contentChars, match)) {
|
||||
std::string incString = match.match(2);
|
||||
std::string const incBase =
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(incString);
|
||||
if (cmHasLiteralPrefix(incBase, "moc_")) {
|
||||
// moc_<BASE>.cpp
|
||||
// Remove the moc_ part from the base name
|
||||
underscore.emplace(std::move(incString));
|
||||
} else {
|
||||
// <BASE>.moc
|
||||
dot.emplace(std::move(incString));
|
||||
}
|
||||
// Forward content pointer
|
||||
contentChars += match.end();
|
||||
}
|
||||
}
|
||||
auto& Include = FileHandle->ParseData->Moc.Include;
|
||||
CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
|
||||
CreateKeys(Include.Dot, dot, 0);
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseT::UicIncludes()
|
||||
{
|
||||
if (Content.find("ui_") == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> includes;
|
||||
{
|
||||
const char* contentChars = Content.c_str();
|
||||
cmsys::RegularExpression const& regExp = UicConst().RegExpInclude;
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (regExp.find(contentChars, match)) {
|
||||
includes.emplace(match.match(2));
|
||||
// Forward content pointer
|
||||
contentChars += match.end();
|
||||
}
|
||||
}
|
||||
CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength);
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseHeaderT::Process()
|
||||
{
|
||||
if (!ReadFile()) {
|
||||
return;
|
||||
}
|
||||
// Moc parsing
|
||||
if (FileHandle->Moc) {
|
||||
MocMacro();
|
||||
MocDependecies();
|
||||
}
|
||||
// Uic parsing
|
||||
if (FileHandle->Uic) {
|
||||
UicIncludes();
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobParseSourceT::Process()
|
||||
{
|
||||
if (!ReadFile()) {
|
||||
return;
|
||||
}
|
||||
// Moc parsing
|
||||
if (FileHandle->Moc) {
|
||||
MocMacro();
|
||||
MocDependecies();
|
||||
MocIncludes();
|
||||
}
|
||||
// Uic parsing
|
||||
if (FileHandle->Uic) {
|
||||
UicIncludes();
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobEvaluateT::Process()
|
||||
{
|
||||
// Evaluate for moc
|
||||
if (MocConst().Enabled) {
|
||||
// Evaluate headers
|
||||
for (auto const& pair : BaseEval().Headers) {
|
||||
if (!MocEvalHeader(pair.second)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Evaluate sources
|
||||
for (auto const& pair : BaseEval().Sources) {
|
||||
if (!MocEvalSource(pair.second)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Evaluate for uic
|
||||
if (UicConst().Enabled) {
|
||||
if (!UicEval(BaseEval().Headers) || !UicEval(BaseEval().Sources)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add discovered header parse jobs
|
||||
Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered);
|
||||
// Add generate job after
|
||||
Gen()->WorkerPool().EmplaceJob<JobGenerateT>();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobEvaluateT::MocEvalHeader(SourceFileHandleT source)
|
||||
{
|
||||
SourceFileT const& sourceFile = *source;
|
||||
auto const& parseData = sourceFile.ParseData->Moc;
|
||||
if (!source->Moc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!parseData.Macro.empty()) {
|
||||
// Create a new mapping
|
||||
MappingHandleT handle = std::make_shared<MappingT>();
|
||||
handle->SourceFile = std::move(source);
|
||||
|
||||
// Absolute build path
|
||||
if (BaseConst().MultiConfig) {
|
||||
handle->OutputFile = Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
|
||||
} else {
|
||||
handle->OutputFile = Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
|
||||
}
|
||||
|
||||
// Register mapping in headers map
|
||||
MocRegisterMapping(handle, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource(
|
||||
SourceFileHandleT const& source)
|
||||
{
|
||||
SourceFileT const& sourceFile = *source;
|
||||
auto const& parseData = sourceFile.ParseData->Moc;
|
||||
if (!sourceFile.Moc ||
|
||||
(parseData.Macro.empty() && parseData.Include.Underscore.empty() &&
|
||||
parseData.Include.Dot.empty())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
|
||||
std::string const sourceBase =
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName);
|
||||
|
||||
// For relaxed mode check if the own "moc_" or ".moc" file is included
|
||||
bool const relaxedMode = MocConst().RelaxedMode;
|
||||
bool sourceIncludesMocUnderscore = false;
|
||||
bool sourceIncludesDotMoc = false;
|
||||
// Check if the sources own "moc_" or ".moc" file is included
|
||||
if (relaxedMode) {
|
||||
for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
|
||||
if (incKey.Base == sourceBase) {
|
||||
sourceIncludesMocUnderscore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (IncludeKeyT const& incKey : parseData.Include.Dot) {
|
||||
if (incKey.Base == sourceBase) {
|
||||
sourceIncludesDotMoc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this source needs to be moc processed but doesn't.
|
||||
if (!sourceIncludesDotMoc && !parseData.Macro.empty() &&
|
||||
!(relaxedMode && sourceIncludesMocUnderscore)) {
|
||||
{
|
||||
std::string emsg = "The file contains a ";
|
||||
emsg += Quoted(parseData.Macro);
|
||||
emsg += " macro, but does not include ";
|
||||
emsg += Quoted(sourceBase + ".moc");
|
||||
emsg += "!\nConsider to\n - add #include \"";
|
||||
emsg += sourceBase;
|
||||
emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
|
||||
LogFileError(GenT::MOC, sourceFile.FileName, emsg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate "moc_" includes
|
||||
for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
|
||||
std::string const headerBase = incKey.Dir + incKey.Base;
|
||||
SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
|
||||
if (!header) {
|
||||
{
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ",\nbut the header could not be found "
|
||||
"in the following locations\n";
|
||||
msg += MocMessageTestHeaders(headerBase);
|
||||
LogFileError(GenT::MOC, sourceFile.FileName, msg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// The include might be handled differently in relaxed mode
|
||||
if (relaxedMode && !sourceIncludesDotMoc && !parseData.Macro.empty() &&
|
||||
(incKey.Base == sourceBase)) {
|
||||
// The <BASE>.cpp file includes a Qt macro but does not include the
|
||||
// <BASE>.moc file. In this case, the moc_<BASE>.cpp should probably
|
||||
// be generated from <BASE>.cpp instead of <BASE>.h, because otherwise
|
||||
// it won't build. But warn, since this is not how it is supposed to be
|
||||
// used. This is for KDE4 compatibility.
|
||||
{
|
||||
// Issue a warning
|
||||
std::string msg = "The file contains a ";
|
||||
msg += Quoted(parseData.Macro);
|
||||
msg += " macro, but does not include ";
|
||||
msg += Quoted(sourceBase + ".moc");
|
||||
msg += ".\nInstead it includes ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ".\nRunning moc on the source\n ";
|
||||
msg += Quoted(sourceFile.FileName);
|
||||
msg += "!\nBetter include ";
|
||||
msg += Quoted(sourceBase + ".moc");
|
||||
msg += " for compatibility with strict mode.\n";
|
||||
msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
|
||||
Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
|
||||
}
|
||||
// Create mapping
|
||||
if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if header is skipped
|
||||
if (MocConst().skipped(header->FileName)) {
|
||||
continue;
|
||||
}
|
||||
// Create mapping
|
||||
if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Process <BASE>.moc includes
|
||||
for (const MocInclude& mocInc : mocIncsDot) {
|
||||
const bool ownMoc = (mocInc.Base == meta.FileBase);
|
||||
if (Gen()->Moc().RelaxedMode) {
|
||||
// Relaxed mode
|
||||
if (!ownMacro.empty() && ownMoc) {
|
||||
// Add self
|
||||
jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
|
||||
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 =
|
||||
MocFindIncludedHeader(meta.FileDir, mocInc.Dir + mocInc.Base);
|
||||
if (!header.empty()) {
|
||||
// Check if header is skipped
|
||||
if (Gen()->Moc().skipped(header)) {
|
||||
continue;
|
||||
}
|
||||
// Register moc job
|
||||
jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc });
|
||||
if (ownMacro.empty()) {
|
||||
if (ownMoc) {
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += ", but does not contain a ";
|
||||
emsg += Gen()->Moc().MacrosString();
|
||||
emsg += " macro.\nRunning moc on\n ";
|
||||
emsg += Quoted(header);
|
||||
emsg += "!\nBetter include ";
|
||||
emsg += Quoted("moc_" + mocInc.Base + ".cpp");
|
||||
emsg += " for a compatibility with strict mode.\n"
|
||||
"(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
|
||||
Log().WarningFile(GenT::MOC, FileName, emsg);
|
||||
} else {
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += " instead of ";
|
||||
emsg += Quoted("moc_" + mocInc.Base + ".cpp");
|
||||
emsg += ".\nRunning moc on\n ";
|
||||
emsg += Quoted(header);
|
||||
emsg += "!\nBetter include ";
|
||||
emsg += Quoted("moc_" + mocInc.Base + ".cpp");
|
||||
emsg += " for compatibility with strict mode.\n"
|
||||
"(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
|
||||
Log().WarningFile(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
{
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += ", which seems to be the moc file from a different "
|
||||
"source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a "
|
||||
"matching header ";
|
||||
emsg += Quoted(MocStringHeaders(mocInc.Base));
|
||||
emsg += " could not be found.";
|
||||
LogFileError(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
// Evaluate ".moc" includes
|
||||
if (relaxedMode) {
|
||||
// Relaxed mode
|
||||
for (IncludeKeyT const& incKey : parseData.Include.Dot) {
|
||||
// Check if this is the sources own .moc file
|
||||
bool const ownMoc = (incKey.Base == sourceBase);
|
||||
if (ownMoc && !parseData.Macro.empty()) {
|
||||
// Create mapping for the regular use case
|
||||
if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Strict mode
|
||||
if (ownMoc) {
|
||||
// Include self
|
||||
jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
|
||||
ownDotMocIncluded = true;
|
||||
// Accept but issue a warning if moc isn't required
|
||||
if (ownMacro.empty()) {
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += ", but does not contain a ";
|
||||
emsg += Gen()->Moc().MacrosString();
|
||||
emsg += " macro.";
|
||||
Log().WarningFile(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
// Try to find a header instead but issue a warning.
|
||||
// This is for KDE4 compatibility.
|
||||
std::string const headerBase = incKey.Dir + incKey.Base;
|
||||
SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
|
||||
if (!header) {
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ",\nwhich seems to be the moc file from a different source "
|
||||
"file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a matching header"
|
||||
"could not be found in the following locations\n";
|
||||
msg += MocMessageTestHeaders(headerBase);
|
||||
LogFileError(GenT::MOC, sourceFile.FileName, msg);
|
||||
return false;
|
||||
}
|
||||
// Check if header is skipped
|
||||
if (MocConst().skipped(header->FileName)) {
|
||||
continue;
|
||||
}
|
||||
// Issue a warning
|
||||
if (ownMoc && parseData.Macro.empty()) {
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ", but does not contain a\n";
|
||||
msg += MocConst().MacrosString();
|
||||
msg += " macro.\nRunning moc on the header\n ";
|
||||
msg += Quoted(header->FileName);
|
||||
msg += "!\nBetter include ";
|
||||
msg += Quoted("moc_" + incKey.Base + ".cpp");
|
||||
msg += " for a compatibility with strict mode.\n";
|
||||
msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
|
||||
Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
|
||||
} else {
|
||||
// Don't allow <BASE>.moc include other than self in strict mode
|
||||
{
|
||||
std::string emsg = "The file includes the moc file ";
|
||||
emsg += Quoted(mocInc.Inc);
|
||||
emsg += ", which seems to be the moc file from a different "
|
||||
"source file.\nThis is not supported. Include ";
|
||||
emsg += Quoted(meta.FileBase + ".moc");
|
||||
emsg += " to run moc on this source file.";
|
||||
LogFileError(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += " instead of ";
|
||||
msg += Quoted("moc_" + incKey.Base + ".cpp");
|
||||
msg += ".\nRunning moc on the header\n ";
|
||||
msg += Quoted(header->FileName);
|
||||
msg += "!\nBetter include ";
|
||||
msg += Quoted("moc_" + incKey.Base + ".cpp");
|
||||
msg += " for compatibility with strict mode.\n";
|
||||
msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
|
||||
Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
|
||||
}
|
||||
// Create mapping
|
||||
if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Strict mode
|
||||
for (IncludeKeyT const& incKey : parseData.Include.Dot) {
|
||||
// Check if this is the sources own .moc file
|
||||
bool const ownMoc = (incKey.Base == sourceBase);
|
||||
if (!ownMoc) {
|
||||
// Don't allow <BASE>.moc include other than own in strict mode
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ",\nwhich seems to be the moc file from a different "
|
||||
"source file.\nThis is not supported. Include ";
|
||||
msg += Quoted(sourceBase + ".moc");
|
||||
msg += " to run moc on this source file.";
|
||||
LogFileError(GenT::MOC, sourceFile.FileName, msg);
|
||||
return false;
|
||||
}
|
||||
// Accept but issue a warning if moc isn't required
|
||||
if (parseData.Macro.empty()) {
|
||||
std::string msg = "The file includes the moc file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ", but does not contain a ";
|
||||
msg += MocConst().MacrosString();
|
||||
msg += " macro.";
|
||||
Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
|
||||
}
|
||||
// Create mapping
|
||||
if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ownMacro.empty() && !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.
|
||||
// This is for KDE4 compatibility.
|
||||
if (Gen()->Moc().RelaxedMode && ownMocUscIncluded) {
|
||||
JobPre uscJobPre;
|
||||
// Remove underscore job request
|
||||
{
|
||||
auto itC = jobs.begin();
|
||||
auto itE = jobs.end();
|
||||
for (; itC != itE; ++itC) {
|
||||
JobPre& job(*itC);
|
||||
if (job.self && job.underscore) {
|
||||
uscJobPre = std::move(job);
|
||||
jobs.erase(itC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Issue a warning
|
||||
{
|
||||
std::string emsg = "The file contains a ";
|
||||
emsg += ownMacro;
|
||||
emsg += " macro, but does not include ";
|
||||
emsg += Quoted(meta.FileBase + ".moc");
|
||||
emsg += ". Instead it includes ";
|
||||
emsg += Quoted(uscJobPre.IncludeString);
|
||||
emsg += ".\nRunning moc on\n ";
|
||||
emsg += Quoted(FileName);
|
||||
emsg += "!\nBetter include ";
|
||||
emsg += Quoted(meta.FileBase + ".moc");
|
||||
emsg += " for compatibility with strict mode.\n"
|
||||
"(CMAKE_AUTOMOC_RELAXED_MODE warning)";
|
||||
Log().WarningFile(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
// Add own source job
|
||||
jobs.emplace_back(
|
||||
JobPre{ true, false, FileName, uscJobPre.IncludeString });
|
||||
} else {
|
||||
// Otherwise always error out since it will not compile.
|
||||
{
|
||||
std::string emsg = "The file contains a ";
|
||||
emsg += ownMacro;
|
||||
emsg += " macro, but does not include ";
|
||||
emsg += Quoted(meta.FileBase + ".moc");
|
||||
emsg += "!\nConsider to\n - add #include \"";
|
||||
emsg += meta.FileBase;
|
||||
emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
|
||||
LogFileError(GenT::MOC, FileName, emsg);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::SourceFileHandleT
|
||||
cmQtAutoMocUic::JobEvaluateT::MocFindIncludedHeader(
|
||||
std::string const& includerDir, std::string const& includeBase) const
|
||||
{
|
||||
// Search in vicinity of the source
|
||||
{
|
||||
SourceFileHandleT res = MocFindHeader(includerDir + includeBase);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert pre jobs to actual jobs
|
||||
for (JobPre& jobPre : jobs) {
|
||||
cmWorkerPool::JobHandleT jobHandle = cm::make_unique<JobMocT>(
|
||||
std::move(jobPre.SourceFile), FileName, std::move(jobPre.IncludeString));
|
||||
if (jobPre.self) {
|
||||
// Read dependencies from this source
|
||||
JobMocT& jobMoc = static_cast<JobMocT&>(*jobHandle);
|
||||
Gen()->Moc().FindDependencies(meta.Content, jobMoc.Depends);
|
||||
jobMoc.DependsValid = true;
|
||||
// Search in include directories
|
||||
for (std::string const& path : MocConst().IncludePaths) {
|
||||
std::string testPath = path;
|
||||
testPath += '/';
|
||||
testPath += includeBase;
|
||||
SourceFileHandleT res = MocFindHeader(testPath);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
if (!Gen()->ParallelJobPushMoc(std::move(jobHandle))) {
|
||||
}
|
||||
// Return without success
|
||||
return SourceFileHandleT();
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::SourceFileHandleT cmQtAutoMocUic::JobEvaluateT::MocFindHeader(
|
||||
std::string const& basePath) const
|
||||
{
|
||||
std::string testPath;
|
||||
testPath.reserve(basePath.size() + 8);
|
||||
for (std::string const& ext : BaseConst().HeaderExtensions) {
|
||||
testPath.clear();
|
||||
testPath += basePath;
|
||||
testPath += '.';
|
||||
testPath += ext;
|
||||
cmFileTime fileTime;
|
||||
if (fileTime.Load(testPath)) {
|
||||
// Compute real path of the file
|
||||
testPath = cmSystemTools::GetRealPath(testPath);
|
||||
// Return a known file if it exists already
|
||||
{
|
||||
auto it = BaseEval().Headers.find(testPath);
|
||||
if (it != BaseEval().Headers.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
// Created and return discovered file entry
|
||||
SourceFileHandleT& res = MocEval().HeadersDiscovered[testPath];
|
||||
if (!res) {
|
||||
res = std::make_shared<SourceFileT>(testPath);
|
||||
res->FileTime = fileTime;
|
||||
res->Moc = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
// Return without success
|
||||
return SourceFileHandleT();
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::JobEvaluateT::MocMessageTestHeaders(
|
||||
std::string const& fileBase) const
|
||||
{
|
||||
std::ostringstream res;
|
||||
{
|
||||
std::string exts = ".{";
|
||||
exts += cmJoin(BaseConst().HeaderExtensions, ",");
|
||||
exts += '}';
|
||||
// Compose result string
|
||||
res << " " << fileBase << exts << '\n';
|
||||
for (std::string const& path : MocConst().IncludePaths) {
|
||||
res << " " << path << '/' << fileBase << exts << '\n';
|
||||
}
|
||||
}
|
||||
return res.str();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded(
|
||||
std::string const& includeString, SourceFileHandleT includerFileHandle,
|
||||
SourceFileHandleT sourceFileHandle, bool sourceIsHeader) const
|
||||
{
|
||||
// Check if this file is already included
|
||||
MappingHandleT& handle = MocEval().Includes[includeString];
|
||||
if (handle) {
|
||||
// Check if the output file would be generated from different source files
|
||||
if (handle->SourceFile != sourceFileHandle) {
|
||||
std::string msg = "The source files\n ";
|
||||
msg += Quoted(includerFileHandle->FileName);
|
||||
msg += '\n';
|
||||
for (auto const& item : handle->IncluderFiles) {
|
||||
msg += " ";
|
||||
msg += Quoted(item->FileName);
|
||||
msg += '\n';
|
||||
}
|
||||
msg += "contain the same include string ";
|
||||
msg += Quoted(includeString);
|
||||
msg += ", but\nthe moc file would be generated from different "
|
||||
"source files\n ";
|
||||
msg += Quoted(sourceFileHandle->FileName);
|
||||
msg += " and\n ";
|
||||
msg += Quoted(handle->SourceFile->FileName);
|
||||
msg += ".\nConsider 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";
|
||||
LogError(GenT::MOC, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The same mapping already exists. Just add to the includers list.
|
||||
handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a new mapping
|
||||
handle = std::make_shared<MappingT>();
|
||||
handle->IncludeString = includeString;
|
||||
handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
|
||||
handle->SourceFile = std::move(sourceFileHandle);
|
||||
handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
|
||||
|
||||
// Register mapping in sources/headers map
|
||||
MocRegisterMapping(handle, sourceIsHeader);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobEvaluateT::MocRegisterMapping(
|
||||
MappingHandleT mappingHandle, bool sourceIsHeader) const
|
||||
{
|
||||
auto& regMap =
|
||||
sourceIsHeader ? MocEval().HeaderMappings : MocEval().SourceMappings;
|
||||
// Check if source file already gets mapped
|
||||
auto& regHandle = regMap[mappingHandle->SourceFile->FileName];
|
||||
if (!regHandle) {
|
||||
// Yet unknown mapping
|
||||
regHandle = std::move(mappingHandle);
|
||||
} else {
|
||||
// Mappings with include string override those without
|
||||
if (!mappingHandle->IncludeString.empty()) {
|
||||
regHandle = std::move(mappingHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobEvaluateT::UicEval(SourceFileMapT const& fileMap)
|
||||
{
|
||||
for (auto const& pair : fileMap) {
|
||||
if (!UicEvalFile(pair.second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobParseT::ParseMocHeader(MetaT const& meta)
|
||||
bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile(
|
||||
SourceFileHandleT sourceFileHandle)
|
||||
{
|
||||
bool success = true;
|
||||
std::string const macroName = Gen()->Moc().FindMacro(meta.Content);
|
||||
if (!macroName.empty()) {
|
||||
cmWorkerPool::JobHandleT jobHandle = cm::make_unique<JobMocT>(
|
||||
std::string(FileName), std::string(), std::string());
|
||||
// Read dependencies from this source
|
||||
{
|
||||
JobMocT& jobMoc = static_cast<JobMocT&>(*jobHandle);
|
||||
Gen()->Moc().FindDependencies(meta.Content, jobMoc.Depends);
|
||||
jobMoc.DependsValid = true;
|
||||
}
|
||||
success = Gen()->ParallelJobPushMoc(std::move(jobHandle));
|
||||
SourceFileT const& sourceFile = *sourceFileHandle;
|
||||
auto const& Include = sourceFile.ParseData->Uic.Include;
|
||||
if (!sourceFile.Uic || Include.empty()) {
|
||||
return true;
|
||||
}
|
||||
return success;
|
||||
|
||||
std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
|
||||
for (IncludeKeyT const& incKey : Include) {
|
||||
// Find .ui file name
|
||||
SourceFileHandleT uiFileHandle =
|
||||
UicFindIncludedUi(sourceFile.FileName, sourceDir, incKey);
|
||||
if (!uiFileHandle || UicConst().skipped(uiFileHandle->FileName)) {
|
||||
continue;
|
||||
}
|
||||
// Register mapping
|
||||
if (!UicRegisterMapping(incKey.Key, std::move(uiFileHandle),
|
||||
std::move(sourceFileHandle))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::JobParseT::MocStringHeaders(
|
||||
std::string const& fileBase) const
|
||||
bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping(
|
||||
std::string const& includeString, SourceFileHandleT uiFileHandle,
|
||||
SourceFileHandleT includerFileHandle)
|
||||
{
|
||||
std::string res = fileBase;
|
||||
res += ".{";
|
||||
res += cmJoin(Gen()->Base().HeaderExtensions, ",");
|
||||
res += "}";
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::JobParseT::MocFindIncludedHeader(
|
||||
std::string const& includerDir, std::string const& includeBase)
|
||||
{
|
||||
std::string header;
|
||||
// Search in vicinity of the source
|
||||
if (!Gen()->Base().FindHeader(header, includerDir + includeBase)) {
|
||||
// Search in include directories
|
||||
for (std::string const& path : Gen()->Moc().IncludePaths) {
|
||||
std::string fullPath = path;
|
||||
fullPath.push_back('/');
|
||||
fullPath += includeBase;
|
||||
if (Gen()->Base().FindHeader(header, fullPath)) {
|
||||
break;
|
||||
auto& Includes = Gen()->UicEval().Includes;
|
||||
auto it = Includes.find(includeString);
|
||||
if (it != Includes.end()) {
|
||||
MappingHandleT const& handle = it->second;
|
||||
if (handle->SourceFile != uiFileHandle) {
|
||||
// The output file already gets generated - from a different .ui file!
|
||||
std::string msg = "The source files\n ";
|
||||
msg += Quoted(includerFileHandle->FileName);
|
||||
msg += '\n';
|
||||
for (auto const& item : handle->IncluderFiles) {
|
||||
msg += " ";
|
||||
msg += Quoted(item->FileName);
|
||||
msg += '\n';
|
||||
}
|
||||
msg += "contain the same include string ";
|
||||
msg += Quoted(includeString);
|
||||
msg += ", but\nthe uic file would be generated from different "
|
||||
"user interface files\n ";
|
||||
msg += Quoted(uiFileHandle->FileName);
|
||||
msg += " and\n ";
|
||||
msg += Quoted(handle->SourceFile->FileName);
|
||||
msg += ".\nConsider 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";
|
||||
LogError(GenT::UIC, msg);
|
||||
return false;
|
||||
}
|
||||
// Add includer file to existing mapping
|
||||
handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
|
||||
} else {
|
||||
// New mapping handle
|
||||
MappingHandleT handle = std::make_shared<MappingT>();
|
||||
handle->IncludeString = includeString;
|
||||
handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
|
||||
handle->SourceFile = std::move(uiFileHandle);
|
||||
handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
|
||||
// Register mapping
|
||||
Includes.emplace(includeString, std::move(handle));
|
||||
}
|
||||
// Sanitize
|
||||
if (!header.empty()) {
|
||||
header = FileSys().GetRealPath(header);
|
||||
}
|
||||
return header;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobParseT::ParseUic(MetaT const& meta)
|
||||
cmQtAutoMocUic::SourceFileHandleT
|
||||
cmQtAutoMocUic::JobEvaluateT::UicFindIncludedUi(
|
||||
std::string const& sourceFile, std::string const& sourceDir,
|
||||
IncludeKeyT const& incKey) const
|
||||
{
|
||||
bool success = true;
|
||||
if (meta.Content.find("ui_") != std::string::npos) {
|
||||
const char* contentChars = meta.Content.c_str();
|
||||
cmsys::RegularExpressionMatch match;
|
||||
while (Gen()->Uic().RegExpInclude.find(contentChars, match)) {
|
||||
if (!ParseUicInclude(meta, match.match(2))) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
contentChars += match.end();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobParseT::ParseUicInclude(MetaT const& meta,
|
||||
std::string&& includeString)
|
||||
{
|
||||
bool success = false;
|
||||
std::string uiInputFile = UicFindIncludedFile(meta, includeString);
|
||||
if (!uiInputFile.empty()) {
|
||||
if (!Gen()->Uic().skipped(uiInputFile)) {
|
||||
cmWorkerPool::JobHandleT jobHandle = cm::make_unique<JobUicT>(
|
||||
std::move(uiInputFile), FileName, std::move(includeString));
|
||||
success = Gen()->ParallelJobPushUic(std::move(jobHandle));
|
||||
} else {
|
||||
// A skipped file is successful
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::JobParseT::UicFindIncludedFile(
|
||||
MetaT const& meta, std::string const& includeString)
|
||||
{
|
||||
std::string res;
|
||||
std::string searchFile =
|
||||
FileSys().GetFilenameWithoutLastExtension(includeString).substr(3);
|
||||
searchFile += ".ui";
|
||||
std::string searchFileName = incKey.Base;
|
||||
searchFileName += ".ui";
|
||||
// Collect search paths list
|
||||
std::deque<std::string> testFiles;
|
||||
std::vector<std::string> testFiles;
|
||||
{
|
||||
std::string const searchPath = FileSys().SubDirPrefix(includeString);
|
||||
auto& searchPaths = UicConst().SearchPaths;
|
||||
testFiles.reserve((searchPaths.size() + 1) * 2);
|
||||
|
||||
std::string searchFileFull;
|
||||
if (!searchPath.empty()) {
|
||||
searchFileFull = searchPath;
|
||||
searchFileFull += searchFile;
|
||||
}
|
||||
// Vicinity of the source
|
||||
{
|
||||
std::string const sourcePath = meta.FileDir;
|
||||
testFiles.push_back(sourcePath + searchFile);
|
||||
if (!searchPath.empty()) {
|
||||
testFiles.push_back(sourcePath + searchFileFull);
|
||||
}
|
||||
testFiles.emplace_back(sourceDir + searchFileName);
|
||||
if (!incKey.Dir.empty()) {
|
||||
std::string path = sourceDir;
|
||||
path += incKey.Dir;
|
||||
path += searchFileName;
|
||||
testFiles.emplace_back(path);
|
||||
}
|
||||
// AUTOUIC search paths
|
||||
if (!Gen()->Uic().SearchPaths.empty()) {
|
||||
for (std::string const& sPath : Gen()->Uic().SearchPaths) {
|
||||
testFiles.push_back((sPath + "/").append(searchFile));
|
||||
if (!searchPaths.empty()) {
|
||||
for (std::string const& sPath : searchPaths) {
|
||||
std::string path = sPath;
|
||||
path += '/';
|
||||
path += searchFileName;
|
||||
testFiles.emplace_back(std::move(path));
|
||||
}
|
||||
if (!searchPath.empty()) {
|
||||
for (std::string const& sPath : Gen()->Uic().SearchPaths) {
|
||||
testFiles.push_back((sPath + "/").append(searchFileFull));
|
||||
if (!incKey.Dir.empty()) {
|
||||
for (std::string const& sPath : searchPaths) {
|
||||
std::string path = sPath;
|
||||
path += '/';
|
||||
path += incKey.Dir;
|
||||
path += searchFileName;
|
||||
testFiles.emplace_back(std::move(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -675,414 +1100,430 @@ std::string cmQtAutoMocUic::JobParseT::UicFindIncludedFile(
|
||||
|
||||
// Search for the .ui file!
|
||||
for (std::string const& testFile : testFiles) {
|
||||
if (FileSys().FileExists(testFile)) {
|
||||
res = FileSys().GetRealPath(testFile);
|
||||
break;
|
||||
cmFileTime fileTime;
|
||||
if (fileTime.Load(testFile)) {
|
||||
// .ui file found in files system!
|
||||
std::string realPath = cmSystemTools::GetRealPath(testFile);
|
||||
// Get or create .ui file handle
|
||||
SourceFileHandleT& handle = Gen()->UicEval().UiFiles[realPath];
|
||||
if (!handle) {
|
||||
// The file wasn't registered, yet
|
||||
handle = std::make_shared<SourceFileT>(realPath);
|
||||
handle->FileTime = fileTime;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
// Log error
|
||||
if (res.empty()) {
|
||||
std::string emsg = "Could not find ";
|
||||
emsg += Quoted(searchFile);
|
||||
emsg += " in\n";
|
||||
{
|
||||
std::string msg = "The file includes the uic file ";
|
||||
msg += Quoted(incKey.Key);
|
||||
msg += ",\nbut the user interface file ";
|
||||
msg += Quoted(searchFileName);
|
||||
msg += "\ncould not be found in the following locations\n";
|
||||
for (std::string const& testFile : testFiles) {
|
||||
emsg += " ";
|
||||
emsg += Quoted(testFile);
|
||||
emsg += "\n";
|
||||
msg += " ";
|
||||
msg += Quoted(testFile);
|
||||
msg += '\n';
|
||||
}
|
||||
LogFileError(GenT::UIC, FileName, emsg);
|
||||
LogFileError(GenT::UIC, sourceFile, msg);
|
||||
}
|
||||
|
||||
return res;
|
||||
return SourceFileHandleT();
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobPostParseT::Process()
|
||||
void cmQtAutoMocUic::JobGenerateT::Process()
|
||||
{
|
||||
if (Gen()->Moc().Enabled) {
|
||||
// Add mocs compilations fence job
|
||||
// Add moc compile jobs
|
||||
if (MocConst().Enabled) {
|
||||
for (auto const& pair : MocEval().HeaderMappings) {
|
||||
// Register if this mapping is a candidate for mocs_compilation.cpp
|
||||
bool const compFile = pair.second->IncludeString.empty();
|
||||
if (compFile) {
|
||||
MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath);
|
||||
}
|
||||
if (!MocGenerate(pair.second, compFile)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto const& pair : MocEval().SourceMappings) {
|
||||
if (!MocGenerate(pair.second, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add mocs compilations job on demand
|
||||
Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
|
||||
}
|
||||
|
||||
// Add uic compile jobs
|
||||
if (UicConst().Enabled) {
|
||||
for (auto const& pair : Gen()->UicEval().Includes) {
|
||||
if (!UicGenerate(pair.second)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add finish job
|
||||
Gen()->WorkerPool().EmplaceJob<JobFinishT>();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobGenerateT::MocGenerate(MappingHandleT const& mapping,
|
||||
bool compFile) const
|
||||
{
|
||||
std::unique_ptr<std::string> reason;
|
||||
if (Log().Verbose()) {
|
||||
reason = cm::make_unique<std::string>();
|
||||
}
|
||||
if (MocUpdate(*mapping, reason.get())) {
|
||||
// Create the parent directory
|
||||
if (!MakeParentDirectory(mapping->OutputFile)) {
|
||||
LogFileError(GenT::MOC, mapping->OutputFile,
|
||||
"Could not create parent directory.");
|
||||
return false;
|
||||
}
|
||||
// Add moc job
|
||||
Gen()->WorkerPool().EmplaceJob<JobMocT>(mapping, std::move(reason));
|
||||
// Check if a moc job for a mocs_compilation.cpp entry was generated
|
||||
if (compFile) {
|
||||
MocEval().CompUpdated = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping,
|
||||
std::string* reason) const
|
||||
{
|
||||
std::string const& sourceFile = mapping.SourceFile->FileName;
|
||||
std::string const& outputFile = mapping.OutputFile;
|
||||
|
||||
// Test if the output file exists
|
||||
cmFileTime outputFileTime;
|
||||
if (!outputFileTime.Load(outputFile)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it doesn't exist, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if any setting changed
|
||||
if (MocConst().SettingsChanged) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because the uic settings changed, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the source file is newer
|
||||
if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it's older than its source file, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the moc_predefs file is newer
|
||||
if (!MocConst().PredefsFileAbs.empty()) {
|
||||
if (outputFileTime.Older(MocEval().PredefsTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it's older than ";
|
||||
*reason += Quoted(MocConst().PredefsFileAbs);
|
||||
*reason += ", from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the moc executable is newer
|
||||
if (outputFileTime.Older(MocConst().ExecutableTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it's older than the moc executable, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if a dependency file is newer
|
||||
{
|
||||
// Check dependency timestamps
|
||||
std::string const sourceDir = SubDirPrefix(sourceFile);
|
||||
for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) {
|
||||
// Find dependency file
|
||||
auto const depMatch = MocFindDependency(sourceDir, dep);
|
||||
if (depMatch.first.empty()) {
|
||||
Log().WarningFile(GenT::MOC, sourceFile,
|
||||
"Could not find dependency file " + Quoted(dep));
|
||||
continue;
|
||||
}
|
||||
// Test if dependency file is older
|
||||
if (outputFileTime.Older(depMatch.second)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it's older than its dependency file ";
|
||||
*reason += Quoted(depMatch.first);
|
||||
*reason += ", from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<std::string, cmFileTime>
|
||||
cmQtAutoMocUic::JobGenerateT::MocFindDependency(
|
||||
std::string const& sourceDir, std::string const& includeString) const
|
||||
{
|
||||
typedef std::pair<std::string, cmFileTime> ResPair;
|
||||
// Search in vicinity of the source
|
||||
{
|
||||
ResPair res{ sourceDir + includeString, {} };
|
||||
if (res.second.Load(res.first)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
// Search in include directories
|
||||
for (std::string const& includePath : MocConst().IncludePaths) {
|
||||
ResPair res{ includePath, {} };
|
||||
res.first += '/';
|
||||
res.first += includeString;
|
||||
if (res.second.Load(res.first)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
// Return empty
|
||||
return ResPair();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobGenerateT::UicGenerate(
|
||||
MappingHandleT const& mapping) const
|
||||
{
|
||||
std::unique_ptr<std::string> reason;
|
||||
if (Log().Verbose()) {
|
||||
reason = cm::make_unique<std::string>();
|
||||
}
|
||||
if (UicUpdate(*mapping, reason.get())) {
|
||||
// Create the parent directory
|
||||
if (!MakeParentDirectory(mapping->OutputFile)) {
|
||||
LogFileError(GenT::UIC, mapping->OutputFile,
|
||||
"Could not create parent directory.");
|
||||
return false;
|
||||
}
|
||||
// Add uic job
|
||||
Gen()->WorkerPool().EmplaceJob<JobUicT>(mapping, std::move(reason));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping,
|
||||
std::string* reason) const
|
||||
{
|
||||
std::string const& sourceFile = mapping.SourceFile->FileName;
|
||||
std::string const& outputFile = mapping.OutputFile;
|
||||
|
||||
// Test if the build file exists
|
||||
cmFileTime outputFileTime;
|
||||
if (!outputFileTime.Load(outputFile)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it doesn't exist, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the uic settings changed
|
||||
if (UicConst().SettingsChanged) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because the uic settings changed, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the source file is newer
|
||||
if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += " because it's older than the source file ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the uic executable is newer
|
||||
if (outputFileTime.Older(UicConst().ExecutableTime)) {
|
||||
if (reason != nullptr) {
|
||||
*reason = "Generating ";
|
||||
*reason += Quoted(outputFile);
|
||||
*reason += ", because it's older than the uic executable, from ";
|
||||
*reason += Quoted(sourceFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocT::Process()
|
||||
{
|
||||
std::string const& sourceFile = Mapping->SourceFile->FileName;
|
||||
std::string const& outputFile = Mapping->OutputFile;
|
||||
|
||||
// Compose moc command
|
||||
std::vector<std::string> cmd;
|
||||
cmd.push_back(MocConst().Executable);
|
||||
// Add options
|
||||
cmd.insert(cmd.end(), MocConst().AllOptions.begin(),
|
||||
MocConst().AllOptions.end());
|
||||
// Add predefs include
|
||||
if (!MocConst().PredefsFileAbs.empty()) {
|
||||
cmd.emplace_back("--include");
|
||||
cmd.push_back(MocConst().PredefsFileAbs);
|
||||
}
|
||||
cmd.emplace_back("-o");
|
||||
cmd.push_back(outputFile);
|
||||
cmd.push_back(sourceFile);
|
||||
|
||||
// Execute moc command
|
||||
cmWorkerPool::ProcessResultT result;
|
||||
if (RunProcess(GenT::MOC, result, cmd, Reason.get())) {
|
||||
// Moc command success. Print moc output.
|
||||
if (!result.StdOut.empty()) {
|
||||
Log().Info(GenT::MOC, result.StdOut);
|
||||
}
|
||||
} else {
|
||||
// Moc command failed
|
||||
std::string msg = "The moc process failed to compile\n ";
|
||||
msg += Quoted(sourceFile);
|
||||
msg += "\ninto\n ";
|
||||
msg += Quoted(outputFile);
|
||||
if (Mapping->IncluderFiles.empty()) {
|
||||
msg += ".\n";
|
||||
} else {
|
||||
msg += "\nincluded by\n";
|
||||
for (auto const& item : Mapping->IncluderFiles) {
|
||||
msg += " ";
|
||||
msg += Quoted(item->FileName);
|
||||
msg += '\n';
|
||||
}
|
||||
}
|
||||
msg += result.ErrorMessage;
|
||||
LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobUicT::Process()
|
||||
{
|
||||
std::string const& sourceFile = Mapping->SourceFile->FileName;
|
||||
std::string const& outputFile = Mapping->OutputFile;
|
||||
|
||||
// Compose uic command
|
||||
std::vector<std::string> cmd;
|
||||
cmd.push_back(UicConst().Executable);
|
||||
{
|
||||
std::vector<std::string> allOpts = UicConst().TargetOptions;
|
||||
auto optionIt = UicConst().Options.find(sourceFile);
|
||||
if (optionIt != UicConst().Options.end()) {
|
||||
UicMergeOptions(allOpts, optionIt->second,
|
||||
(BaseConst().QtVersionMajor == 5));
|
||||
}
|
||||
cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
|
||||
}
|
||||
cmd.emplace_back("-o");
|
||||
cmd.emplace_back(outputFile);
|
||||
cmd.emplace_back(sourceFile);
|
||||
|
||||
cmWorkerPool::ProcessResultT result;
|
||||
if (RunProcess(GenT::UIC, result, cmd, Reason.get())) {
|
||||
// Uic command success
|
||||
// Print uic output
|
||||
if (!result.StdOut.empty()) {
|
||||
Log().Info(GenT::UIC, result.StdOut);
|
||||
}
|
||||
} else {
|
||||
// Uic command failed
|
||||
std::string msg = "The uic process failed to compile\n ";
|
||||
msg += Quoted(sourceFile);
|
||||
msg += "\ninto\n ";
|
||||
msg += Quoted(outputFile);
|
||||
msg += "\nincluded by\n";
|
||||
for (auto const& item : Mapping->IncluderFiles) {
|
||||
msg += " ";
|
||||
msg += Quoted(item->FileName);
|
||||
msg += '\n';
|
||||
}
|
||||
msg += result.ErrorMessage;
|
||||
LogCommandError(GenT::UIC, msg, cmd, result.StdOut);
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocsCompilationT::Process()
|
||||
{
|
||||
// Compose mocs compilation file content
|
||||
std::string content =
|
||||
"// This file is autogenerated. Changes will be overwritten.\n";
|
||||
if (Gen()->MocAutoFiles().empty()) {
|
||||
|
||||
if (MocEval().CompFiles.empty()) {
|
||||
// Placeholder content
|
||||
content += "// No files found that require moc or the moc files are "
|
||||
"included\n";
|
||||
content += "enum some_compilers { need_more_than_nothing };\n";
|
||||
} else {
|
||||
// Valid content
|
||||
char const sbeg = Gen()->Base().MultiConfig ? '<' : '"';
|
||||
char const send = Gen()->Base().MultiConfig ? '>' : '"';
|
||||
for (std::string const& mocfile : Gen()->MocAutoFiles()) {
|
||||
char const clampB = BaseConst().MultiConfig ? '<' : '"';
|
||||
char const clampE = BaseConst().MultiConfig ? '>' : '"';
|
||||
for (std::string const& mocfile : MocEval().CompFiles) {
|
||||
content += "#include ";
|
||||
content += sbeg;
|
||||
content += clampB;
|
||||
content += mocfile;
|
||||
content += send;
|
||||
content += clampE;
|
||||
content += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& compAbs = Gen()->Moc().CompFileAbs;
|
||||
if (FileSys().FileDiffers(compAbs, content)) {
|
||||
std::string const& compAbs = MocConst().CompFileAbs;
|
||||
if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
|
||||
// Actually write mocs compilation file
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs);
|
||||
}
|
||||
if (!FileSys().FileWrite(compAbs, content)) {
|
||||
if (!FileWrite(compAbs, content)) {
|
||||
LogFileError(GenT::MOC, compAbs,
|
||||
"mocs compilation file writing failed.");
|
||||
}
|
||||
} else if (Gen()->MocAutoFileUpdated()) {
|
||||
} else if (MocEval().CompUpdated) {
|
||||
// Only touch mocs compilation file
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs);
|
||||
}
|
||||
FileSys().Touch(compAbs);
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocT::FindDependencies(std::string const& content)
|
||||
{
|
||||
Gen()->Moc().FindDependencies(content, Depends);
|
||||
DependsValid = true;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocT::Process()
|
||||
{
|
||||
// Compute build file name
|
||||
if (!IncludeString.empty()) {
|
||||
BuildFile = Gen()->Base().AutogenIncludeDir;
|
||||
BuildFile += '/';
|
||||
BuildFile += IncludeString;
|
||||
} else {
|
||||
// Relative build path
|
||||
std::string relPath = FileSys().GetFilePathChecksum(SourceFile);
|
||||
relPath += "/moc_";
|
||||
relPath += FileSys().GetFilenameWithoutLastExtension(SourceFile);
|
||||
|
||||
// Register relative file path with duplication check
|
||||
relPath = Gen()->ParallelMocAutoRegister(relPath);
|
||||
|
||||
// Absolute build path
|
||||
if (Gen()->Base().MultiConfig) {
|
||||
BuildFile = Gen()->Base().AutogenIncludeDir;
|
||||
BuildFile += '/';
|
||||
BuildFile += relPath;
|
||||
} else {
|
||||
BuildFile = Gen()->Base().AbsoluteBuildPath(relPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (UpdateRequired()) {
|
||||
GenerateMoc();
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobMocT::UpdateRequired()
|
||||
{
|
||||
bool const verbose = Log().Verbose();
|
||||
|
||||
// Test if the build file exists
|
||||
if (!FileSys().FileExists(BuildFile)) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " from its source file ";
|
||||
reason += Quoted(SourceFile);
|
||||
reason += " because it doesn't exist";
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if any setting changed
|
||||
if (Gen()->Moc().SettingsChanged) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " from ";
|
||||
reason += Quoted(SourceFile);
|
||||
reason += " because the MOC settings changed";
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the moc_predefs file is newer
|
||||
if (!Gen()->Moc().PredefsFileAbs.empty()) {
|
||||
bool isOlder = false;
|
||||
{
|
||||
std::string error;
|
||||
isOlder = FileSys().FileIsOlderThan(BuildFile,
|
||||
Gen()->Moc().PredefsFileAbs, &error);
|
||||
if (!isOlder && !error.empty()) {
|
||||
LogError(GenT::MOC, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isOlder) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " because it's older than: ";
|
||||
reason += Quoted(Gen()->Moc().PredefsFileAbs);
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the source file is newer
|
||||
{
|
||||
bool isOlder = false;
|
||||
{
|
||||
std::string error;
|
||||
isOlder = FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
|
||||
if (!isOlder && !error.empty()) {
|
||||
LogError(GenT::MOC, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isOlder) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " because it's older than its source file ";
|
||||
reason += Quoted(SourceFile);
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Test if a dependency file is newer
|
||||
{
|
||||
// Read dependencies on demand
|
||||
if (!DependsValid) {
|
||||
std::string content;
|
||||
{
|
||||
std::string error;
|
||||
if (!FileSys().FileRead(content, SourceFile, &error)) {
|
||||
std::string emsg = "Could not read file\n ";
|
||||
emsg += Quoted(SourceFile);
|
||||
emsg += "\nrequired by moc include ";
|
||||
emsg += Quoted(IncludeString);
|
||||
emsg += " in\n ";
|
||||
emsg += Quoted(IncluderFile);
|
||||
emsg += ".\n";
|
||||
emsg += error;
|
||||
LogError(GenT::MOC, emsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
FindDependencies(content);
|
||||
}
|
||||
// Check dependency timestamps
|
||||
std::string error;
|
||||
std::string sourceDir = FileSys().SubDirPrefix(SourceFile);
|
||||
for (std::string const& depFileRel : Depends) {
|
||||
std::string depFileAbs =
|
||||
Gen()->Moc().FindIncludedFile(sourceDir, depFileRel);
|
||||
if (!depFileAbs.empty()) {
|
||||
if (FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " from ";
|
||||
reason += Quoted(SourceFile);
|
||||
reason += " because it is older than it's dependency file ";
|
||||
reason += Quoted(depFileAbs);
|
||||
Log().Info(GenT::MOC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!error.empty()) {
|
||||
LogError(GenT::MOC, error);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::string message = "Could not find dependency file ";
|
||||
message += Quoted(depFileRel);
|
||||
Log().WarningFile(GenT::MOC, SourceFile, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobMocT::GenerateMoc()
|
||||
{
|
||||
// Make sure the parent directory exists
|
||||
if (!FileSys().MakeParentDirectory(BuildFile)) {
|
||||
LogFileError(GenT::MOC, BuildFile, "Could not create parent directory.");
|
||||
return;
|
||||
}
|
||||
{
|
||||
// Compose moc command
|
||||
std::vector<std::string> cmd;
|
||||
cmd.push_back(Gen()->Moc().Executable);
|
||||
// Add options
|
||||
cmd.insert(cmd.end(), Gen()->Moc().AllOptions.begin(),
|
||||
Gen()->Moc().AllOptions.end());
|
||||
// Add predefs include
|
||||
if (!Gen()->Moc().PredefsFileAbs.empty()) {
|
||||
cmd.emplace_back("--include");
|
||||
cmd.push_back(Gen()->Moc().PredefsFileAbs);
|
||||
}
|
||||
cmd.emplace_back("-o");
|
||||
cmd.push_back(BuildFile);
|
||||
cmd.push_back(SourceFile);
|
||||
|
||||
// Execute moc command
|
||||
cmWorkerPool::ProcessResultT result;
|
||||
if (RunProcess(GenT::MOC, result, cmd)) {
|
||||
// Moc command success
|
||||
// Print moc output
|
||||
if (!result.StdOut.empty()) {
|
||||
Log().Info(GenT::MOC, result.StdOut);
|
||||
}
|
||||
// Notify the generator that a not included file changed (on demand)
|
||||
if (IncludeString.empty()) {
|
||||
Gen()->ParallelMocAutoUpdated();
|
||||
}
|
||||
} else {
|
||||
// Moc command failed
|
||||
{
|
||||
std::string emsg = "The moc process failed to compile\n ";
|
||||
emsg += Quoted(SourceFile);
|
||||
emsg += "\ninto\n ";
|
||||
emsg += Quoted(BuildFile);
|
||||
emsg += ".\n";
|
||||
emsg += result.ErrorMessage;
|
||||
LogCommandError(GenT::MOC, emsg, cmd, result.StdOut);
|
||||
}
|
||||
FileSys().FileRemove(BuildFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobUicT::Process()
|
||||
{
|
||||
// Compute build file name
|
||||
BuildFile = Gen()->Base().AutogenIncludeDir;
|
||||
BuildFile += '/';
|
||||
BuildFile += IncludeString;
|
||||
|
||||
if (UpdateRequired()) {
|
||||
GenerateUic();
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::JobUicT::UpdateRequired()
|
||||
{
|
||||
bool const verbose = Log().Verbose();
|
||||
|
||||
// Test if the build file exists
|
||||
if (!FileSys().FileExists(BuildFile)) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " from its source file ";
|
||||
reason += Quoted(SourceFile);
|
||||
reason += " because it doesn't exist";
|
||||
Log().Info(GenT::UIC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the uic settings changed
|
||||
if (Gen()->Uic().SettingsChanged) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " from ";
|
||||
reason += Quoted(SourceFile);
|
||||
reason += " because the UIC settings changed";
|
||||
Log().Info(GenT::UIC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test if the source file is newer
|
||||
{
|
||||
bool isOlder = false;
|
||||
{
|
||||
std::string error;
|
||||
isOlder = FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
|
||||
if (!isOlder && !error.empty()) {
|
||||
LogError(GenT::UIC, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isOlder) {
|
||||
if (verbose) {
|
||||
std::string reason = "Generating ";
|
||||
reason += Quoted(BuildFile);
|
||||
reason += " because it's older than its source file ";
|
||||
reason += Quoted(SourceFile);
|
||||
Log().Info(GenT::UIC, reason);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::JobUicT::GenerateUic()
|
||||
{
|
||||
// Make sure the parent directory exists
|
||||
if (!FileSys().MakeParentDirectory(BuildFile)) {
|
||||
LogFileError(GenT::UIC, BuildFile, "Could not create parent directory.");
|
||||
return;
|
||||
}
|
||||
{
|
||||
// Compose uic command
|
||||
std::vector<std::string> cmd;
|
||||
cmd.push_back(Gen()->Uic().Executable);
|
||||
{
|
||||
std::vector<std::string> allOpts = Gen()->Uic().TargetOptions;
|
||||
auto optionIt = Gen()->Uic().Options.find(SourceFile);
|
||||
if (optionIt != Gen()->Uic().Options.end()) {
|
||||
UicMergeOptions(allOpts, optionIt->second,
|
||||
(Gen()->Base().QtVersionMajor == 5));
|
||||
}
|
||||
cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
|
||||
}
|
||||
cmd.emplace_back("-o");
|
||||
cmd.emplace_back(BuildFile);
|
||||
cmd.emplace_back(SourceFile);
|
||||
|
||||
cmWorkerPool::ProcessResultT result;
|
||||
if (RunProcess(GenT::UIC, result, cmd)) {
|
||||
// Uic command success
|
||||
// Print uic output
|
||||
if (!result.StdOut.empty()) {
|
||||
Log().Info(GenT::UIC, result.StdOut);
|
||||
}
|
||||
} else {
|
||||
// Uic command failed
|
||||
{
|
||||
std::string emsg = "The uic process failed to compile\n ";
|
||||
emsg += Quoted(SourceFile);
|
||||
emsg += "\ninto\n ";
|
||||
emsg += Quoted(BuildFile);
|
||||
emsg += "\nincluded by\n ";
|
||||
emsg += Quoted(IncluderFile);
|
||||
emsg += ".\n";
|
||||
emsg += result.ErrorMessage;
|
||||
LogCommandError(GenT::UIC, emsg, cmd, result.StdOut);
|
||||
}
|
||||
FileSys().FileRemove(BuildFile);
|
||||
if (!cmSystemTools::Touch(compAbs, false)) {
|
||||
LogFileError(GenT::MOC, compAbs,
|
||||
"mocs compilation file touching failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1092,25 +1533,11 @@ void cmQtAutoMocUic::JobFinishT::Process()
|
||||
Gen()->AbortSuccess();
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::cmQtAutoMocUic()
|
||||
: Base_(&FileSys())
|
||||
, Moc_(&FileSys())
|
||||
{
|
||||
// Precompile regular expressions
|
||||
Moc_.RegExpInclude.compile(
|
||||
"(^|\n)[ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
||||
Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
|
||||
"[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
|
||||
}
|
||||
|
||||
cmQtAutoMocUic::cmQtAutoMocUic() = default;
|
||||
cmQtAutoMocUic::~cmQtAutoMocUic() = default;
|
||||
|
||||
bool cmQtAutoMocUic::Init(cmMakefile* makefile)
|
||||
{
|
||||
// -- Meta
|
||||
Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
|
||||
|
||||
// Utility lambdas
|
||||
auto InfoGet = [makefile](const char* key) {
|
||||
return makefile->GetSafeDefinition(key);
|
||||
@@ -1169,171 +1596,185 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
|
||||
cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
|
||||
return list;
|
||||
};
|
||||
auto LogInfoError = [this](std::string const& msg) -> bool {
|
||||
std::ostringstream err;
|
||||
err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
|
||||
this->Log().Error(GenT::GEN, err.str());
|
||||
return false;
|
||||
};
|
||||
auto MatchSizes = [&LogInfoError](const char* keyA, const char* keyB,
|
||||
std::size_t sizeA,
|
||||
std::size_t sizeB) -> bool {
|
||||
if (sizeA == sizeB) {
|
||||
return true;
|
||||
}
|
||||
std::ostringstream err;
|
||||
err << "Lists sizes mismatch " << keyA << '(' << sizeA << ") " << keyB
|
||||
<< '(' << sizeB << ')';
|
||||
return LogInfoError(err.str());
|
||||
};
|
||||
|
||||
// -- Read info file
|
||||
if (!makefile->ReadListFile(InfoFile())) {
|
||||
Log().ErrorFile(GenT::GEN, InfoFile(), "File processing failed");
|
||||
return false;
|
||||
return LogInfoError("File processing failed");
|
||||
}
|
||||
|
||||
// -- Meta
|
||||
Log().RaiseVerbosity(InfoGet("AM_VERBOSITY"));
|
||||
Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
|
||||
Logger_.RaiseVerbosity(InfoGet("AM_VERBOSITY"));
|
||||
BaseConst_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
|
||||
{
|
||||
unsigned long num = Base_.NumThreads;
|
||||
unsigned long num = 1;
|
||||
if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
|
||||
num = std::max<unsigned long>(num, 1);
|
||||
num = std::min<unsigned long>(num, ParallelMax);
|
||||
Base_.NumThreads = static_cast<unsigned int>(num);
|
||||
}
|
||||
WorkerPool_.SetThreadCount(Base_.NumThreads);
|
||||
WorkerPool_.SetThreadCount(static_cast<unsigned int>(num));
|
||||
}
|
||||
BaseConst_.HeaderExtensions =
|
||||
makefile->GetCMakeInstance()->GetHeaderExtensions();
|
||||
|
||||
// - Files and directories
|
||||
Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
|
||||
Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
|
||||
Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
|
||||
Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
|
||||
Base_.IncludeProjectDirsBefore =
|
||||
BaseConst_.IncludeProjectDirsBefore =
|
||||
InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
|
||||
Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
|
||||
if (Base_.AutogenBuildDir.empty()) {
|
||||
Log().ErrorFile(GenT::GEN, InfoFile(), "Autogen build directory missing");
|
||||
return false;
|
||||
BaseConst_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
|
||||
BaseConst_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
|
||||
BaseConst_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
|
||||
BaseConst_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
|
||||
BaseConst_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
|
||||
if (BaseConst_.AutogenBuildDir.empty()) {
|
||||
return LogInfoError("Autogen build directory missing.");
|
||||
}
|
||||
// include directory
|
||||
Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
|
||||
if (Base_.AutogenIncludeDir.empty()) {
|
||||
Log().ErrorFile(GenT::GEN, InfoFile(),
|
||||
"Autogen include directory missing");
|
||||
return false;
|
||||
BaseConst_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
|
||||
if (BaseConst_.AutogenIncludeDir.empty()) {
|
||||
return LogInfoError("Autogen include directory missing.");
|
||||
}
|
||||
BaseConst_.CMakeExecutable = InfoGetConfig("AM_CMAKE_EXECUTABLE");
|
||||
if (BaseConst_.CMakeExecutable.empty()) {
|
||||
return LogInfoError("CMake executable file name missing.");
|
||||
}
|
||||
if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) {
|
||||
std::string error = "The CMake executable ";
|
||||
error += Quoted(BaseConst_.CMakeExecutable);
|
||||
error += " does not exist.";
|
||||
return LogInfoError(error);
|
||||
}
|
||||
BaseConst_.ParseCacheFile = InfoGetConfig("AM_PARSE_CACHE_FILE");
|
||||
if (BaseConst_.ParseCacheFile.empty()) {
|
||||
return LogInfoError("Parse cache file name missing.");
|
||||
}
|
||||
|
||||
// - Files
|
||||
// - Settings file
|
||||
SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
|
||||
if (SettingsFile_.empty()) {
|
||||
Log().ErrorFile(GenT::GEN, InfoFile(), "Settings file name missing");
|
||||
return false;
|
||||
return LogInfoError("Settings file name missing.");
|
||||
}
|
||||
|
||||
// - Qt environment
|
||||
{
|
||||
unsigned long qtv = Base_.QtVersionMajor;
|
||||
unsigned long qtv = BaseConst_.QtVersionMajor;
|
||||
if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
|
||||
&qtv)) {
|
||||
Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
|
||||
BaseConst_.QtVersionMajor = static_cast<unsigned int>(qtv);
|
||||
}
|
||||
}
|
||||
|
||||
// - Moc
|
||||
Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
|
||||
Moc_.Enabled = !Moc().Executable.empty();
|
||||
if (Moc().Enabled) {
|
||||
for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
|
||||
Moc_.SkipList.insert(std::move(sfl));
|
||||
MocConst_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
|
||||
if (!MocConst().Executable.empty()) {
|
||||
MocConst_.Enabled = true;
|
||||
// Load the executable file time
|
||||
if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) {
|
||||
std::string error = "The moc executable ";
|
||||
error += Quoted(MocConst_.Executable);
|
||||
error += " does not exist.";
|
||||
return LogInfoError(error);
|
||||
}
|
||||
Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
|
||||
Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
|
||||
Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
|
||||
Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
|
||||
for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
|
||||
MocConst_.SkipList.insert(std::move(sfl));
|
||||
}
|
||||
MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
|
||||
MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
|
||||
MocConst_.Options = InfoGetList("AM_MOC_OPTIONS");
|
||||
MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
|
||||
for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
|
||||
Moc_.MacroFilters.emplace_back(
|
||||
MocConst_.MacroFilters.emplace_back(
|
||||
item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
|
||||
}
|
||||
{
|
||||
auto pushFilter = [this](std::string const& key, std::string const& exp,
|
||||
std::string& error) {
|
||||
if (!key.empty()) {
|
||||
if (!exp.empty()) {
|
||||
Moc_.DependFilters.emplace_back();
|
||||
KeyExpT& filter(Moc_.DependFilters.back());
|
||||
if (filter.Exp.compile(exp)) {
|
||||
filter.Key = key;
|
||||
} else {
|
||||
error = "Regular expression compiling failed";
|
||||
}
|
||||
} else {
|
||||
error = "Regular expression is empty";
|
||||
}
|
||||
} else {
|
||||
error = "Key is empty";
|
||||
auto addFilter = [this, &LogInfoError](std::string const& key,
|
||||
std::string const& exp) -> bool {
|
||||
auto filterErr = [&LogInfoError, &key, &exp](const char* err) -> bool {
|
||||
std::ostringstream ferr;
|
||||
ferr << "AUTOMOC_DEPEND_FILTERS: " << err << '\n';
|
||||
ferr << " Key: " << Quoted(key) << '\n';
|
||||
ferr << " Exp: " << Quoted(exp) << '\n';
|
||||
return LogInfoError(ferr.str());
|
||||
};
|
||||
if (key.empty()) {
|
||||
return filterErr("Key is empty");
|
||||
}
|
||||
if (!error.empty()) {
|
||||
error = ("AUTOMOC_DEPEND_FILTERS: " + error);
|
||||
error += "\n";
|
||||
error += " Key: ";
|
||||
error += Quoted(key);
|
||||
error += "\n";
|
||||
error += " Exp: ";
|
||||
error += Quoted(exp);
|
||||
error += "\n";
|
||||
if (exp.empty()) {
|
||||
return filterErr("Regular expression is empty");
|
||||
}
|
||||
this->MocConst_.DependFilters.emplace_back(key, exp);
|
||||
if (!this->MocConst_.DependFilters.back().Exp.is_valid()) {
|
||||
return filterErr("Regular expression compiling failed");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
std::string error;
|
||||
// Insert default filter for Q_PLUGIN_METADATA
|
||||
if (Base().QtVersionMajor != 4) {
|
||||
pushFilter("Q_PLUGIN_METADATA",
|
||||
"[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
|
||||
"[^\\)]*FILE[ \t]*\"([^\"]+)\"",
|
||||
error);
|
||||
}
|
||||
// Insert user defined dependency filters
|
||||
{
|
||||
std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
|
||||
if ((flts.size() % 2) == 0) {
|
||||
for (std::vector<std::string>::iterator itC = flts.begin(),
|
||||
itE = flts.end();
|
||||
itC != itE; itC += 2) {
|
||||
pushFilter(*itC, *(itC + 1), error);
|
||||
if (!error.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log().ErrorFile(
|
||||
GenT::MOC, InfoFile(),
|
||||
"AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
|
||||
if (BaseConst().QtVersionMajor != 4) {
|
||||
if (!addFilter("Q_PLUGIN_METADATA",
|
||||
"[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
|
||||
"[^\\)]*FILE[ \t]*\"([^\"]+)\"")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!error.empty()) {
|
||||
Log().ErrorFile(GenT::MOC, InfoFile(), error);
|
||||
return false;
|
||||
// Insert user defined dependency filters
|
||||
std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
|
||||
if ((flts.size() % 2) != 0) {
|
||||
return LogInfoError(
|
||||
"AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
|
||||
}
|
||||
for (auto itC = flts.begin(), itE = flts.end(); itC != itE; itC += 2) {
|
||||
if (!addFilter(*itC, *(itC + 1))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
|
||||
// Install moc predefs job
|
||||
if (!Moc().PredefsCmd.empty()) {
|
||||
WorkerPool().EmplaceJob<JobMocPredefsT>();
|
||||
}
|
||||
MocConst_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
|
||||
}
|
||||
|
||||
// - Uic
|
||||
Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
|
||||
Uic_.Enabled = !Uic().Executable.empty();
|
||||
if (Uic().Enabled) {
|
||||
for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
|
||||
Uic_.SkipList.insert(std::move(sfl));
|
||||
UicConst_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
|
||||
if (!UicConst().Executable.empty()) {
|
||||
UicConst_.Enabled = true;
|
||||
// Load the executable file time
|
||||
if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) {
|
||||
std::string error = "The uic executable ";
|
||||
error += Quoted(UicConst_.Executable);
|
||||
error += " does not exist.";
|
||||
return LogInfoError(error);
|
||||
}
|
||||
Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
|
||||
Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
|
||||
for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
|
||||
UicConst_.SkipList.insert(std::move(sfl));
|
||||
}
|
||||
UicConst_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
|
||||
UicConst_.TargetOptions = 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() << ")";
|
||||
Log().ErrorFile(GenT::UIC, InfoFile(), ost.str());
|
||||
const char* keyFiles = "AM_UIC_OPTIONS_FILES";
|
||||
const char* keyOpts = "AM_UIC_OPTIONS_OPTIONS";
|
||||
auto sources = InfoGetList(keyFiles);
|
||||
auto options = InfoGetLists(keyOpts);
|
||||
if (!MatchSizes(keyFiles, keyOpts, sources.size(), options.size())) {
|
||||
return false;
|
||||
}
|
||||
auto fitEnd = sources.cend();
|
||||
auto fit = sources.begin();
|
||||
auto oit = options.begin();
|
||||
while (fit != fitEnd) {
|
||||
Uic_.Options[*fit] = std::move(*oit);
|
||||
UicConst_.Options[*fit] = std::move(*oit);
|
||||
++fit;
|
||||
++oit;
|
||||
}
|
||||
@@ -1341,92 +1782,121 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
|
||||
}
|
||||
|
||||
// - Headers and sources
|
||||
// Add sources
|
||||
{
|
||||
auto addSource = [this](std::string&& src, bool moc, bool uic) {
|
||||
WorkerPool().EmplaceJob<JobParseT>(std::move(src), moc, uic, false);
|
||||
auto makeSource =
|
||||
[&LogInfoError](std::string const& fileName,
|
||||
std::string const& fileFlags) -> SourceFileHandleT {
|
||||
if (fileFlags.size() != 2) {
|
||||
LogInfoError("Invalid file flags string size");
|
||||
return SourceFileHandleT();
|
||||
}
|
||||
cmFileTime fileTime;
|
||||
if (!fileTime.Load(fileName)) {
|
||||
LogInfoError("The source file " + cmQtAutoGen::Quoted(fileName) +
|
||||
" does not exist.");
|
||||
return SourceFileHandleT();
|
||||
}
|
||||
SourceFileHandleT sfh = std::make_shared<SourceFileT>(fileName);
|
||||
sfh->FileTime = fileTime;
|
||||
sfh->Moc = (fileFlags[0] == 'M');
|
||||
sfh->Uic = (fileFlags[1] == 'U');
|
||||
return sfh;
|
||||
};
|
||||
for (std::string& src : InfoGetList("AM_SOURCES")) {
|
||||
addSource(std::move(src), true, true);
|
||||
}
|
||||
if (Moc().Enabled) {
|
||||
for (std::string& src : InfoGetList("AM_MOC_SOURCES")) {
|
||||
addSource(std::move(src), true, false);
|
||||
|
||||
// Headers
|
||||
{
|
||||
// Get file lists
|
||||
const char *keyFiles = "AM_HEADERS", *keyFlags = "AM_HEADERS_FLAGS";
|
||||
std::vector<std::string> files = InfoGetList(keyFiles);
|
||||
std::vector<std::string> flags = InfoGetList(keyFlags);
|
||||
std::vector<std::string> builds;
|
||||
if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
|
||||
return false;
|
||||
}
|
||||
if (MocConst().Enabled) {
|
||||
const char* keyPaths = "AM_HEADERS_BUILD_PATHS";
|
||||
builds = InfoGetList(keyPaths);
|
||||
if (!MatchSizes(keyFiles, keyPaths, files.size(), builds.size())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Process file lists
|
||||
for (std::size_t ii = 0; ii != files.size(); ++ii) {
|
||||
std::string& fileName(files[ii]);
|
||||
SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
|
||||
if (!sfh) {
|
||||
return false;
|
||||
}
|
||||
if (MocConst().Enabled) {
|
||||
sfh->BuildPath = std::move(builds[ii]);
|
||||
if (sfh->BuildPath.empty()) {
|
||||
Log().ErrorFile(GenT::GEN, this->InfoFile(),
|
||||
"Header file build path is empty");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BaseEval().Headers.emplace(std::move(fileName), std::move(sfh));
|
||||
}
|
||||
}
|
||||
if (Uic().Enabled) {
|
||||
for (std::string& src : InfoGetList("AM_UIC_SOURCES")) {
|
||||
addSource(std::move(src), false, true);
|
||||
|
||||
// Sources
|
||||
{
|
||||
const char *keyFiles = "AM_SOURCES", *keyFlags = "AM_SOURCES_FLAGS";
|
||||
std::vector<std::string> files = InfoGetList(keyFiles);
|
||||
std::vector<std::string> flags = InfoGetList(keyFlags);
|
||||
if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
|
||||
return false;
|
||||
}
|
||||
// Process file lists
|
||||
for (std::size_t ii = 0; ii != files.size(); ++ii) {
|
||||
std::string& fileName(files[ii]);
|
||||
SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
|
||||
if (!sfh) {
|
||||
return false;
|
||||
}
|
||||
BaseEval().Sources.emplace(std::move(fileName), std::move(sfh));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add Fence job
|
||||
WorkerPool().EmplaceJob<JobFenceT>();
|
||||
// Add headers
|
||||
{
|
||||
auto addHeader = [this](std::string&& hdr, bool moc, bool uic) {
|
||||
WorkerPool().EmplaceJob<JobParseT>(std::move(hdr), moc, uic, true);
|
||||
};
|
||||
for (std::string& hdr : InfoGetList("AM_HEADERS")) {
|
||||
addHeader(std::move(hdr), true, true);
|
||||
}
|
||||
if (Moc().Enabled) {
|
||||
for (std::string& hdr : InfoGetList("AM_MOC_HEADERS")) {
|
||||
addHeader(std::move(hdr), true, false);
|
||||
}
|
||||
}
|
||||
if (Uic().Enabled) {
|
||||
for (std::string& hdr : InfoGetList("AM_UIC_HEADERS")) {
|
||||
addHeader(std::move(hdr), false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Addpost parse fence job
|
||||
WorkerPool().EmplaceJob<JobPostParseT>();
|
||||
|
||||
// Init derived information
|
||||
// ------------------------
|
||||
|
||||
// Init file path checksum generator
|
||||
FileSys().setupFilePathChecksum(
|
||||
Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
|
||||
Base().ProjectBinaryDir);
|
||||
|
||||
// Moc variables
|
||||
if (Moc().Enabled) {
|
||||
if (MocConst().Enabled) {
|
||||
// Mocs compilation file
|
||||
Moc_.CompFileAbs = Base().AbsoluteBuildPath("mocs_compilation.cpp");
|
||||
MocConst_.CompFileAbs = AbsoluteBuildPath("mocs_compilation.cpp");
|
||||
|
||||
// Moc predefs file
|
||||
if (!Moc_.PredefsCmd.empty()) {
|
||||
Moc_.PredefsFileRel = "moc_predefs";
|
||||
if (Base_.MultiConfig) {
|
||||
Moc_.PredefsFileRel += '_';
|
||||
Moc_.PredefsFileRel += InfoConfig();
|
||||
if (!MocConst_.PredefsCmd.empty()) {
|
||||
MocConst_.PredefsFileRel = "moc_predefs";
|
||||
if (BaseConst_.MultiConfig) {
|
||||
MocConst_.PredefsFileRel += '_';
|
||||
MocConst_.PredefsFileRel += InfoConfig();
|
||||
}
|
||||
Moc_.PredefsFileRel += ".h";
|
||||
Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
|
||||
MocConst_.PredefsFileRel += ".h";
|
||||
MocConst_.PredefsFileAbs = AbsoluteBuildPath(MocConst().PredefsFileRel);
|
||||
}
|
||||
|
||||
// Sort include directories on demand
|
||||
if (Base().IncludeProjectDirsBefore) {
|
||||
if (BaseConst().IncludeProjectDirsBefore) {
|
||||
// Move strings to temporary list
|
||||
std::list<std::string> includes;
|
||||
includes.insert(includes.end(), Moc().IncludePaths.begin(),
|
||||
Moc().IncludePaths.end());
|
||||
Moc_.IncludePaths.clear();
|
||||
Moc_.IncludePaths.reserve(includes.size());
|
||||
includes.insert(includes.end(), MocConst().IncludePaths.begin(),
|
||||
MocConst().IncludePaths.end());
|
||||
MocConst_.IncludePaths.clear();
|
||||
MocConst_.IncludePaths.reserve(includes.size());
|
||||
// Append project directories only
|
||||
{
|
||||
std::array<std::string const*, 2> const movePaths = {
|
||||
{ &Base().ProjectBinaryDir, &Base().ProjectSourceDir }
|
||||
{ &BaseConst().ProjectBinaryDir, &BaseConst().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())) {
|
||||
Moc_.IncludePaths.push_back(path);
|
||||
MocConst_.IncludePaths.push_back(path);
|
||||
it = includes.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
@@ -1435,124 +1905,176 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
|
||||
}
|
||||
}
|
||||
// Append remaining directories
|
||||
Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(),
|
||||
includes.end());
|
||||
MocConst_.IncludePaths.insert(MocConst_.IncludePaths.end(),
|
||||
includes.begin(), includes.end());
|
||||
}
|
||||
// Compose moc includes list
|
||||
{
|
||||
std::set<std::string> frameworkPaths;
|
||||
for (std::string const& path : Moc().IncludePaths) {
|
||||
Moc_.Includes.push_back("-I" + path);
|
||||
for (std::string const& path : MocConst().IncludePaths) {
|
||||
MocConst_.Includes.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;
|
||||
FileSys().SplitPath(path, pathComponents);
|
||||
std::string frameworkPath = FileSys().JoinPath(
|
||||
pathComponents.begin(), pathComponents.end() - 2);
|
||||
frameworkPaths.insert(frameworkPath);
|
||||
cmSystemTools::SplitPath(path, pathComponents);
|
||||
frameworkPaths.emplace(cmSystemTools::JoinPath(
|
||||
pathComponents.begin(), pathComponents.end() - 2));
|
||||
}
|
||||
}
|
||||
// Append framework includes
|
||||
for (std::string const& path : frameworkPaths) {
|
||||
Moc_.Includes.emplace_back("-F");
|
||||
Moc_.Includes.push_back(path);
|
||||
MocConst_.Includes.emplace_back("-F");
|
||||
MocConst_.Includes.push_back(path);
|
||||
}
|
||||
}
|
||||
// Setup single list with all options
|
||||
{
|
||||
// Add includes
|
||||
Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
|
||||
Moc().Includes.end());
|
||||
MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
|
||||
MocConst().Includes.begin(),
|
||||
MocConst().Includes.end());
|
||||
// Add definitions
|
||||
for (std::string const& def : Moc().Definitions) {
|
||||
Moc_.AllOptions.push_back("-D" + def);
|
||||
for (std::string const& def : MocConst().Definitions) {
|
||||
MocConst_.AllOptions.push_back("-D" + def);
|
||||
}
|
||||
// Add options
|
||||
Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
|
||||
Moc().Options.end());
|
||||
MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
|
||||
MocConst().Options.begin(),
|
||||
MocConst().Options.end());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class JOBTYPE>
|
||||
void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap)
|
||||
{
|
||||
cmFileTime const parseCacheTime = BaseEval().ParseCacheTime;
|
||||
ParseCacheT& parseCache = BaseEval().ParseCache;
|
||||
for (auto& src : sourceMap) {
|
||||
// Get or create the file parse data reference
|
||||
ParseCacheT::GetOrInsertT cacheEntry = parseCache.GetOrInsert(src.first);
|
||||
src.second->ParseData = std::move(cacheEntry.first);
|
||||
// Create a parse job if the cache file was missing or is older
|
||||
if (cacheEntry.second || src.second->FileTime.Newer(parseCacheTime)) {
|
||||
BaseEval().ParseCacheChanged = true;
|
||||
WorkerPool().EmplaceJob<JOBTYPE>(src.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::InitJobs()
|
||||
{
|
||||
// Add moc_predefs.h job
|
||||
if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) {
|
||||
WorkerPool().EmplaceJob<JobMocPredefsT>();
|
||||
}
|
||||
// Add header parse jobs
|
||||
CreateParseJobs<JobParseHeaderT>(BaseEval().Headers);
|
||||
// Add source parse jobs
|
||||
CreateParseJobs<JobParseSourceT>(BaseEval().Sources);
|
||||
// Add evaluate job
|
||||
WorkerPool().EmplaceJob<JobEvaluateT>();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::Process()
|
||||
{
|
||||
SettingsFileRead();
|
||||
ParseCacheRead();
|
||||
if (!CreateDirectories()) {
|
||||
return false;
|
||||
}
|
||||
InitJobs();
|
||||
if (!WorkerPool_.Process(this)) {
|
||||
return false;
|
||||
}
|
||||
if (JobError_) {
|
||||
return false;
|
||||
}
|
||||
return SettingsFileWrite();
|
||||
if (!ParseCacheWrite()) {
|
||||
return false;
|
||||
}
|
||||
if (!SettingsFileWrite()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::SettingsFileRead()
|
||||
{
|
||||
// Compose current settings strings
|
||||
{
|
||||
cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
|
||||
std::string const sep(" ~~~ ");
|
||||
if (Moc_.Enabled) {
|
||||
std::string str;
|
||||
str += Moc().Executable;
|
||||
str += sep;
|
||||
str += cmJoin(Moc().AllOptions, ";");
|
||||
str += sep;
|
||||
str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE";
|
||||
str += sep;
|
||||
str += cmJoin(Moc().PredefsCmd, ";");
|
||||
str += sep;
|
||||
SettingsStringMoc_ = crypt.HashString(str);
|
||||
}
|
||||
if (Uic().Enabled) {
|
||||
std::string str;
|
||||
str += Uic().Executable;
|
||||
str += sep;
|
||||
str += cmJoin(Uic().TargetOptions, ";");
|
||||
for (const auto& item : Uic().Options) {
|
||||
str += sep;
|
||||
str += item.first;
|
||||
str += sep;
|
||||
str += cmJoin(item.second, ";");
|
||||
cmCryptoHash cryptoHash(cmCryptoHash::AlgoSHA256);
|
||||
std::string const sep(";");
|
||||
auto cha = [&cryptoHash, &sep](std::string const& value) {
|
||||
cryptoHash.Append(value);
|
||||
cryptoHash.Append(sep);
|
||||
};
|
||||
|
||||
if (MocConst_.Enabled) {
|
||||
cryptoHash.Initialize();
|
||||
cha(MocConst().Executable);
|
||||
for (auto const& value : MocConst().AllOptions) {
|
||||
cha(value);
|
||||
}
|
||||
str += sep;
|
||||
SettingsStringUic_ = crypt.HashString(str);
|
||||
cha(BaseConst().IncludeProjectDirsBefore ? "TRUE" : "FALSE");
|
||||
for (auto const& value : MocConst().PredefsCmd) {
|
||||
cha(value);
|
||||
}
|
||||
for (auto const& filter : MocConst().DependFilters) {
|
||||
cha(filter.Key);
|
||||
}
|
||||
for (auto const& filter : MocConst().MacroFilters) {
|
||||
cha(filter.Key);
|
||||
}
|
||||
SettingsStringMoc_ = cryptoHash.FinalizeHex();
|
||||
}
|
||||
|
||||
if (UicConst().Enabled) {
|
||||
cryptoHash.Initialize();
|
||||
cha(UicConst().Executable);
|
||||
for (auto const& value : UicConst().TargetOptions) {
|
||||
cha(value);
|
||||
}
|
||||
for (const auto& item : UicConst().Options) {
|
||||
cha(item.first);
|
||||
for (auto const& svalue : item.second) {
|
||||
cha(svalue);
|
||||
}
|
||||
}
|
||||
SettingsStringUic_ = cryptoHash.FinalizeHex();
|
||||
}
|
||||
}
|
||||
|
||||
// Read old settings and compare
|
||||
{
|
||||
std::string content;
|
||||
if (FileSys().FileRead(content, SettingsFile_)) {
|
||||
if (Moc().Enabled) {
|
||||
if (cmQtAutoGenerator::FileRead(content, SettingsFile_)) {
|
||||
if (MocConst().Enabled) {
|
||||
if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
|
||||
Moc_.SettingsChanged = true;
|
||||
MocConst_.SettingsChanged = true;
|
||||
}
|
||||
}
|
||||
if (Uic().Enabled) {
|
||||
if (UicConst().Enabled) {
|
||||
if (SettingsStringUic_ != SettingsFind(content, "uic")) {
|
||||
Uic_.SettingsChanged = true;
|
||||
UicConst_.SettingsChanged = 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 (Moc().SettingsChanged || Uic().SettingsChanged) {
|
||||
FileSys().FileRemove(SettingsFile_);
|
||||
if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
|
||||
cmSystemTools::RemoveFile(SettingsFile_);
|
||||
}
|
||||
} else {
|
||||
// Settings file read failed
|
||||
if (Moc().Enabled) {
|
||||
Moc_.SettingsChanged = true;
|
||||
if (MocConst().Enabled) {
|
||||
MocConst_.SettingsChanged = true;
|
||||
}
|
||||
if (Uic().Enabled) {
|
||||
Uic_.SettingsChanged = true;
|
||||
if (UicConst().Enabled) {
|
||||
UicConst_.SettingsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1561,7 +2083,7 @@ void cmQtAutoMocUic::SettingsFileRead()
|
||||
bool cmQtAutoMocUic::SettingsFileWrite()
|
||||
{
|
||||
// Only write if any setting changed
|
||||
if (Moc().SettingsChanged || Uic().SettingsChanged) {
|
||||
if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_));
|
||||
}
|
||||
@@ -1582,11 +2104,54 @@ bool cmQtAutoMocUic::SettingsFileWrite()
|
||||
}
|
||||
// Write settings file
|
||||
std::string error;
|
||||
if (!FileSys().FileWrite(SettingsFile_, content, &error)) {
|
||||
if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) {
|
||||
Log().ErrorFile(GenT::GEN, SettingsFile_,
|
||||
"Settings file writing failed. " + error);
|
||||
// Remove old settings file to trigger a full rebuild on the next run
|
||||
FileSys().FileRemove(SettingsFile_);
|
||||
cmSystemTools::RemoveFile(SettingsFile_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmQtAutoMocUic::ParseCacheRead()
|
||||
{
|
||||
const char* reason = nullptr;
|
||||
// Don't read the cache if it is invalid
|
||||
if (!BaseEval().ParseCacheTime.Load(BaseConst().ParseCacheFile)) {
|
||||
reason = "Refreshing parse cache because it doesn't exist.";
|
||||
} else if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
|
||||
reason = "Refreshing parse cache because the settings changed.";
|
||||
} else if (BaseEval().ParseCacheTime.Older(
|
||||
BaseConst().CMakeExecutableTime)) {
|
||||
reason =
|
||||
"Refreshing parse cache because it is older than the CMake executable.";
|
||||
}
|
||||
|
||||
if (reason != nullptr) {
|
||||
// Don't read but refresh the complete parse cache
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::GEN, reason);
|
||||
}
|
||||
BaseEval().ParseCacheChanged = true;
|
||||
} else {
|
||||
// Read parse cache
|
||||
BaseEval().ParseCache.ReadFromFile(BaseConst().ParseCacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParseCacheWrite()
|
||||
{
|
||||
if (BaseEval().ParseCacheChanged) {
|
||||
if (Log().Verbose()) {
|
||||
Log().Info(GenT::GEN,
|
||||
"Writing parse cache file " +
|
||||
Quoted(BaseConst().ParseCacheFile));
|
||||
}
|
||||
if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) {
|
||||
Log().ErrorFile(GenT::GEN, BaseConst().ParseCacheFile,
|
||||
"Parse cache file writing failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1596,16 +2161,14 @@ bool cmQtAutoMocUic::SettingsFileWrite()
|
||||
bool cmQtAutoMocUic::CreateDirectories()
|
||||
{
|
||||
// Create AUTOGEN include directory
|
||||
if (!FileSys().MakeDirectory(Base().AutogenIncludeDir)) {
|
||||
Log().ErrorFile(GenT::GEN, Base().AutogenIncludeDir,
|
||||
if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) {
|
||||
Log().ErrorFile(GenT::GEN, BaseConst().AutogenIncludeDir,
|
||||
"Could not create directory.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Private method that requires cmQtAutoMocUic::JobsMutex_ to be
|
||||
// locked
|
||||
void cmQtAutoMocUic::Abort(bool error)
|
||||
{
|
||||
if (error) {
|
||||
@@ -1614,132 +2177,20 @@ void cmQtAutoMocUic::Abort(bool error)
|
||||
WorkerPool_.Abort();
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParallelJobPushMoc(cmWorkerPool::JobHandleT&& jobHandle)
|
||||
std::string cmQtAutoMocUic::AbsoluteBuildPath(
|
||||
std::string const& relativePath) const
|
||||
{
|
||||
JobMocT const& mocJob(static_cast<JobMocT&>(*jobHandle));
|
||||
// Do additional tests if this is an included moc job
|
||||
if (!mocJob.IncludeString.empty()) {
|
||||
std::lock_guard<std::mutex> guard(MocMetaMutex_);
|
||||
// Register included moc file
|
||||
MocIncludedFiles_.emplace(mocJob.SourceFile);
|
||||
|
||||
// Check if the same moc file would be generated from a different
|
||||
// source file.
|
||||
auto const range = MocIncludes_.equal_range(mocJob.IncludeString);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second[0] == mocJob.SourceFile) {
|
||||
// The output file already gets generated
|
||||
return true;
|
||||
}
|
||||
{
|
||||
// The output file already gets generated - from a different source
|
||||
// file!
|
||||
std::string error = "The two source files\n ";
|
||||
error += Quoted(mocJob.IncluderFile);
|
||||
error += " and\n ";
|
||||
error += Quoted(it->second[1]);
|
||||
error += "\ncontain the same moc include string ";
|
||||
error += Quoted(mocJob.IncludeString);
|
||||
error += "\nbut the moc file would be generated from different "
|
||||
"source files\n ";
|
||||
error += Quoted(mocJob.SourceFile);
|
||||
error += " and\n ";
|
||||
error += Quoted(it->second[0]);
|
||||
error += ".\nConsider 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";
|
||||
Log().Error(GenT::MOC, error);
|
||||
AbortError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We're still here so register this job
|
||||
MocIncludes_.emplace_hint(range.first, mocJob.IncludeString,
|
||||
std::array<std::string, 2>{
|
||||
{ mocJob.SourceFile, mocJob.IncluderFile } });
|
||||
}
|
||||
return WorkerPool_.PushJob(std::move(jobHandle));
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParallelJobPushUic(cmWorkerPool::JobHandleT&& jobHandle)
|
||||
{
|
||||
const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(UicMetaMutex_);
|
||||
// Check if the same uic file would be generated from a different
|
||||
// source file.
|
||||
auto const range = UicIncludes_.equal_range(uicJob.IncludeString);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second[0] == uicJob.SourceFile) {
|
||||
// The output file already gets generated
|
||||
return true;
|
||||
}
|
||||
{
|
||||
// The output file already gets generated - from a different .ui
|
||||
// file!
|
||||
std::string error = "The two source files\n ";
|
||||
error += Quoted(uicJob.IncluderFile);
|
||||
error += " and\n ";
|
||||
error += Quoted(it->second[1]);
|
||||
error += "\ncontain the same uic include string ";
|
||||
error += Quoted(uicJob.IncludeString);
|
||||
error += "\nbut the uic file would be generated from different "
|
||||
"source files\n ";
|
||||
error += Quoted(uicJob.SourceFile);
|
||||
error += " and\n ";
|
||||
error += Quoted(it->second[0]);
|
||||
error +=
|
||||
".\nConsider 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";
|
||||
Log().Error(GenT::UIC, error);
|
||||
AbortError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We're still here so register this job
|
||||
UicIncludes_.emplace_hint(range.first, uicJob.IncludeString,
|
||||
std::array<std::string, 2>{
|
||||
{ uicJob.SourceFile, uicJob.IncluderFile } });
|
||||
}
|
||||
return WorkerPool_.PushJob(std::move(jobHandle));
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUic::ParallelMocIncluded(std::string const& sourceFile)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(MocMetaMutex_);
|
||||
return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
|
||||
std::string res(BaseConst().AutogenBuildDir);
|
||||
res += '/';
|
||||
res += relativePath;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string cmQtAutoMocUic::ParallelMocAutoRegister(
|
||||
std::string const& baseName)
|
||||
std::string cmQtAutoMocUic::AbsoluteIncludePath(
|
||||
std::string const& relativePath) const
|
||||
{
|
||||
std::string res;
|
||||
{
|
||||
std::lock_guard<std::mutex> mocLock(MocMetaMutex_);
|
||||
res = baseName;
|
||||
res += ".cpp";
|
||||
if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
|
||||
MocAutoFiles_.emplace(res);
|
||||
} else {
|
||||
// Append number suffix to the file name
|
||||
for (unsigned int ii = 2; ii != 1024; ++ii) {
|
||||
res = baseName;
|
||||
res += '_';
|
||||
res += std::to_string(ii);
|
||||
res += ".cpp";
|
||||
if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
|
||||
MocAutoFiles_.emplace(res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string res(BaseConst().AutogenIncludeDir);
|
||||
res += '/';
|
||||
res += relativePath;
|
||||
return res;
|
||||
}
|
||||
|
||||
+340
-177
@@ -5,25 +5,28 @@
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmFileTime.h"
|
||||
#include "cmQtAutoGen.h"
|
||||
#include "cmQtAutoGenerator.h"
|
||||
#include "cmWorkerPool.h"
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <memory> // IWYU pragma: keep
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class cmMakefile;
|
||||
|
||||
// @brief AUTOMOC and AUTOUIC generator
|
||||
/** \class cmQtAutoMocUic
|
||||
* \brief AUTOMOC and AUTOUIC generator
|
||||
*/
|
||||
class cmQtAutoMocUic : public cmQtAutoGenerator
|
||||
{
|
||||
public:
|
||||
@@ -35,10 +38,10 @@ public:
|
||||
|
||||
public:
|
||||
// -- Types
|
||||
typedef std::multimap<std::string, std::array<std::string, 2>> IncludesMap;
|
||||
|
||||
/// @brief Search key plus regular expression pair
|
||||
///
|
||||
/**
|
||||
* Search key plus regular expression pair
|
||||
*/
|
||||
struct KeyExpT
|
||||
{
|
||||
KeyExpT() = default;
|
||||
@@ -59,35 +62,123 @@ public:
|
||||
cmsys::RegularExpression Exp;
|
||||
};
|
||||
|
||||
/// @brief Common settings
|
||||
///
|
||||
/**
|
||||
* 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:
|
||||
// -- Volatile methods
|
||||
BaseSettingsT(FileSystem* fileSystem)
|
||||
: MultiConfig(false)
|
||||
, IncludeProjectDirsBefore(false)
|
||||
, QtVersionMajor(4)
|
||||
, NumThreads(1)
|
||||
, FileSys(fileSystem)
|
||||
{
|
||||
}
|
||||
// -- Constructors
|
||||
BaseSettingsT();
|
||||
~BaseSettingsT();
|
||||
|
||||
BaseSettingsT(BaseSettingsT const&) = delete;
|
||||
BaseSettingsT& operator=(BaseSettingsT const&) = delete;
|
||||
|
||||
// -- 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;
|
||||
bool MultiConfig = false;
|
||||
bool IncludeProjectDirsBefore = false;
|
||||
unsigned int QtVersionMajor = 4;
|
||||
// - Directories
|
||||
std::string ProjectSourceDir;
|
||||
std::string ProjectBinaryDir;
|
||||
@@ -96,37 +187,50 @@ public:
|
||||
std::string AutogenBuildDir;
|
||||
std::string AutogenIncludeDir;
|
||||
// - Files
|
||||
std::string CMakeExecutable;
|
||||
cmFileTime CMakeExecutableTime;
|
||||
std::string ParseCacheFile;
|
||||
std::vector<std::string> HeaderExtensions;
|
||||
// - File system
|
||||
FileSystem* FileSys;
|
||||
};
|
||||
|
||||
/// @brief Moc settings
|
||||
///
|
||||
/**
|
||||
* 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:
|
||||
MocSettingsT(FileSystem* fileSys)
|
||||
: FileSys(fileSys)
|
||||
{
|
||||
}
|
||||
// -- Constructors
|
||||
MocSettingsT();
|
||||
~MocSettingsT();
|
||||
|
||||
MocSettingsT(MocSettingsT const&) = delete;
|
||||
MocSettingsT& operator=(MocSettingsT const&) = delete;
|
||||
|
||||
// -- 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;
|
||||
cmFileTime ExecutableTime;
|
||||
std::string Executable;
|
||||
std::string CompFileAbs;
|
||||
std::string PredefsFileRel;
|
||||
@@ -141,16 +245,35 @@ public:
|
||||
std::vector<KeyExpT> DependFilters;
|
||||
std::vector<KeyExpT> MacroFilters;
|
||||
cmsys::RegularExpression RegExpInclude;
|
||||
// - File system
|
||||
FileSystem* FileSys;
|
||||
};
|
||||
|
||||
/// @brief Uic settings
|
||||
///
|
||||
/**
|
||||
* 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() = default;
|
||||
UicSettingsT();
|
||||
~UicSettingsT();
|
||||
|
||||
UicSettingsT(UicSettingsT const&) = delete;
|
||||
UicSettingsT& operator=(UicSettingsT const&) = delete;
|
||||
@@ -161,6 +284,7 @@ public:
|
||||
// -- Attributes
|
||||
bool Enabled = false;
|
||||
bool SettingsChanged = false;
|
||||
cmFileTime ExecutableTime;
|
||||
std::string Executable;
|
||||
std::unordered_set<std::string> SkipList;
|
||||
std::vector<std::string> TargetOptions;
|
||||
@@ -169,8 +293,19 @@ public:
|
||||
cmsys::RegularExpression RegExpInclude;
|
||||
};
|
||||
|
||||
/// @brief Abstract job class for concurrent job processing
|
||||
///
|
||||
/**
|
||||
* Uic shared variables
|
||||
*/
|
||||
class UicEvalT
|
||||
{
|
||||
public:
|
||||
SourceFileMapT UiFiles;
|
||||
MappingMapT Includes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract job class for concurrent job processing
|
||||
*/
|
||||
class JobT : public cmWorkerPool::JobT
|
||||
{
|
||||
protected:
|
||||
@@ -188,10 +323,14 @@ public:
|
||||
return static_cast<cmQtAutoMocUic*>(UserData());
|
||||
};
|
||||
|
||||
//! Get the file system interface. Only valid during Process() call!
|
||||
FileSystem& FileSys() { return Gen()->FileSys(); }
|
||||
//! Get the logger. Only valid during Process() call!
|
||||
Logger& Log() { return Gen()->Log(); }
|
||||
// -- 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;
|
||||
@@ -205,11 +344,13 @@ public:
|
||||
* @brief Run an external process. Use only during Process() call!
|
||||
*/
|
||||
bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
|
||||
std::vector<std::string> const& command);
|
||||
std::vector<std::string> const& command,
|
||||
std::string* infoMessage = nullptr);
|
||||
};
|
||||
|
||||
/// @brief Fence job utility class
|
||||
///
|
||||
/**
|
||||
* Fence job utility class
|
||||
*/
|
||||
class JobFenceT : public JobT
|
||||
{
|
||||
public:
|
||||
@@ -220,58 +361,143 @@ public:
|
||||
void Process() override{};
|
||||
};
|
||||
|
||||
/// @brief Generate moc_predefs.h
|
||||
///
|
||||
class JobMocPredefsT : public JobT
|
||||
/**
|
||||
* Generate moc_predefs.h
|
||||
*/
|
||||
class JobMocPredefsT : public JobFenceT
|
||||
{
|
||||
private:
|
||||
void Process() override;
|
||||
bool Update(std::string* reason) const;
|
||||
};
|
||||
|
||||
/// @brief Parses a source file
|
||||
///
|
||||
/**
|
||||
* File parse job base class
|
||||
*/
|
||||
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)
|
||||
JobParseT(SourceFileHandleT fileHandle)
|
||||
: FileHandle(std::move(fileHandle))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
struct MetaT
|
||||
{
|
||||
std::string Content;
|
||||
std::string FileDir;
|
||||
std::string FileBase;
|
||||
};
|
||||
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();
|
||||
|
||||
void Process() override;
|
||||
bool ParseMocSource(MetaT const& meta);
|
||||
bool ParseMocHeader(MetaT const& meta);
|
||||
std::string MocStringHeaders(std::string const& fileBase) const;
|
||||
std::string MocFindIncludedHeader(std::string const& includerDir,
|
||||
std::string const& includeBase);
|
||||
bool ParseUic(MetaT const& meta);
|
||||
bool ParseUicInclude(MetaT const& meta, std::string&& includeString);
|
||||
std::string UicFindIncludedFile(MetaT const& meta,
|
||||
std::string const& includeString);
|
||||
|
||||
private:
|
||||
std::string FileName;
|
||||
bool AutoMoc = false;
|
||||
bool AutoUic = false;
|
||||
bool Header = false;
|
||||
protected:
|
||||
SourceFileHandleT FileHandle;
|
||||
std::string Content;
|
||||
};
|
||||
|
||||
/// @brief Generates additional jobs after all files have been parsed
|
||||
///
|
||||
class JobPostParseT : public JobFenceT
|
||||
/**
|
||||
* Header file parse job
|
||||
*/
|
||||
class JobParseHeaderT : public JobParseT
|
||||
{
|
||||
private:
|
||||
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<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;
|
||||
};
|
||||
|
||||
@@ -283,60 +509,6 @@ public:
|
||||
void Process() override;
|
||||
};
|
||||
|
||||
/// @brief Moc a file job
|
||||
///
|
||||
class JobMocT : public JobT
|
||||
{
|
||||
public:
|
||||
JobMocT(std::string sourceFile, std::string includerFile,
|
||||
std::string includeString)
|
||||
: SourceFile(std::move(sourceFile))
|
||||
, IncluderFile(std::move(includerFile))
|
||||
, IncludeString(std::move(includeString))
|
||||
{
|
||||
}
|
||||
|
||||
void FindDependencies(std::string const& content);
|
||||
|
||||
private:
|
||||
void Process() override;
|
||||
bool UpdateRequired();
|
||||
void GenerateMoc();
|
||||
|
||||
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 includerFile,
|
||||
std::string includeString)
|
||||
: SourceFile(std::move(sourceFile))
|
||||
, IncluderFile(std::move(includerFile))
|
||||
, IncludeString(std::move(includeString))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void Process() override;
|
||||
bool UpdateRequired();
|
||||
void GenerateUic();
|
||||
|
||||
public:
|
||||
std::string SourceFile;
|
||||
std::string IncluderFile;
|
||||
std::string IncludeString;
|
||||
std::string BuildFile;
|
||||
};
|
||||
|
||||
/// @brief The last job
|
||||
///
|
||||
class JobFinishT : public JobFenceT
|
||||
@@ -346,39 +518,37 @@ public:
|
||||
};
|
||||
|
||||
// -- Const settings interface
|
||||
const BaseSettingsT& Base() const { return this->Base_; }
|
||||
const MocSettingsT& Moc() const { return this->Moc_; }
|
||||
const UicSettingsT& Uic() const { return this->Uic_; }
|
||||
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); }
|
||||
bool ParallelJobPushMoc(cmWorkerPool::JobHandleT&& jobHandle);
|
||||
bool ParallelJobPushUic(cmWorkerPool::JobHandleT&& jobHandle);
|
||||
|
||||
// -- Mocs compilation include file updated flag
|
||||
void ParallelMocAutoUpdated() { MocAutoFileUpdated_.store(true); }
|
||||
bool MocAutoFileUpdated() const { return MocAutoFileUpdated_.load(); }
|
||||
|
||||
// -- Mocs compilation file register
|
||||
std::string ParallelMocAutoRegister(std::string const& baseName);
|
||||
bool ParallelMocIncluded(std::string const& sourceFile);
|
||||
std::set<std::string> const& MocAutoFiles() const
|
||||
{
|
||||
return this->MocAutoFiles_;
|
||||
}
|
||||
// -- 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& Log() { return Logger_; }
|
||||
FileSystem& FileSys() { return FileSys_; }
|
||||
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
|
||||
@@ -387,25 +557,18 @@ private:
|
||||
private:
|
||||
// -- Utility
|
||||
Logger Logger_;
|
||||
FileSystem FileSys_;
|
||||
// -- Settings
|
||||
BaseSettingsT Base_;
|
||||
MocSettingsT Moc_;
|
||||
UicSettingsT Uic_;
|
||||
// -- Moc meta
|
||||
std::mutex MocMetaMutex_;
|
||||
std::set<std::string> MocIncludedFiles_;
|
||||
IncludesMap MocIncludes_;
|
||||
std::set<std::string> MocAutoFiles_;
|
||||
std::atomic<bool> MocAutoFileUpdated_ = ATOMIC_VAR_INIT(false);
|
||||
// -- Uic meta
|
||||
std::mutex UicMetaMutex_;
|
||||
IncludesMap UicIncludes_;
|
||||
BaseSettingsT BaseConst_;
|
||||
BaseEvalT BaseEval_;
|
||||
MocSettingsT MocConst_;
|
||||
MocEvalT MocEval_;
|
||||
UicSettingsT UicConst_;
|
||||
UicEvalT UicEval_;
|
||||
// -- Settings file
|
||||
std::string SettingsFile_;
|
||||
std::string SettingsStringMoc_;
|
||||
std::string SettingsStringUic_;
|
||||
// -- Thread pool and job queue
|
||||
// -- Worker thread pool
|
||||
std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false);
|
||||
cmWorkerPool WorkerPool_;
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile)
|
||||
}
|
||||
|
||||
// - Configurations
|
||||
Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
|
||||
Logger_.RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
|
||||
MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
|
||||
|
||||
// - Directories
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
|
||||
private:
|
||||
// -- Utility
|
||||
Logger& Log() { return Logger_; }
|
||||
Logger const& Log() const { return Logger_; }
|
||||
bool IsMultiConfig() const { return MultiConfig_; }
|
||||
std::string MultiConfigOutput() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user