|
|
@@ -5,16 +5,15 @@
|
|
|
|
|
|
#include <algorithm>
|
|
|
#include <array>
|
|
|
+#include <functional>
|
|
|
#include <list>
|
|
|
#include <memory>
|
|
|
#include <sstream>
|
|
|
-#include <string.h>
|
|
|
#include <utility>
|
|
|
|
|
|
#include "cmAlgorithms.h"
|
|
|
#include "cmCryptoHash.h"
|
|
|
#include "cmMakefile.h"
|
|
|
-#include "cmOutputConverter.h"
|
|
|
#include "cmSystemTools.h"
|
|
|
#include "cmake.h"
|
|
|
|
|
|
@@ -22,1712 +21,2004 @@
|
|
|
#include <unistd.h>
|
|
|
#endif
|
|
|
|
|
|
-// -- Static variables
|
|
|
-
|
|
|
-static const char* SettingsKeyMoc = "AM_MOC_SETTINGS_HASH";
|
|
|
-static const char* SettingsKeyUic = "AM_UIC_SETTINGS_HASH";
|
|
|
+// -- Class methods
|
|
|
|
|
|
-// -- Static functions
|
|
|
+std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
|
|
|
+ std::string const& relativePath) const
|
|
|
+{
|
|
|
+ return cmSystemTools::CollapseCombinedPath(AutogenBuildDir, relativePath);
|
|
|
+}
|
|
|
|
|
|
-static std::string SubDirPrefix(std::string const& fileName)
|
|
|
+/**
|
|
|
+ * @brief Tries to find the header file to the given file base path by
|
|
|
+ * appending different header extensions
|
|
|
+ * @return True on success
|
|
|
+ */
|
|
|
+bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader(
|
|
|
+ std::string& header, std::string const& testBasePath) const
|
|
|
{
|
|
|
- std::string res(cmSystemTools::GetFilenamePath(fileName));
|
|
|
- if (!res.empty()) {
|
|
|
- res += '/';
|
|
|
+ for (std::string const& ext : HeaderExtensions) {
|
|
|
+ std::string testFilePath(testBasePath);
|
|
|
+ testFilePath.push_back('.');
|
|
|
+ testFilePath += ext;
|
|
|
+ if (FileSys->FileExists(testFilePath)) {
|
|
|
+ header = testFilePath;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
- return res;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-static bool ListContains(std::vector<std::string> const& list,
|
|
|
- std::string const& entry)
|
|
|
+bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped(
|
|
|
+ std::string const& fileName) const
|
|
|
{
|
|
|
- return (std::find(list.begin(), list.end(), entry) != list.end());
|
|
|
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
|
|
|
}
|
|
|
|
|
|
-// -- Class methods
|
|
|
+/**
|
|
|
+ * @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 cmQtAutoGeneratorMocUic::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();
|
|
|
+}
|
|
|
|
|
|
-cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
|
|
|
- : MultiConfig(cmQtAutoGen::WRAP)
|
|
|
- , IncludeProjectDirsBefore(false)
|
|
|
- , QtVersionMajor(4)
|
|
|
- , MocSettingsChanged(false)
|
|
|
- , MocPredefsChanged(false)
|
|
|
- , MocRelaxedMode(false)
|
|
|
- , UicSettingsChanged(false)
|
|
|
+std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const
|
|
|
{
|
|
|
- // Precompile regular expressions
|
|
|
- this->MocRegExpInclude.compile(
|
|
|
- "[\n][ \t]*#[ \t]*include[ \t]+"
|
|
|
- "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
|
|
- this->UicRegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+"
|
|
|
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
|
|
|
+ std::string res;
|
|
|
+ const auto itB = MacroFilters.cbegin();
|
|
|
+ const auto itE = MacroFilters.cend();
|
|
|
+ const auto itL = itE - 1;
|
|
|
+ auto itC = itB;
|
|
|
+ for (; itC != itE; ++itC) {
|
|
|
+ // Separator
|
|
|
+ if (itC != itB) {
|
|
|
+ if (itC != itL) {
|
|
|
+ res += ", ";
|
|
|
+ } else {
|
|
|
+ res += " or ";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Key
|
|
|
+ res += itC->Key;
|
|
|
+ }
|
|
|
+ return res;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile)
|
|
|
+std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile(
|
|
|
+ std::string const& sourcePath, std::string const& includeString) const
|
|
|
{
|
|
|
- // -- Meta
|
|
|
- this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
|
|
|
+ // Search in vicinity of the source
|
|
|
+ {
|
|
|
+ std::string testPath = sourcePath;
|
|
|
+ testPath += includeString;
|
|
|
+ if (FileSys->FileExists(testPath)) {
|
|
|
+ return FileSys->RealPath(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->RealPath(fullPath);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Return empty string
|
|
|
+ return std::string();
|
|
|
+}
|
|
|
|
|
|
- // Utility lambdas
|
|
|
- auto InfoGet = [makefile](const char* key) {
|
|
|
- return makefile->GetSafeDefinition(key);
|
|
|
- };
|
|
|
- auto InfoGetBool = [makefile](const char* key) {
|
|
|
- return makefile->IsOn(key);
|
|
|
- };
|
|
|
- auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
|
|
|
- std::vector<std::string> list;
|
|
|
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
|
|
|
- return list;
|
|
|
- };
|
|
|
- auto InfoGetLists =
|
|
|
- [makefile](const char* key) -> std::vector<std::vector<std::string>> {
|
|
|
- std::vector<std::vector<std::string>> lists;
|
|
|
- {
|
|
|
- std::string const value = makefile->GetSafeDefinition(key);
|
|
|
- std::string::size_type pos = 0;
|
|
|
- while (pos < value.size()) {
|
|
|
- std::string::size_type next = value.find(cmQtAutoGen::listSep, pos);
|
|
|
- std::string::size_type length =
|
|
|
- (next != std::string::npos) ? next - pos : value.size() - pos;
|
|
|
- // Remove enclosing braces
|
|
|
- if (length >= 2) {
|
|
|
- std::string::const_iterator itBeg = value.begin() + (pos + 1);
|
|
|
- std::string::const_iterator itEnd = itBeg + (length - 2);
|
|
|
+void cmQtAutoGeneratorMocUic::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 subValue(itBeg, itEnd);
|
|
|
- std::vector<std::string> list;
|
|
|
- cmSystemTools::ExpandListArgument(subValue, list);
|
|
|
- lists.push_back(std::move(list));
|
|
|
+ std::string dep = match.match(1);
|
|
|
+ if (!dep.empty()) {
|
|
|
+ depends.emplace(std::move(dep));
|
|
|
+ }
|
|
|
}
|
|
|
+ contentChars += match.end();
|
|
|
}
|
|
|
- pos += length;
|
|
|
- pos += cmQtAutoGen::listSep.size();
|
|
|
}
|
|
|
}
|
|
|
- return lists;
|
|
|
- };
|
|
|
- auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
|
|
|
- const char* valueConf = nullptr;
|
|
|
- {
|
|
|
- std::string keyConf = key;
|
|
|
- keyConf += '_';
|
|
|
- keyConf += this->GetInfoConfig();
|
|
|
- valueConf = makefile->GetDefinition(keyConf);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped(
|
|
|
+ std::string const& fileName) const
|
|
|
+{
|
|
|
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk)
|
|
|
+{
|
|
|
+ if (AutoMoc && Header) {
|
|
|
+ // Don't parse header for moc if the file is included by a source already
|
|
|
+ if (wrk.Gen().ParallelMocIncluded(FileName)) {
|
|
|
+ AutoMoc = false;
|
|
|
}
|
|
|
- if (valueConf == nullptr) {
|
|
|
- valueConf = makefile->GetSafeDefinition(key);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (AutoMoc || AutoUic) {
|
|
|
+ std::string error;
|
|
|
+ MetaT meta;
|
|
|
+ if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) {
|
|
|
+ if (!meta.Content.empty()) {
|
|
|
+ meta.FileDir = SubDirPrefix(FileName);
|
|
|
+ meta.FileBase =
|
|
|
+ cmSystemTools::GetFilenameWithoutLastExtension(FileName);
|
|
|
+
|
|
|
+ bool success = true;
|
|
|
+ if (AutoMoc) {
|
|
|
+ if (Header) {
|
|
|
+ success = ParseMocHeader(wrk, meta);
|
|
|
+ } else {
|
|
|
+ success = ParseMocSource(wrk, meta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (AutoUic && success) {
|
|
|
+ ParseUic(wrk, meta);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ wrk.LogFileWarning(GeneratorT::GEN, FileName,
|
|
|
+ "The source file is empty");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ wrk.LogFileError(GeneratorT::GEN, FileName,
|
|
|
+ "Could not read the file: " + error);
|
|
|
}
|
|
|
- return std::string(valueConf);
|
|
|
- };
|
|
|
- auto InfoGetConfigList =
|
|
|
- [&InfoGetConfig](const char* key) -> std::vector<std::string> {
|
|
|
- std::vector<std::string> list;
|
|
|
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
|
|
|
- return list;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk,
|
|
|
+ MetaT const& meta)
|
|
|
+{
|
|
|
+ struct JobPre
|
|
|
+ {
|
|
|
+ bool self; // source file is self
|
|
|
+ bool underscore; // "moc_" style include
|
|
|
+ std::string SourceFile;
|
|
|
+ std::string IncludeString;
|
|
|
};
|
|
|
|
|
|
- // -- Read info file
|
|
|
- if (!makefile->ReadListFile(this->GetInfoFile().c_str())) {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
|
|
|
- "File processing failed");
|
|
|
- return false;
|
|
|
- }
|
|
|
+ struct MocInclude
|
|
|
+ {
|
|
|
+ std::string Inc; // full include string
|
|
|
+ std::string Dir; // include string directory
|
|
|
+ std::string Base; // include string file base
|
|
|
+ };
|
|
|
|
|
|
- // -- Meta
|
|
|
- this->MultiConfig = cmQtAutoGen::MultiConfigType(InfoGet("AM_MULTI_CONFIG"));
|
|
|
- this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
|
|
|
- if (this->ConfigSuffix.empty()) {
|
|
|
- this->ConfigSuffix = "_";
|
|
|
- this->ConfigSuffix += this->GetInfoConfig();
|
|
|
- }
|
|
|
+ // Check if this source file contains a relevant macro
|
|
|
+ std::string const ownMacro = wrk.Moc().FindMacro(meta.Content);
|
|
|
|
|
|
- this->SettingsFile = InfoGetConfig("AM_SETTINGS_FILE");
|
|
|
- if (this->SettingsFile.empty()) {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
|
|
|
- "Settings file name missing");
|
|
|
- return false;
|
|
|
+ // 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 (wrk.Moc().RegExpInclude.find(contentChars, match)) {
|
|
|
+ std::string incString = match.match(1);
|
|
|
+ std::string incDir(SubDirPrefix(incString));
|
|
|
+ std::string incBase =
|
|
|
+ cmSystemTools::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();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // - Files and directories
|
|
|
- this->ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
|
|
|
- this->ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
|
|
|
- this->CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
|
|
|
- this->CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
|
|
|
- this->IncludeProjectDirsBefore =
|
|
|
- InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
|
|
|
- this->AutogenBuildDir = InfoGet("AM_BUILD_DIR");
|
|
|
- if (this->AutogenBuildDir.empty()) {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(),
|
|
|
- "Autogen build directory missing");
|
|
|
- return false;
|
|
|
+ // Check if there is anything to do
|
|
|
+ if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- // - Qt environment
|
|
|
- if (!cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"),
|
|
|
- &this->QtVersionMajor)) {
|
|
|
- this->QtVersionMajor = 4;
|
|
|
- }
|
|
|
- this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE");
|
|
|
- this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE");
|
|
|
+ bool ownDotMocIncluded = false;
|
|
|
+ bool ownMocUscIncluded = false;
|
|
|
+ std::deque<JobPre> jobs;
|
|
|
|
|
|
- // - Moc
|
|
|
- if (this->MocEnabled()) {
|
|
|
- this->MocSkipList = InfoGetList("AM_MOC_SKIP");
|
|
|
- this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
|
|
|
-#ifdef _WIN32
|
|
|
- {
|
|
|
- std::string const win32("WIN32");
|
|
|
- if (!ListContains(this->MocDefinitions, win32)) {
|
|
|
- this->MocDefinitions.push_back(win32);
|
|
|
+ // Process moc_<BASE>.cxx includes
|
|
|
+ for (const MocInclude& mocInc : mocIncsUsc) {
|
|
|
+ std::string const header =
|
|
|
+ MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
|
|
|
+ if (!header.empty()) {
|
|
|
+ // Check if header is skipped
|
|
|
+ if (wrk.Moc().skipped(header)) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
-#endif
|
|
|
- this->MocIncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
|
|
|
- this->MocOptions = InfoGetList("AM_MOC_OPTIONS");
|
|
|
- this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
|
|
|
- {
|
|
|
- std::vector<std::string> const MocMacroNames =
|
|
|
- InfoGetList("AM_MOC_MACRO_NAMES");
|
|
|
- for (std::string const& item : MocMacroNames) {
|
|
|
- this->MocMacroFilters.emplace_back(
|
|
|
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
|
|
|
+ // 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;
|
|
|
}
|
|
|
- }
|
|
|
- {
|
|
|
- std::vector<std::string> const mocDependFilters =
|
|
|
- InfoGetList("AM_MOC_DEPEND_FILTERS");
|
|
|
- // Insert Q_PLUGIN_METADATA dependency filter
|
|
|
- if (this->QtVersionMajor != 4) {
|
|
|
- this->MocDependFilterPush("Q_PLUGIN_METADATA",
|
|
|
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
|
|
|
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
|
|
|
+ } else {
|
|
|
+ {
|
|
|
+ std::string emsg = "The file includes the moc file ";
|
|
|
+ emsg += Quoted(mocInc.Inc);
|
|
|
+ emsg += ", but the header ";
|
|
|
+ emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
|
|
|
+ emsg += " could not be found.";
|
|
|
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
|
|
|
}
|
|
|
- // Insert user defined dependency filters
|
|
|
- if ((mocDependFilters.size() % 2) == 0) {
|
|
|
- for (std::vector<std::string>::const_iterator
|
|
|
- dit = mocDependFilters.begin(),
|
|
|
- ditEnd = mocDependFilters.end();
|
|
|
- dit != ditEnd; dit += 2) {
|
|
|
- if (!this->MocDependFilterPush(*dit, *(dit + 1))) {
|
|
|
- return false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Process <BASE>.moc includes
|
|
|
+ for (const MocInclude& mocInc : mocIncsDot) {
|
|
|
+ const bool ownMoc = (mocInc.Base == meta.FileBase);
|
|
|
+ if (wrk.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(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
|
|
|
+ if (!header.empty()) {
|
|
|
+ // Check if header is skipped
|
|
|
+ if (wrk.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 += wrk.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";
|
|
|
+ wrk.LogFileWarning(GeneratorT::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";
|
|
|
+ wrk.LogFileWarning(GeneratorT::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(wrk, mocInc.Base));
|
|
|
+ emsg += " could not be found.";
|
|
|
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } 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 += wrk.Moc().MacrosString();
|
|
|
+ emsg += " macro.";
|
|
|
+ wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
|
|
|
}
|
|
|
} else {
|
|
|
- this->LogFileError(
|
|
|
- cmQtAutoGen::MOC, this->GetInfoFile(),
|
|
|
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
|
|
|
+ // 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.";
|
|
|
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
|
|
|
+ }
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
- this->MocPredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
|
|
|
}
|
|
|
|
|
|
- // - Uic
|
|
|
- if (this->UicEnabled()) {
|
|
|
- this->UicSkipList = InfoGetList("AM_UIC_SKIP");
|
|
|
- this->UicSearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
|
|
|
- this->UicTargetOptions = 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() << ")";
|
|
|
- this->LogFileError(cmQtAutoGen::UIC, this->GetInfoFile(), ost.str());
|
|
|
- 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 (wrk.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;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- auto fitEnd = sources.cend();
|
|
|
- auto fit = sources.begin();
|
|
|
- auto oit = options.begin();
|
|
|
- while (fit != fitEnd) {
|
|
|
- this->UicOptions[*fit] = std::move(*oit);
|
|
|
- ++fit;
|
|
|
- ++oit;
|
|
|
+ // 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)";
|
|
|
+ wrk.LogFileWarning(GeneratorT::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";
|
|
|
+ wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Initialize source file jobs
|
|
|
+ // Convert pre jobs to actual jobs
|
|
|
+ for (JobPre& jobPre : jobs) {
|
|
|
+ JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName,
|
|
|
+ std::move(jobPre.IncludeString)));
|
|
|
+ if (jobPre.self) {
|
|
|
+ // Read depdendencies from this source
|
|
|
+ static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
|
|
|
+ }
|
|
|
+ if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk,
|
|
|
+ MetaT const& meta)
|
|
|
+{
|
|
|
+ bool success = true;
|
|
|
+ std::string const macroName = wrk.Moc().FindMacro(meta.Content);
|
|
|
+ if (!macroName.empty()) {
|
|
|
+ JobHandleT jobHandle(
|
|
|
+ new JobMocT(std::string(FileName), std::string(), std::string()));
|
|
|
+ // Read depdendencies from this source
|
|
|
+ static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
|
|
|
+ success = wrk.Gen().ParallelJobPushMoc(jobHandle);
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+
|
|
|
+std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders(
|
|
|
+ WorkerT& wrk, std::string const& fileBase) const
|
|
|
+{
|
|
|
+ std::string res = fileBase;
|
|
|
+ res += ".{";
|
|
|
+ res += cmJoin(wrk.Base().HeaderExtensions, ",");
|
|
|
+ res += "}";
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader(
|
|
|
+ WorkerT& wrk, std::string const& includerDir, std::string const& includeBase)
|
|
|
+{
|
|
|
+ std::string header;
|
|
|
+ // Search in vicinity of the source
|
|
|
+ if (!wrk.Base().FindHeader(header, includerDir + includeBase)) {
|
|
|
+ // Search in include directories
|
|
|
+ for (std::string const& path : wrk.Moc().IncludePaths) {
|
|
|
+ std::string fullPath = path;
|
|
|
+ fullPath.push_back('/');
|
|
|
+ fullPath += includeBase;
|
|
|
+ if (wrk.Base().FindHeader(header, fullPath)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Sanitize
|
|
|
+ if (!header.empty()) {
|
|
|
+ header = wrk.FileSys().RealPath(header);
|
|
|
+ }
|
|
|
+ return header;
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk,
|
|
|
+ MetaT const& meta)
|
|
|
+{
|
|
|
+ bool success = true;
|
|
|
+ if (meta.Content.find("ui_") != std::string::npos) {
|
|
|
+ const char* contentChars = meta.Content.c_str();
|
|
|
+ cmsys::RegularExpressionMatch match;
|
|
|
+ while (wrk.Uic().RegExpInclude.find(contentChars, match)) {
|
|
|
+ if (!ParseUicInclude(wrk, meta, match.match(1))) {
|
|
|
+ success = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ contentChars += match.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude(
|
|
|
+ WorkerT& wrk, MetaT const& meta, std::string&& includeString)
|
|
|
+{
|
|
|
+ bool success = false;
|
|
|
+ std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
|
|
|
+ if (!uiInputFile.empty()) {
|
|
|
+ if (!wrk.Uic().skipped(uiInputFile)) {
|
|
|
+ JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName,
|
|
|
+ std::move(includeString)));
|
|
|
+ success = wrk.Gen().ParallelJobPushUic(jobHandle);
|
|
|
+ } else {
|
|
|
+ // A skipped file is successful
|
|
|
+ success = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return success;
|
|
|
+}
|
|
|
+
|
|
|
+std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile(
|
|
|
+ WorkerT& wrk, MetaT const& meta, std::string const& includeString)
|
|
|
+{
|
|
|
+ std::string res;
|
|
|
+ std::string searchFile =
|
|
|
+ cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3);
|
|
|
+ searchFile += ".ui";
|
|
|
+ // Collect search paths list
|
|
|
+ std::deque<std::string> testFiles;
|
|
|
{
|
|
|
- // Utility lambdas
|
|
|
- auto AddJob = [this](std::map<std::string, SourceJob>& jobs,
|
|
|
- std::string&& sourceFile) {
|
|
|
- const bool moc = !this->MocSkip(sourceFile);
|
|
|
- const bool uic = !this->UicSkip(sourceFile);
|
|
|
- if (moc || uic) {
|
|
|
- SourceJob& job = jobs[std::move(sourceFile)];
|
|
|
- job.Moc = moc;
|
|
|
- job.Uic = uic;
|
|
|
- }
|
|
|
- };
|
|
|
+ std::string const searchPath = SubDirPrefix(includeString);
|
|
|
|
|
|
- // Add header jobs
|
|
|
- for (std::string& hdr : InfoGetList("AM_HEADERS")) {
|
|
|
- AddJob(this->HeaderJobs, std::move(hdr));
|
|
|
+ std::string searchFileFull;
|
|
|
+ if (!searchPath.empty()) {
|
|
|
+ searchFileFull = searchPath;
|
|
|
+ searchFileFull += searchFile;
|
|
|
}
|
|
|
- // Add source jobs
|
|
|
+ // Vicinity of the source
|
|
|
{
|
|
|
- std::vector<std::string> sources = InfoGetList("AM_SOURCES");
|
|
|
- // Add header(s) for the source file
|
|
|
- for (std::string const& src : sources) {
|
|
|
- const bool srcMoc = !this->MocSkip(src);
|
|
|
- const bool srcUic = !this->UicSkip(src);
|
|
|
- if (!srcMoc && !srcUic) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Search for the default header file and a private header
|
|
|
- std::array<std::string, 2> headerBases;
|
|
|
- headerBases[0] = SubDirPrefix(src);
|
|
|
- headerBases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src);
|
|
|
- headerBases[1] = headerBases[0];
|
|
|
- headerBases[1] += "_p";
|
|
|
- for (std::string const& headerBase : headerBases) {
|
|
|
- std::string header;
|
|
|
- if (this->FindHeader(header, headerBase)) {
|
|
|
- const bool moc = srcMoc && !this->MocSkip(header);
|
|
|
- const bool uic = srcUic && !this->UicSkip(header);
|
|
|
- if (moc || uic) {
|
|
|
- SourceJob& job = this->HeaderJobs[std::move(header)];
|
|
|
- job.Moc = moc;
|
|
|
- job.Uic = uic;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ std::string const sourcePath = meta.FileDir;
|
|
|
+ testFiles.push_back(sourcePath + searchFile);
|
|
|
+ if (!searchPath.empty()) {
|
|
|
+ testFiles.push_back(sourcePath + searchFileFull);
|
|
|
}
|
|
|
- // Add Source jobs
|
|
|
- for (std::string& src : sources) {
|
|
|
- AddJob(this->SourceJobs, std::move(src));
|
|
|
+ }
|
|
|
+ // AUTOUIC search paths
|
|
|
+ if (!wrk.Uic().SearchPaths.empty()) {
|
|
|
+ for (std::string const& sPath : wrk.Uic().SearchPaths) {
|
|
|
+ testFiles.push_back((sPath + "/").append(searchFile));
|
|
|
+ }
|
|
|
+ if (!searchPath.empty()) {
|
|
|
+ for (std::string const& sPath : wrk.Uic().SearchPaths) {
|
|
|
+ testFiles.push_back((sPath + "/").append(searchFileFull));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Init derived information
|
|
|
- // ------------------------
|
|
|
-
|
|
|
- // Init file path checksum generator
|
|
|
- this->FilePathChecksum.setupParentDirs(
|
|
|
- this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir,
|
|
|
- this->ProjectBinaryDir);
|
|
|
-
|
|
|
- // include directory
|
|
|
- this->AutogenIncludeDir = "include";
|
|
|
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
|
|
|
- this->AutogenIncludeDir += this->ConfigSuffix;
|
|
|
+ // Search for the .ui file!
|
|
|
+ for (std::string const& testFile : testFiles) {
|
|
|
+ if (wrk.FileSys().FileExists(testFile)) {
|
|
|
+ res = wrk.FileSys().RealPath(testFile);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- this->AutogenIncludeDir += "/";
|
|
|
|
|
|
- // Moc variables
|
|
|
- if (this->MocEnabled()) {
|
|
|
- // Mocs compilation file
|
|
|
- this->MocCompFileRel = "mocs_compilation";
|
|
|
- if (this->MultiConfig == cmQtAutoGen::FULL) {
|
|
|
- this->MocCompFileRel += this->ConfigSuffix;
|
|
|
+ // Log error
|
|
|
+ if (res.empty()) {
|
|
|
+ std::string emsg = "Could not find ";
|
|
|
+ emsg += Quoted(searchFile);
|
|
|
+ emsg += " in\n";
|
|
|
+ for (std::string const& testFile : testFiles) {
|
|
|
+ emsg += " ";
|
|
|
+ emsg += Quoted(testFile);
|
|
|
+ emsg += "\n";
|
|
|
}
|
|
|
- this->MocCompFileRel += ".cpp";
|
|
|
- this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath(
|
|
|
- this->AutogenBuildDir, this->MocCompFileRel);
|
|
|
+ wrk.LogFileError(GeneratorT::UIC, FileName, emsg);
|
|
|
+ }
|
|
|
|
|
|
- // Moc predefs file
|
|
|
- if (!this->MocPredefsCmd.empty()) {
|
|
|
- this->MocPredefsFileRel = "moc_predefs";
|
|
|
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
|
|
|
- this->MocPredefsFileRel += this->ConfigSuffix;
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk)
|
|
|
+{
|
|
|
+ // (Re)generate moc_predefs.h on demand
|
|
|
+ bool generate(false);
|
|
|
+ bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs));
|
|
|
+ if (!fileExists) {
|
|
|
+ if (wrk.Log().Verbose()) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(wrk.Moc().PredefsFileRel);
|
|
|
+ reason += " because it doesn't exist";
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
+ }
|
|
|
+ generate = true;
|
|
|
+ } else if (wrk.Moc().SettingsChanged) {
|
|
|
+ if (wrk.Log().Verbose()) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(wrk.Moc().PredefsFileRel);
|
|
|
+ reason += " because the settings changed.";
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
+ }
|
|
|
+ generate = true;
|
|
|
+ }
|
|
|
+ if (generate) {
|
|
|
+ ProcessResultT result;
|
|
|
+ {
|
|
|
+ // Compose command
|
|
|
+ std::vector<std::string> cmd = wrk.Moc().PredefsCmd;
|
|
|
+ // Add includes
|
|
|
+ cmd.insert(cmd.end(), wrk.Moc().Includes.begin(),
|
|
|
+ wrk.Moc().Includes.end());
|
|
|
+ // Add definitions
|
|
|
+ for (std::string const& def : wrk.Moc().Definitions) {
|
|
|
+ cmd.push_back("-D" + def);
|
|
|
+ }
|
|
|
+ // Execute command
|
|
|
+ if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
|
|
|
+ std::string emsg = "The content generation command for ";
|
|
|
+ emsg += Quoted(wrk.Moc().PredefsFileRel);
|
|
|
+ emsg += " failed.\n";
|
|
|
+ emsg += result.ErrorMessage;
|
|
|
+ wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
|
|
|
}
|
|
|
- this->MocPredefsFileRel += ".h";
|
|
|
- this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath(
|
|
|
- this->AutogenBuildDir, this->MocPredefsFileRel);
|
|
|
}
|
|
|
|
|
|
- // Sort include directories on demand
|
|
|
- if (this->IncludeProjectDirsBefore) {
|
|
|
- // Move strings to temporary list
|
|
|
- std::list<std::string> includes;
|
|
|
- includes.insert(includes.end(), this->MocIncludePaths.begin(),
|
|
|
- this->MocIncludePaths.end());
|
|
|
- this->MocIncludePaths.clear();
|
|
|
- this->MocIncludePaths.reserve(includes.size());
|
|
|
- // Append project directories only
|
|
|
- {
|
|
|
- std::array<std::string const*, 2> const movePaths = {
|
|
|
- { &this->ProjectBinaryDir, &this->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())) {
|
|
|
- this->MocIncludePaths.push_back(path);
|
|
|
- it = includes.erase(it);
|
|
|
- } else {
|
|
|
- ++it;
|
|
|
- }
|
|
|
- }
|
|
|
+ // (Re)write predefs file only on demand
|
|
|
+ if (!result.error()) {
|
|
|
+ if (!fileExists ||
|
|
|
+ wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
|
|
|
+ if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs,
|
|
|
+ result.StdOut)) {
|
|
|
+ // Success
|
|
|
+ } else {
|
|
|
+ std::string emsg = "Writing ";
|
|
|
+ emsg += Quoted(wrk.Moc().PredefsFileRel);
|
|
|
+ emsg += " failed.";
|
|
|
+ wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ // Touch to update the time stamp
|
|
|
+ if (wrk.Log().Verbose()) {
|
|
|
+ std::string msg = "Touching ";
|
|
|
+ msg += Quoted(wrk.Moc().PredefsFileRel);
|
|
|
+ msg += ".";
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, msg);
|
|
|
+ }
|
|
|
+ wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
|
|
|
}
|
|
|
- // Append remaining directories
|
|
|
- this->MocIncludePaths.insert(this->MocIncludePaths.end(),
|
|
|
- includes.begin(), includes.end());
|
|
|
}
|
|
|
- // Compose moc includes list
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies(
|
|
|
+ WorkerT& wrk, std::string const& content)
|
|
|
+{
|
|
|
+ wrk.Moc().FindDependencies(content, Depends);
|
|
|
+ DependsValid = true;
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk)
|
|
|
+{
|
|
|
+ // Compute build file name
|
|
|
+ if (!IncludeString.empty()) {
|
|
|
+ BuildFile = wrk.Base().AutogenIncludeDirAbs;
|
|
|
+ BuildFile += IncludeString;
|
|
|
+ } else {
|
|
|
+ std::string buildRel = wrk.Base().FilePathChecksum.getPart(SourceFile);
|
|
|
+ buildRel += '/';
|
|
|
+ buildRel += "moc_";
|
|
|
+ buildRel += cmSystemTools::GetFilenameWithoutLastExtension(SourceFile);
|
|
|
+ if (wrk.Base().MultiConfig != MultiConfigT::SINGLE) {
|
|
|
+ buildRel += wrk.Base().ConfigSuffix;
|
|
|
+ }
|
|
|
+ buildRel += ".cpp";
|
|
|
+ wrk.Gen().ParallelMocAutoRegister(buildRel);
|
|
|
+ BuildFile = wrk.Base().AbsoluteBuildPath(buildRel);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (UpdateRequired(wrk)) {
|
|
|
+ GenerateMoc(wrk);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk)
|
|
|
+{
|
|
|
+ bool const verbose = wrk.Gen().Log().Verbose();
|
|
|
+
|
|
|
+ // Test if the build file exists
|
|
|
+ if (!wrk.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";
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test if any setting changed
|
|
|
+ if (wrk.Moc().SettingsChanged) {
|
|
|
+ if (verbose) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(BuildFile);
|
|
|
+ reason += " from ";
|
|
|
+ reason += Quoted(SourceFile);
|
|
|
+ reason += " because the MOC settings changed";
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test if the moc_predefs file is newer
|
|
|
+ if (!wrk.Moc().PredefsFileAbs.empty()) {
|
|
|
+ bool isOlder = false;
|
|
|
{
|
|
|
- std::set<std::string> frameworkPaths;
|
|
|
- for (std::string const& path : this->MocIncludePaths) {
|
|
|
- this->MocIncludes.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;
|
|
|
- cmSystemTools::SplitPath(path, pathComponents);
|
|
|
- std::string frameworkPath = cmSystemTools::JoinPath(
|
|
|
- pathComponents.begin(), pathComponents.end() - 2);
|
|
|
- frameworkPaths.insert(frameworkPath);
|
|
|
- }
|
|
|
- }
|
|
|
- // Append framework includes
|
|
|
- for (std::string const& path : frameworkPaths) {
|
|
|
- this->MocIncludes.push_back("-F");
|
|
|
- this->MocIncludes.push_back(path);
|
|
|
+ std::string error;
|
|
|
+ isOlder = wrk.FileSys().FileIsOlderThan(
|
|
|
+ BuildFile, wrk.Moc().PredefsFileAbs, &error);
|
|
|
+ if (!isOlder && !error.empty()) {
|
|
|
+ wrk.LogError(GeneratorT::MOC, error);
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
- // Setup single list with all options
|
|
|
- {
|
|
|
- // Add includes
|
|
|
- this->MocAllOptions.insert(this->MocAllOptions.end(),
|
|
|
- this->MocIncludes.begin(),
|
|
|
- this->MocIncludes.end());
|
|
|
- // Add definitions
|
|
|
- for (std::string const& def : this->MocDefinitions) {
|
|
|
- this->MocAllOptions.push_back("-D" + def);
|
|
|
+ if (isOlder) {
|
|
|
+ if (verbose) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(BuildFile);
|
|
|
+ reason += " because it's older than: ";
|
|
|
+ reason += Quoted(wrk.Moc().PredefsFileAbs);
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
}
|
|
|
- // Add options
|
|
|
- this->MocAllOptions.insert(this->MocAllOptions.end(),
|
|
|
- this->MocOptions.begin(),
|
|
|
- this->MocOptions.end());
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-void cmQtAutoGeneratorMocUic::SettingsFileRead(cmMakefile* makefile)
|
|
|
-{
|
|
|
- // Compose current settings strings
|
|
|
+ // Test if the source file is newer
|
|
|
{
|
|
|
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
|
|
|
- std::string const sep(" ~~~ ");
|
|
|
- if (this->MocEnabled()) {
|
|
|
- std::string str;
|
|
|
- str += this->MocExecutable;
|
|
|
- str += sep;
|
|
|
- str += cmJoin(this->MocAllOptions, ";");
|
|
|
- str += sep;
|
|
|
- str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE";
|
|
|
- str += sep;
|
|
|
- str += cmJoin(this->MocPredefsCmd, ";");
|
|
|
- str += sep;
|
|
|
- this->SettingsStringMoc = crypt.HashString(str);
|
|
|
+ bool isOlder = false;
|
|
|
+ {
|
|
|
+ std::string error;
|
|
|
+ isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
|
|
|
+ if (!isOlder && !error.empty()) {
|
|
|
+ wrk.LogError(GeneratorT::MOC, error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
- if (this->UicEnabled()) {
|
|
|
- std::string str;
|
|
|
- str += this->UicExecutable;
|
|
|
- str += sep;
|
|
|
- str += cmJoin(this->UicTargetOptions, ";");
|
|
|
- for (const auto& item : this->UicOptions) {
|
|
|
- str += sep;
|
|
|
- str += item.first;
|
|
|
- str += sep;
|
|
|
- str += cmJoin(item.second, ";");
|
|
|
+ if (isOlder) {
|
|
|
+ if (verbose) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(BuildFile);
|
|
|
+ reason += " because it's older than its source file ";
|
|
|
+ reason += Quoted(SourceFile);
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
}
|
|
|
- str += sep;
|
|
|
- this->SettingsStringUic = crypt.HashString(str);
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Read old settings
|
|
|
- if (makefile->ReadListFile(this->SettingsFile.c_str())) {
|
|
|
- {
|
|
|
- auto SMatch = [makefile](const char* key, std::string const& value) {
|
|
|
- return (value == makefile->GetSafeDefinition(key));
|
|
|
- };
|
|
|
- if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) {
|
|
|
- this->MocSettingsChanged = true;
|
|
|
- }
|
|
|
- if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) {
|
|
|
- this->UicSettingsChanged = true;
|
|
|
+ // Test if a dependency file is newer
|
|
|
+ {
|
|
|
+ // Read dependencies on demand
|
|
|
+ if (!DependsValid) {
|
|
|
+ std::string content;
|
|
|
+ {
|
|
|
+ std::string error;
|
|
|
+ if (!wrk.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;
|
|
|
+ wrk.LogError(GeneratorT::MOC, emsg);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
+ FindDependencies(wrk, content);
|
|
|
}
|
|
|
- // 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 (this->SettingsChanged()) {
|
|
|
- cmSystemTools::RemoveFile(this->SettingsFile);
|
|
|
+ // Check dependency timestamps
|
|
|
+ std::string error;
|
|
|
+ std::string sourceDir = SubDirPrefix(SourceFile);
|
|
|
+ for (std::string const& depFileRel : Depends) {
|
|
|
+ std::string depFileAbs =
|
|
|
+ wrk.Moc().FindIncludedFile(sourceDir, depFileRel);
|
|
|
+ if (!depFileAbs.empty()) {
|
|
|
+ if (wrk.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);
|
|
|
+ wrk.LogInfo(GeneratorT::MOC, reason);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!error.empty()) {
|
|
|
+ wrk.LogError(GeneratorT::MOC, error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ std::string message = "Could not find dependency file ";
|
|
|
+ message += Quoted(depFileRel);
|
|
|
+ wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message);
|
|
|
+ }
|
|
|
}
|
|
|
- } else {
|
|
|
- // If the file could not be read re-generate everythiung.
|
|
|
- this->MocSettingsChanged = true;
|
|
|
- this->UicSettingsChanged = true;
|
|
|
}
|
|
|
+
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::SettingsFileWrite()
|
|
|
+void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
|
|
|
{
|
|
|
- bool success = true;
|
|
|
- // Only write if any setting changed
|
|
|
- if (this->SettingsChanged()) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " +
|
|
|
- cmQtAutoGen::Quoted(this->SettingsFile));
|
|
|
- }
|
|
|
- // Compose settings file content
|
|
|
- std::string settings;
|
|
|
- {
|
|
|
- auto SettingAppend = [&settings](const char* key,
|
|
|
- std::string const& value) {
|
|
|
- settings += "set(";
|
|
|
- settings += key;
|
|
|
- settings += " ";
|
|
|
- settings += cmOutputConverter::EscapeForCMake(value);
|
|
|
- settings += ")\n";
|
|
|
- };
|
|
|
- SettingAppend(SettingsKeyMoc, this->SettingsStringMoc);
|
|
|
- SettingAppend(SettingsKeyUic, this->SettingsStringUic);
|
|
|
- }
|
|
|
- // Write settings file
|
|
|
- if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, this->SettingsFile,
|
|
|
- "Settings file writing failed");
|
|
|
- // Remove old settings file to trigger a full rebuild on the next run
|
|
|
- cmSystemTools::RemoveFile(this->SettingsFile);
|
|
|
- success = false;
|
|
|
+ // Make sure the parent directory exists
|
|
|
+ if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) {
|
|
|
+ // Compose moc command
|
|
|
+ std::vector<std::string> cmd;
|
|
|
+ cmd.push_back(wrk.Moc().Executable);
|
|
|
+ // Add options
|
|
|
+ cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(),
|
|
|
+ wrk.Moc().AllOptions.end());
|
|
|
+ // Add predefs include
|
|
|
+ if (!wrk.Moc().PredefsFileAbs.empty()) {
|
|
|
+ cmd.push_back("--include");
|
|
|
+ cmd.push_back(wrk.Moc().PredefsFileAbs);
|
|
|
+ }
|
|
|
+ cmd.push_back("-o");
|
|
|
+ cmd.push_back(BuildFile);
|
|
|
+ cmd.push_back(SourceFile);
|
|
|
+
|
|
|
+ // Execute moc command
|
|
|
+ ProcessResultT result;
|
|
|
+ if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
|
|
|
+ // Moc command success
|
|
|
+ if (IncludeString.empty()) {
|
|
|
+ // Notify the generator that a not included file changed
|
|
|
+ wrk.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;
|
|
|
+ wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
|
|
|
+ }
|
|
|
+ wrk.FileSys().FileRemove(BuildFile);
|
|
|
}
|
|
|
}
|
|
|
- return success;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::Process(cmMakefile* makefile)
|
|
|
+void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk)
|
|
|
{
|
|
|
- // the program goes through all .cpp files to see which moc files are
|
|
|
- // included. It is not really interesting how the moc file is named, but
|
|
|
- // what file the moc is created from. Once a moc is included the same moc
|
|
|
- // may not be included in the mocs_compilation.cpp file anymore.
|
|
|
- // OTOH if there's a header containing Q_OBJECT where no corresponding
|
|
|
- // moc file is included anywhere a moc_<filename>.cpp file is created and
|
|
|
- // included in the mocs_compilation.cpp file.
|
|
|
-
|
|
|
- if (!this->InitInfoFile(makefile)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- // Read latest settings
|
|
|
- this->SettingsFileRead(makefile);
|
|
|
+ // Compute build file name
|
|
|
+ BuildFile = wrk.Base().AutogenIncludeDirAbs;
|
|
|
+ BuildFile += IncludeString;
|
|
|
|
|
|
- // Create AUTOGEN include directory
|
|
|
- {
|
|
|
- std::string const incDirAbs = cmSystemTools::CollapseCombinedPath(
|
|
|
- this->AutogenBuildDir, this->AutogenIncludeDir);
|
|
|
- if (!cmSystemTools::MakeDirectory(incDirAbs)) {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, incDirAbs,
|
|
|
- "Could not create directory");
|
|
|
- return false;
|
|
|
- }
|
|
|
+ if (UpdateRequired(wrk)) {
|
|
|
+ GenerateUic(wrk);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // Parse source files
|
|
|
- for (const auto& item : this->SourceJobs) {
|
|
|
- if (!this->ParseSourceFile(item.first, item.second)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- // Parse header files
|
|
|
- for (const auto& item : this->HeaderJobs) {
|
|
|
- if (!this->ParseHeaderFile(item.first, item.second)) {
|
|
|
- return false;
|
|
|
+bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk)
|
|
|
+{
|
|
|
+ bool const verbose = wrk.Gen().Log().Verbose();
|
|
|
+
|
|
|
+ // Test if the build file exists
|
|
|
+ if (!wrk.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";
|
|
|
+ wrk.LogInfo(GeneratorT::UIC, reason);
|
|
|
}
|
|
|
- }
|
|
|
- // Read missing dependency information
|
|
|
- if (!this->ParsePostprocess()) {
|
|
|
- return false;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- // Generate files
|
|
|
- if (!this->MocGenerateAll()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (!this->UicGenerateAll()) {
|
|
|
- return false;
|
|
|
+ // Test if the uic settings changed
|
|
|
+ if (wrk.Uic().SettingsChanged) {
|
|
|
+ if (verbose) {
|
|
|
+ std::string reason = "Generating ";
|
|
|
+ reason += Quoted(BuildFile);
|
|
|
+ reason += " from ";
|
|
|
+ reason += Quoted(SourceFile);
|
|
|
+ reason += " because the UIC settings changed";
|
|
|
+ wrk.LogInfo(GeneratorT::UIC, reason);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- if (!this->SettingsFileWrite()) {
|
|
|
- return false;
|
|
|
+ // Test if the source file is newer
|
|
|
+ {
|
|
|
+ bool isOlder = false;
|
|
|
+ {
|
|
|
+ std::string error;
|
|
|
+ isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
|
|
|
+ if (!isOlder && !error.empty()) {
|
|
|
+ wrk.LogError(GeneratorT::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);
|
|
|
+ wrk.LogInfo(GeneratorT::UIC, reason);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::ParseSourceFile(std::string const& absFilename,
|
|
|
- const SourceJob& job)
|
|
|
+void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
|
|
|
{
|
|
|
- std::string contentText;
|
|
|
- std::string error;
|
|
|
- bool success = this->FileRead(contentText, absFilename, &error);
|
|
|
- if (success) {
|
|
|
- if (!contentText.empty()) {
|
|
|
- if (job.Moc) {
|
|
|
- success = this->MocParseSourceContent(absFilename, contentText);
|
|
|
- }
|
|
|
- if (success && job.Uic) {
|
|
|
- success = this->UicParseContent(absFilename, contentText);
|
|
|
+ // Make sure the parent directory exists
|
|
|
+ if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) {
|
|
|
+ // Compose uic command
|
|
|
+ std::vector<std::string> cmd;
|
|
|
+ cmd.push_back(wrk.Uic().Executable);
|
|
|
+ {
|
|
|
+ std::vector<std::string> allOpts = wrk.Uic().TargetOptions;
|
|
|
+ auto optionIt = wrk.Uic().Options.find(SourceFile);
|
|
|
+ if (optionIt != wrk.Uic().Options.end()) {
|
|
|
+ UicMergeOptions(allOpts, optionIt->second,
|
|
|
+ (wrk.Base().QtVersionMajor == 5));
|
|
|
}
|
|
|
+ cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
|
|
|
+ }
|
|
|
+ cmd.push_back("-o");
|
|
|
+ cmd.push_back(BuildFile);
|
|
|
+ cmd.push_back(SourceFile);
|
|
|
+
|
|
|
+ ProcessResultT result;
|
|
|
+ if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) {
|
|
|
+ // Success
|
|
|
} else {
|
|
|
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
|
|
|
- "The source file is empty");
|
|
|
+ // 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;
|
|
|
+ wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut);
|
|
|
+ }
|
|
|
+ wrk.FileSys().FileRemove(BuildFile);
|
|
|
}
|
|
|
- } else {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
|
|
|
- "Could not read the source file: " + error);
|
|
|
}
|
|
|
- return success;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::ParseHeaderFile(std::string const& absFilename,
|
|
|
- const SourceJob& job)
|
|
|
+void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job)
|
|
|
{
|
|
|
- std::string contentText;
|
|
|
- std::string error;
|
|
|
- bool success = this->FileRead(contentText, absFilename, &error);
|
|
|
- if (success) {
|
|
|
- if (!contentText.empty()) {
|
|
|
- if (job.Moc) {
|
|
|
- this->MocParseHeaderContent(absFilename, contentText);
|
|
|
- }
|
|
|
- if (job.Uic) {
|
|
|
- success = this->UicParseContent(absFilename, contentText);
|
|
|
- }
|
|
|
- } else {
|
|
|
- this->LogFileWarning(cmQtAutoGen::GEN, absFilename,
|
|
|
- "The header file is empty");
|
|
|
- }
|
|
|
- } else {
|
|
|
- this->LogFileError(cmQtAutoGen::GEN, absFilename,
|
|
|
- "Could not read the header file: " + error);
|
|
|
+ delete job;
|
|
|
+}
|
|
|
+
|
|
|
+cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
|
|
|
+ uv_loop_t* uvLoop)
|
|
|
+ : Gen_(gen)
|
|
|
+{
|
|
|
+ // Initialize uv asynchronous callback for process starting
|
|
|
+ ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this);
|
|
|
+ // Start thread
|
|
|
+ Thread_ = std::thread(&WorkerT::Loop, this);
|
|
|
+}
|
|
|
+
|
|
|
+cmQtAutoGeneratorMocUic::WorkerT::~WorkerT()
|
|
|
+{
|
|
|
+ // Join thread
|
|
|
+ if (Thread_.joinable()) {
|
|
|
+ Thread_.join();
|
|
|
}
|
|
|
- return success;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::ParsePostprocess()
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
|
|
|
+ GeneratorT genType, std::string const& message) const
|
|
|
{
|
|
|
- bool success = true;
|
|
|
- // Read missing dependencies
|
|
|
- for (auto& item : this->MocJobsIncluded) {
|
|
|
- if (!item->DependsValid) {
|
|
|
- std::string content;
|
|
|
- std::string error;
|
|
|
- if (this->FileRead(content, item->SourceFile, &error)) {
|
|
|
- this->MocFindDepends(item->SourceFile, content, item->Depends);
|
|
|
- item->DependsValid = true;
|
|
|
- } else {
|
|
|
- std::string emsg = "Could not read file\n ";
|
|
|
- emsg += item->SourceFile;
|
|
|
- emsg += "\nrequired by moc include \"";
|
|
|
- emsg += item->IncludeString;
|
|
|
- emsg += "\".\n";
|
|
|
- emsg += error;
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, item->Includer, emsg);
|
|
|
- success = false;
|
|
|
- break;
|
|
|
- }
|
|
|
+ return Log().Info(genType, message);
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
|
|
|
+ GeneratorT genType, std::string const& message) const
|
|
|
+{
|
|
|
+ return Log().Warning(genType, message);
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
|
|
|
+ GeneratorT genType, std::string const& filename,
|
|
|
+ std::string const& message) const
|
|
|
+{
|
|
|
+ return Log().WarningFile(genType, filename, message);
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogError(
|
|
|
+ GeneratorT genType, std::string const& message) const
|
|
|
+{
|
|
|
+ Gen().ParallelRegisterJobError();
|
|
|
+ Log().Error(genType, message);
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
|
|
|
+ GeneratorT genType, std::string const& filename,
|
|
|
+ std::string const& message) const
|
|
|
+{
|
|
|
+ Gen().ParallelRegisterJobError();
|
|
|
+ Log().ErrorFile(genType, filename, message);
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
|
|
|
+ GeneratorT genType, std::string const& message,
|
|
|
+ std::vector<std::string> const& command, std::string const& output) const
|
|
|
+{
|
|
|
+ Gen().ParallelRegisterJobError();
|
|
|
+ Log().ErrorCommand(genType, message, command, output);
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
|
|
|
+ GeneratorT genType, ProcessResultT& result,
|
|
|
+ std::vector<std::string> const& command)
|
|
|
+{
|
|
|
+ if (command.empty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create process instance
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> lock(ProcessMutex_);
|
|
|
+ Process_ = cm::make_unique<ReadOnlyProcessT>();
|
|
|
+ Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Send asynchronous process start request to libuv loop
|
|
|
+ ProcessRequest_.send();
|
|
|
+
|
|
|
+ // Log command
|
|
|
+ if (this->Log().Verbose()) {
|
|
|
+ std::string msg = "Running command:\n";
|
|
|
+ msg += QuotedCommand(command);
|
|
|
+ msg += '\n';
|
|
|
+ this->LogInfo(genType, msg);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wait until the process has been finished and destroyed
|
|
|
+ {
|
|
|
+ std::unique_lock<std::mutex> ulock(ProcessMutex_);
|
|
|
+ while (Process_) {
|
|
|
+ ProcessCondition_.wait(ulock);
|
|
|
}
|
|
|
}
|
|
|
- return success;
|
|
|
+ return !result.error();
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief Tests if the file should be ignored for moc scanning
|
|
|
- * @return True if the file should be ignored
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::MocSkip(std::string const& absFilename) const
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::Loop()
|
|
|
{
|
|
|
- if (this->MocEnabled()) {
|
|
|
- // Test if the file name is on the skip list
|
|
|
- if (!ListContains(this->MocSkipList, absFilename)) {
|
|
|
- return false;
|
|
|
+ while (true) {
|
|
|
+ Gen().WorkerSwapJob(JobHandle_);
|
|
|
+ if (JobHandle_) {
|
|
|
+ JobHandle_->Process(*this);
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief Tests if the C++ content requires moc processing
|
|
|
- * @return True if moc is required
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::MocRequired(std::string const& contentText,
|
|
|
- std::string* macroName)
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle)
|
|
|
{
|
|
|
- for (KeyRegExp& filter : this->MocMacroFilters) {
|
|
|
- // Run a simple find string operation before the expensive
|
|
|
- // regular expression check
|
|
|
- if (contentText.find(filter.Key) != std::string::npos) {
|
|
|
- if (filter.RegExp.find(contentText)) {
|
|
|
- // Return macro name on demand
|
|
|
- if (macroName != nullptr) {
|
|
|
- *macroName = filter.Key;
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
+ auto& wrk = *reinterpret_cast<WorkerT*>(handle->data);
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> lock(wrk.ProcessMutex_);
|
|
|
+ if (wrk.Process_ && !wrk.Process_->IsStarted()) {
|
|
|
+ wrk.Process_->start(handle->loop,
|
|
|
+ std::bind(&WorkerT::UVProcessFinished, &wrk));
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
}
|
|
|
|
|
|
-std::string cmQtAutoGeneratorMocUic::MocStringMacros() const
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
|
|
|
{
|
|
|
- std::string res;
|
|
|
- const auto itB = this->MocMacroFilters.cbegin();
|
|
|
- const auto itE = this->MocMacroFilters.cend();
|
|
|
- const auto itL = itE - 1;
|
|
|
- auto itC = itB;
|
|
|
- for (; itC != itE; ++itC) {
|
|
|
- // Separator
|
|
|
- if (itC != itB) {
|
|
|
- if (itC != itL) {
|
|
|
- res += ", ";
|
|
|
- } else {
|
|
|
- res += " or ";
|
|
|
- }
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> lock(ProcessMutex_);
|
|
|
+ if (Process_ && Process_->IsFinished()) {
|
|
|
+ Process_.reset();
|
|
|
}
|
|
|
- // Key
|
|
|
- res += itC->Key;
|
|
|
}
|
|
|
- return res;
|
|
|
+ // Notify idling thread
|
|
|
+ ProcessCondition_.notify_one();
|
|
|
}
|
|
|
|
|
|
-std::string cmQtAutoGeneratorMocUic::MocStringHeaders(
|
|
|
- std::string const& fileBase) const
|
|
|
+cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
|
|
|
+ : Base_(&FileSys())
|
|
|
+ , Moc_(&FileSys())
|
|
|
+ , Stage_(StageT::SETTINGS_READ)
|
|
|
+ , JobsRemain_(0)
|
|
|
+ , JobError_(false)
|
|
|
+ , JobThreadsAbort_(false)
|
|
|
+ , MocAutoFileUpdated_(false)
|
|
|
{
|
|
|
- std::string res = fileBase;
|
|
|
- res += ".{";
|
|
|
- res += cmJoin(this->HeaderExtensions, ",");
|
|
|
- res += "}";
|
|
|
- return res;
|
|
|
+ // Precompile regular expressions
|
|
|
+ Moc_.RegExpInclude.compile(
|
|
|
+ "[\n][ \t]*#[ \t]*include[ \t]+"
|
|
|
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
|
|
|
+ Uic_.RegExpInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+"
|
|
|
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
|
|
|
+
|
|
|
+ // Initialize libuv asynchronous iteration request
|
|
|
+ UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
|
|
|
}
|
|
|
|
|
|
-std::string cmQtAutoGeneratorMocUic::MocFindIncludedHeader(
|
|
|
- std::string const& sourcePath, std::string const& includeBase) const
|
|
|
+cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic()
|
|
|
{
|
|
|
- std::string header;
|
|
|
- // Search in vicinity of the source
|
|
|
- if (!this->FindHeader(header, sourcePath + includeBase)) {
|
|
|
- // Search in include directories
|
|
|
- for (std::string const& path : this->MocIncludePaths) {
|
|
|
- std::string fullPath = path;
|
|
|
- fullPath.push_back('/');
|
|
|
- fullPath += includeBase;
|
|
|
- if (this->FindHeader(header, fullPath)) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- // Sanitize
|
|
|
- if (!header.empty()) {
|
|
|
- header = cmSystemTools::GetRealPath(header);
|
|
|
- }
|
|
|
- return header;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::MocFindIncludedFile(
|
|
|
- std::string& absFile, std::string const& sourcePath,
|
|
|
- std::string const& includeString) const
|
|
|
+bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
|
|
|
{
|
|
|
- bool success = false;
|
|
|
- // Search in vicinity of the source
|
|
|
- {
|
|
|
- std::string testPath = sourcePath;
|
|
|
- testPath += includeString;
|
|
|
- if (cmSystemTools::FileExists(testPath.c_str())) {
|
|
|
- absFile = cmSystemTools::GetRealPath(testPath);
|
|
|
- success = true;
|
|
|
- }
|
|
|
- }
|
|
|
- // Search in include directories
|
|
|
- if (!success) {
|
|
|
- for (std::string const& path : this->MocIncludePaths) {
|
|
|
- std::string fullPath = path;
|
|
|
- fullPath.push_back('/');
|
|
|
- fullPath += includeString;
|
|
|
- if (cmSystemTools::FileExists(fullPath.c_str())) {
|
|
|
- absFile = cmSystemTools::GetRealPath(fullPath);
|
|
|
- success = true;
|
|
|
- break;
|
|
|
+ // -- Meta
|
|
|
+ Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
|
|
|
+
|
|
|
+ // Utility lambdas
|
|
|
+ auto InfoGet = [makefile](const char* key) {
|
|
|
+ return makefile->GetSafeDefinition(key);
|
|
|
+ };
|
|
|
+ auto InfoGetBool = [makefile](const char* key) {
|
|
|
+ return makefile->IsOn(key);
|
|
|
+ };
|
|
|
+ auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
|
|
|
+ std::vector<std::string> list;
|
|
|
+ cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
|
|
|
+ return list;
|
|
|
+ };
|
|
|
+ auto InfoGetLists =
|
|
|
+ [makefile](const char* key) -> std::vector<std::vector<std::string>> {
|
|
|
+ std::vector<std::vector<std::string>> lists;
|
|
|
+ {
|
|
|
+ std::string const value = makefile->GetSafeDefinition(key);
|
|
|
+ std::string::size_type pos = 0;
|
|
|
+ while (pos < value.size()) {
|
|
|
+ std::string::size_type next = value.find(ListSep, pos);
|
|
|
+ std::string::size_type length =
|
|
|
+ (next != std::string::npos) ? next - pos : value.size() - pos;
|
|
|
+ // Remove enclosing braces
|
|
|
+ if (length >= 2) {
|
|
|
+ std::string::const_iterator itBeg = value.begin() + (pos + 1);
|
|
|
+ std::string::const_iterator itEnd = itBeg + (length - 2);
|
|
|
+ {
|
|
|
+ std::string subValue(itBeg, itEnd);
|
|
|
+ std::vector<std::string> list;
|
|
|
+ cmSystemTools::ExpandListArgument(subValue, list);
|
|
|
+ lists.push_back(std::move(list));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pos += length;
|
|
|
+ pos += ListSep.size();
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- return success;
|
|
|
-}
|
|
|
-
|
|
|
-bool cmQtAutoGeneratorMocUic::MocDependFilterPush(std::string const& key,
|
|
|
- std::string const& regExp)
|
|
|
-{
|
|
|
- std::string error;
|
|
|
- if (!key.empty()) {
|
|
|
- if (!regExp.empty()) {
|
|
|
- KeyRegExp filter;
|
|
|
- filter.Key = key;
|
|
|
- if (filter.RegExp.compile(regExp)) {
|
|
|
- this->MocDependFilters.push_back(std::move(filter));
|
|
|
- } else {
|
|
|
- error = "Regular expression compiling failed";
|
|
|
- }
|
|
|
- } else {
|
|
|
- error = "Regular expression is empty";
|
|
|
+ return lists;
|
|
|
+ };
|
|
|
+ auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
|
|
|
+ const char* valueConf = nullptr;
|
|
|
+ {
|
|
|
+ std::string keyConf = key;
|
|
|
+ keyConf += '_';
|
|
|
+ keyConf += InfoConfig();
|
|
|
+ valueConf = makefile->GetDefinition(keyConf);
|
|
|
}
|
|
|
- } else {
|
|
|
- error = "Key is empty";
|
|
|
- }
|
|
|
- if (!error.empty()) {
|
|
|
- std::string emsg = "AUTOMOC_DEPEND_FILTERS: ";
|
|
|
- emsg += error;
|
|
|
- emsg += "\n";
|
|
|
- emsg += " Key: ";
|
|
|
- emsg += cmQtAutoGen::Quoted(key);
|
|
|
- emsg += "\n";
|
|
|
- emsg += " RegExp: ";
|
|
|
- emsg += cmQtAutoGen::Quoted(regExp);
|
|
|
- emsg += "\n";
|
|
|
- this->LogError(cmQtAutoGen::MOC, emsg);
|
|
|
+ if (valueConf == nullptr) {
|
|
|
+ valueConf = makefile->GetSafeDefinition(key);
|
|
|
+ }
|
|
|
+ return std::string(valueConf);
|
|
|
+ };
|
|
|
+ auto InfoGetConfigList =
|
|
|
+ [&InfoGetConfig](const char* key) -> std::vector<std::string> {
|
|
|
+ std::vector<std::string> list;
|
|
|
+ cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
|
|
|
+ return list;
|
|
|
+ };
|
|
|
+
|
|
|
+ // -- Read info file
|
|
|
+ if (!makefile->ReadListFile(InfoFile().c_str())) {
|
|
|
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed");
|
|
|
return false;
|
|
|
}
|
|
|
- return true;
|
|
|
-}
|
|
|
|
|
|
-void cmQtAutoGeneratorMocUic::MocFindDepends(std::string const& absFilename,
|
|
|
- std::string const& contentText,
|
|
|
- std::set<std::string>& depends)
|
|
|
-{
|
|
|
- if (this->MocDependFilters.empty() && contentText.empty()) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- std::vector<std::string> matches;
|
|
|
- for (KeyRegExp& filter : this->MocDependFilters) {
|
|
|
- // Run a simple find string check
|
|
|
- if (contentText.find(filter.Key) != std::string::npos) {
|
|
|
- // Run the expensive regular expression check loop
|
|
|
- const char* contentChars = contentText.c_str();
|
|
|
- while (filter.RegExp.find(contentChars)) {
|
|
|
- std::string match = filter.RegExp.match(1);
|
|
|
- if (!match.empty()) {
|
|
|
- matches.emplace_back(std::move(match));
|
|
|
- }
|
|
|
- contentChars += filter.RegExp.end();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // -- Meta
|
|
|
+ Base_.MultiConfig = MultiConfigType(InfoGet("AM_MULTI_CONFIG"));
|
|
|
|
|
|
- if (!matches.empty()) {
|
|
|
- std::string const sourcePath = SubDirPrefix(absFilename);
|
|
|
- for (std::string const& match : matches) {
|
|
|
- // Find the dependency file
|
|
|
- std::string incFile;
|
|
|
- if (this->MocFindIncludedFile(incFile, sourcePath, match)) {
|
|
|
- depends.insert(incFile);
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " +
|
|
|
- cmQtAutoGen::Quoted(absFilename) + "\n " +
|
|
|
- cmQtAutoGen::Quoted(incFile));
|
|
|
- }
|
|
|
- } else {
|
|
|
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename,
|
|
|
- "Could not find dependency file " +
|
|
|
- cmQtAutoGen::Quoted(match));
|
|
|
- }
|
|
|
- }
|
|
|
+ Base_.ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX");
|
|
|
+ if (Base_.ConfigSuffix.empty()) {
|
|
|
+ Base_.ConfigSuffix = "_";
|
|
|
+ Base_.ConfigSuffix += InfoConfig();
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::MocParseSourceContent(
|
|
|
- std::string const& absFilename, std::string const& contentText)
|
|
|
-{
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
|
|
|
- }
|
|
|
-
|
|
|
- auto AddJob = [this, &absFilename](std::string const& sourceFile,
|
|
|
- std::string const& includeString,
|
|
|
- std::string const* content) {
|
|
|
- auto job = cm::make_unique<MocJobIncluded>();
|
|
|
- job->SourceFile = sourceFile;
|
|
|
- job->BuildFileRel = this->AutogenIncludeDir;
|
|
|
- job->BuildFileRel += includeString;
|
|
|
- job->Includer = absFilename;
|
|
|
- job->IncludeString = includeString;
|
|
|
- job->DependsValid = (content != nullptr);
|
|
|
- if (job->DependsValid) {
|
|
|
- this->MocFindDepends(sourceFile, *content, job->Depends);
|
|
|
- }
|
|
|
- this->MocJobsIncluded.push_back(std::move(job));
|
|
|
- };
|
|
|
|
|
|
- struct MocInc
|
|
|
- {
|
|
|
- std::string Inc; // full include string
|
|
|
- std::string Dir; // include string directory
|
|
|
- std::string Base; // include string file base
|
|
|
- };
|
|
|
+ SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
|
|
|
+ if (SettingsFile_.empty()) {
|
|
|
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // Extract moc includes from file
|
|
|
- std::vector<MocInc> mocIncsUsc;
|
|
|
- std::vector<MocInc> mocIncsDot;
|
|
|
{
|
|
|
- const char* contentChars = contentText.c_str();
|
|
|
- if (strstr(contentChars, "moc") != nullptr) {
|
|
|
- while (this->MocRegExpInclude.find(contentChars)) {
|
|
|
- std::string incString = this->MocRegExpInclude.match(1);
|
|
|
- std::string incDir(SubDirPrefix(incString));
|
|
|
- std::string incBase =
|
|
|
- cmSystemTools::GetFilenameWithoutLastExtension(incString);
|
|
|
- if (cmHasLiteralPrefix(incBase, "moc_")) {
|
|
|
- // moc_<BASE>.cxx
|
|
|
- // Remove the moc_ part from the base name
|
|
|
- mocIncsUsc.push_back(MocInc{ std::move(incString), std::move(incDir),
|
|
|
- incBase.substr(4) });
|
|
|
- } else {
|
|
|
- // <BASE>.moc
|
|
|
- mocIncsDot.push_back(MocInc{ std::move(incString), std::move(incDir),
|
|
|
- std::move(incBase) });
|
|
|
- }
|
|
|
- // Forward content pointer
|
|
|
- contentChars += this->MocRegExpInclude.end();
|
|
|
- }
|
|
|
+ unsigned long num = Base_.NumThreads;
|
|
|
+ if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL"), &num)) {
|
|
|
+ num = std::max<unsigned long>(num, 1);
|
|
|
+ num = std::min<unsigned long>(num, ParallelMax);
|
|
|
+ Base_.NumThreads = static_cast<unsigned int>(num);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- std::string selfMacroName;
|
|
|
- const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName);
|
|
|
-
|
|
|
- // Check if there is anything to do
|
|
|
- if (!selfRequiresMoc && mocIncsUsc.empty() && mocIncsDot.empty()) {
|
|
|
- return true;
|
|
|
+ // - 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 =
|
|
|
+ InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
|
|
|
+ Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
|
|
|
+ if (Base_.AutogenBuildDir.empty()) {
|
|
|
+ Log().ErrorFile(GeneratorT::GEN, InfoFile(),
|
|
|
+ "Autogen build directory missing");
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- // Scan file variables
|
|
|
- std::string const scanFileDir = SubDirPrefix(absFilename);
|
|
|
- std::string const scanFileBase =
|
|
|
- cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
|
|
|
- // Relaxed mode variables
|
|
|
- bool ownDotMocIncluded = false;
|
|
|
- std::string ownMocUscInclude;
|
|
|
- std::string ownMocUscHeader;
|
|
|
-
|
|
|
- // Process moc_<BASE>.cxx includes
|
|
|
- for (const MocInc& mocInc : mocIncsUsc) {
|
|
|
- std::string const header =
|
|
|
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
|
|
|
- if (!header.empty()) {
|
|
|
- // Check if header is skipped
|
|
|
- if (this->MocSkip(header)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Register moc job
|
|
|
- AddJob(header, mocInc.Inc, nullptr);
|
|
|
- // Store meta information for relaxed mode
|
|
|
- if (this->MocRelaxedMode && (mocInc.Base == scanFileBase)) {
|
|
|
- ownMocUscInclude = mocInc.Inc;
|
|
|
- ownMocUscHeader = header;
|
|
|
- }
|
|
|
- } else {
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += ", but could not find the header ";
|
|
|
- emsg += cmQtAutoGen::Quoted(this->MocStringHeaders(mocInc.Base));
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
- return false;
|
|
|
+ // - Qt environment
|
|
|
+ {
|
|
|
+ unsigned long qtv = Base_.QtVersionMajor;
|
|
|
+ if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), &qtv)) {
|
|
|
+ Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Process <BASE>.moc includes
|
|
|
- for (const MocInc& mocInc : mocIncsDot) {
|
|
|
- const bool ownMoc = (mocInc.Base == scanFileBase);
|
|
|
- if (this->MocRelaxedMode) {
|
|
|
- // Relaxed mode
|
|
|
- if (selfRequiresMoc && ownMoc) {
|
|
|
- // Add self
|
|
|
- AddJob(absFilename, mocInc.Inc, &contentText);
|
|
|
- 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 =
|
|
|
- this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base);
|
|
|
- if (!header.empty()) {
|
|
|
- // Check if header is skipped
|
|
|
- if (this->MocSkip(header)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Register moc job
|
|
|
- AddJob(header, mocInc.Inc, nullptr);
|
|
|
- if (!selfRequiresMoc) {
|
|
|
- if (ownMoc) {
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += ", but does not contain a ";
|
|
|
- emsg += this->MocStringMacros();
|
|
|
- emsg += " macro.\nRunning moc on\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(header);
|
|
|
- emsg += "!\nBetter include ";
|
|
|
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
|
|
|
- emsg += " for a compatibility with strict mode.\n"
|
|
|
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
|
|
|
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
+ // - Moc
|
|
|
+ Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
|
|
|
+ Moc_.Enabled = !Moc().Executable.empty();
|
|
|
+ if (Moc().Enabled) {
|
|
|
+ {
|
|
|
+ auto lst = InfoGetList("AM_MOC_SKIP");
|
|
|
+ Moc_.SkipList.insert(lst.begin(), lst.end());
|
|
|
+ }
|
|
|
+ Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
|
|
|
+#ifdef _WIN32
|
|
|
+ {
|
|
|
+ std::string win32("WIN32");
|
|
|
+ auto itB = Moc().Definitions.cbegin();
|
|
|
+ auto itE = Moc().Definitions.cend();
|
|
|
+ if (std::find(itB, itE, win32) == itE) {
|
|
|
+ Moc_.Definitions.emplace_back(std::move(win32));
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
|
|
|
+ Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
|
|
|
+ Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
|
|
|
+ for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
|
|
|
+ Moc_.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.push_back(KeyExpT());
|
|
|
+ KeyExpT& filter(Moc_.DependFilters.back());
|
|
|
+ if (filter.Exp.compile(exp)) {
|
|
|
+ filter.Key = key;
|
|
|
} else {
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += " instead of ";
|
|
|
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
|
|
|
- emsg += ".\nRunning moc on\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(header);
|
|
|
- emsg += "!\nBetter include ";
|
|
|
- emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp");
|
|
|
- emsg += " for compatibility with strict mode.\n"
|
|
|
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
|
|
|
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
+ error = "Regular expression compiling failed";
|
|
|
}
|
|
|
+ } else {
|
|
|
+ error = "Regular expression is empty";
|
|
|
}
|
|
|
} else {
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += ", which seems to be the moc file from a different "
|
|
|
- "source file. CMake also could not find a matching "
|
|
|
- "header.";
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
- return false;
|
|
|
+ error = "Key is empty";
|
|
|
}
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Strict mode
|
|
|
- if (ownMoc) {
|
|
|
- // Include self
|
|
|
- AddJob(absFilename, mocInc.Inc, &contentText);
|
|
|
- ownDotMocIncluded = true;
|
|
|
- // Accept but issue a warning if moc isn't required
|
|
|
- if (!selfRequiresMoc) {
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += ", but does not contain a ";
|
|
|
- emsg += this->MocStringMacros();
|
|
|
- emsg += " macro.";
|
|
|
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
+ if (!error.empty()) {
|
|
|
+ error = ("AUTOMOC_DEPEND_FILTERS: " + error);
|
|
|
+ error += "\n";
|
|
|
+ error += " Key: ";
|
|
|
+ error += Quoted(key);
|
|
|
+ error += "\n";
|
|
|
+ error += " Exp: ";
|
|
|
+ error += Quoted(exp);
|
|
|
+ error += "\n";
|
|
|
}
|
|
|
- } else {
|
|
|
- // Don't allow <BASE>.moc include other than self in strict mode
|
|
|
- std::string emsg = "The file includes the moc file ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocInc.Inc);
|
|
|
- emsg += ", which seems to be the moc file from a different "
|
|
|
- "source file.\nThis is not supported. Include ";
|
|
|
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
|
|
|
- emsg += " to run moc on this source file.";
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- if (selfRequiresMoc && !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.
|
|
|
- if (this->MocRelaxedMode && !ownMocUscInclude.empty()) {
|
|
|
- // This is for KDE4 compatibility:
|
|
|
- std::string emsg = "The file contains a ";
|
|
|
- emsg += selfMacroName;
|
|
|
- emsg += " macro, but does not include ";
|
|
|
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
|
|
|
- emsg += ". Instead it includes ";
|
|
|
- emsg += cmQtAutoGen::Quoted(ownMocUscInclude);
|
|
|
- emsg += ".\nRunning moc on\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(absFilename);
|
|
|
- emsg += "!\nBetter include ";
|
|
|
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
|
|
|
- emsg += " for compatibility with strict mode.\n"
|
|
|
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
|
|
|
- this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
-
|
|
|
- // Remove own header job
|
|
|
+ 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
|
|
|
{
|
|
|
- auto itC = this->MocJobsIncluded.begin();
|
|
|
- auto itE = this->MocJobsIncluded.end();
|
|
|
- for (; itC != itE; ++itC) {
|
|
|
- if ((*itC)->SourceFile == ownMocUscHeader) {
|
|
|
- if ((*itC)->IncludeString == ownMocUscInclude) {
|
|
|
- this->MocJobsIncluded.erase(itC);
|
|
|
+ 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(
|
|
|
+ GeneratorT::MOC, InfoFile(),
|
|
|
+ "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
- // Add own source job
|
|
|
- AddJob(absFilename, ownMocUscInclude, &contentText);
|
|
|
- } else {
|
|
|
- // Otherwise always error out since it will not compile:
|
|
|
- std::string emsg = "The file contains a ";
|
|
|
- emsg += selfMacroName;
|
|
|
- emsg += " macro, but does not include ";
|
|
|
- emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc");
|
|
|
- emsg += "!\nConsider to\n - add #include \"";
|
|
|
- emsg += scanFileBase;
|
|
|
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg);
|
|
|
- return false;
|
|
|
+ if (!error.empty()) {
|
|
|
+ Log().ErrorFile(GeneratorT::MOC, InfoFile(), error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
|
|
|
+ // Install moc predefs job
|
|
|
+ if (!Moc().PredefsCmd.empty()) {
|
|
|
+ JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT());
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
-}
|
|
|
|
|
|
-void cmQtAutoGeneratorMocUic::MocParseHeaderContent(
|
|
|
- std::string const& absFilename, std::string const& contentText)
|
|
|
-{
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename);
|
|
|
- }
|
|
|
-
|
|
|
- auto const fit =
|
|
|
- std::find_if(this->MocJobsIncluded.cbegin(), this->MocJobsIncluded.cend(),
|
|
|
- [&absFilename](std::unique_ptr<MocJobIncluded> const& job) {
|
|
|
- return job->SourceFile == absFilename;
|
|
|
- });
|
|
|
- if (fit == this->MocJobsIncluded.cend()) {
|
|
|
- if (this->MocRequired(contentText)) {
|
|
|
- auto job = cm::make_unique<MocJobAuto>();
|
|
|
- job->SourceFile = absFilename;
|
|
|
- {
|
|
|
- std::string& bld = job->BuildFileRel;
|
|
|
- bld = this->FilePathChecksum.getPart(absFilename);
|
|
|
- bld += '/';
|
|
|
- bld += "moc_";
|
|
|
- bld += cmSystemTools::GetFilenameWithoutLastExtension(absFilename);
|
|
|
- if (this->MultiConfig != cmQtAutoGen::SINGLE) {
|
|
|
- bld += this->ConfigSuffix;
|
|
|
- }
|
|
|
- bld += ".cpp";
|
|
|
+ // - Uic
|
|
|
+ Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
|
|
|
+ Uic_.Enabled = !Uic().Executable.empty();
|
|
|
+ if (Uic().Enabled) {
|
|
|
+ {
|
|
|
+ auto lst = InfoGetList("AM_UIC_SKIP");
|
|
|
+ Uic_.SkipList.insert(lst.begin(), lst.end());
|
|
|
+ }
|
|
|
+ Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
|
|
|
+ Uic_.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 missmatch (" << sources.size() << "/"
|
|
|
+ << options.size() << ")";
|
|
|
+ Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ auto fitEnd = sources.cend();
|
|
|
+ auto fit = sources.begin();
|
|
|
+ auto oit = options.begin();
|
|
|
+ while (fit != fitEnd) {
|
|
|
+ Uic_.Options[*fit] = std::move(*oit);
|
|
|
+ ++fit;
|
|
|
+ ++oit;
|
|
|
}
|
|
|
- this->MocFindDepends(absFilename, contentText, job->Depends);
|
|
|
- this->MocJobsAuto.push_back(std::move(job));
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-bool cmQtAutoGeneratorMocUic::MocGenerateAll()
|
|
|
-{
|
|
|
- if (!this->MocEnabled()) {
|
|
|
- return true;
|
|
|
- }
|
|
|
|
|
|
- // Look for name collisions in included moc files
|
|
|
+ // Initialize source file jobs
|
|
|
{
|
|
|
- bool collision = false;
|
|
|
- std::map<std::string, std::vector<MocJobIncluded const*>> collisions;
|
|
|
- for (auto const& job : this->MocJobsIncluded) {
|
|
|
- auto& list = collisions[job->IncludeString];
|
|
|
- if (!list.empty()) {
|
|
|
- collision = true;
|
|
|
- }
|
|
|
- list.push_back(job.get());
|
|
|
- }
|
|
|
- if (collision) {
|
|
|
- std::string emsg =
|
|
|
- "Included moc files with the same name will be "
|
|
|
- "generated from different sources.\n"
|
|
|
- "Consider 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"
|
|
|
- "Include conflicts\n"
|
|
|
- "-----------------\n";
|
|
|
- const auto& colls = collisions;
|
|
|
- for (auto const& coll : colls) {
|
|
|
- if (coll.second.size() > 1) {
|
|
|
- emsg += cmQtAutoGen::Quoted(coll.first);
|
|
|
- emsg += " included in\n";
|
|
|
- for (const MocJobIncluded* job : coll.second) {
|
|
|
- emsg += " - ";
|
|
|
- emsg += cmQtAutoGen::Quoted(job->Includer);
|
|
|
- emsg += "\n";
|
|
|
- }
|
|
|
- emsg += "would be generated from\n";
|
|
|
- for (const MocJobIncluded* job : coll.second) {
|
|
|
- emsg += " - ";
|
|
|
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
|
|
|
- emsg += "\n";
|
|
|
+ std::hash<std::string> stringHash;
|
|
|
+ std::set<std::size_t> uniqueHeaders;
|
|
|
+
|
|
|
+ // Add header jobs
|
|
|
+ for (std::string& hdr : InfoGetList("AM_HEADERS")) {
|
|
|
+ const bool moc = !Moc().skipped(hdr);
|
|
|
+ const bool uic = !Uic().skipped(hdr);
|
|
|
+ if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) {
|
|
|
+ JobQueues_.Headers.emplace_back(
|
|
|
+ new JobParseT(std::move(hdr), moc, uic, true));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Add source jobs
|
|
|
+ {
|
|
|
+ std::vector<std::string> sources = InfoGetList("AM_SOURCES");
|
|
|
+ // Add header(s) for the source file
|
|
|
+ for (std::string& src : sources) {
|
|
|
+ const bool srcMoc = !Moc().skipped(src);
|
|
|
+ const bool srcUic = !Uic().skipped(src);
|
|
|
+ if (!srcMoc && !srcUic) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // Search for the default header file and a private header
|
|
|
+ {
|
|
|
+ std::array<std::string, 2> bases;
|
|
|
+ bases[0] = SubDirPrefix(src);
|
|
|
+ bases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src);
|
|
|
+ bases[1] = bases[0];
|
|
|
+ bases[1] += "_p";
|
|
|
+ for (std::string const& headerBase : bases) {
|
|
|
+ std::string header;
|
|
|
+ if (Base().FindHeader(header, headerBase)) {
|
|
|
+ const bool moc = srcMoc && !Moc().skipped(header);
|
|
|
+ const bool uic = srcUic && !Uic().skipped(header);
|
|
|
+ if ((moc || uic) &&
|
|
|
+ uniqueHeaders.emplace(stringHash(header)).second) {
|
|
|
+ JobQueues_.Headers.emplace_back(
|
|
|
+ new JobParseT(std::move(header), moc, uic, true));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ // Add source job
|
|
|
+ JobQueues_.Sources.emplace_back(
|
|
|
+ new JobParseT(std::move(src), srcMoc, srcUic));
|
|
|
}
|
|
|
- this->LogError(cmQtAutoGen::MOC, emsg);
|
|
|
- return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // (Re)generate moc_predefs.h on demand
|
|
|
- if (!this->MocPredefsCmd.empty()) {
|
|
|
- if (this->MocSettingsChanged ||
|
|
|
- !cmSystemTools::FileExists(this->MocPredefsFileAbs)) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel);
|
|
|
+ // Init derived information
|
|
|
+ // ------------------------
|
|
|
+
|
|
|
+ // Init file path checksum generator
|
|
|
+ Base_.FilePathChecksum.setupParentDirs(
|
|
|
+ Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
|
|
|
+ Base().ProjectBinaryDir);
|
|
|
+
|
|
|
+ // include directory
|
|
|
+ Base_.AutogenIncludeDirRel = "include";
|
|
|
+ if (Base().MultiConfig != MultiConfigT::SINGLE) {
|
|
|
+ Base_.AutogenIncludeDirRel += Base().ConfigSuffix;
|
|
|
+ }
|
|
|
+ Base_.AutogenIncludeDirRel += "/";
|
|
|
+ Base_.AutogenIncludeDirAbs =
|
|
|
+ Base_.AbsoluteBuildPath(Base().AutogenIncludeDirRel);
|
|
|
+
|
|
|
+ // Moc variables
|
|
|
+ if (Moc().Enabled) {
|
|
|
+ // Mocs compilation file
|
|
|
+ Moc_.CompFileRel = "mocs_compilation";
|
|
|
+ if (Base_.MultiConfig == MultiConfigT::MULTI) {
|
|
|
+ Moc_.CompFileRel += Base().ConfigSuffix;
|
|
|
+ }
|
|
|
+ Moc_.CompFileRel += ".cpp";
|
|
|
+ Moc_.CompFileAbs = Base_.AbsoluteBuildPath(Moc().CompFileRel);
|
|
|
+
|
|
|
+ // Moc predefs file
|
|
|
+ if (!Moc_.PredefsCmd.empty()) {
|
|
|
+ Moc_.PredefsFileRel = "moc_predefs";
|
|
|
+ if (Base_.MultiConfig != MultiConfigT::SINGLE) {
|
|
|
+ Moc_.PredefsFileRel += Base().ConfigSuffix;
|
|
|
}
|
|
|
+ Moc_.PredefsFileRel += ".h";
|
|
|
+ Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
|
|
|
+ }
|
|
|
|
|
|
- std::string output;
|
|
|
+ // Sort include directories on demand
|
|
|
+ if (Base().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());
|
|
|
+ // Append project directories only
|
|
|
{
|
|
|
- // Compose command
|
|
|
- std::vector<std::string> cmd = this->MocPredefsCmd;
|
|
|
- // Add includes
|
|
|
- cmd.insert(cmd.end(), this->MocIncludes.begin(),
|
|
|
- this->MocIncludes.end());
|
|
|
- // Add definitions
|
|
|
- for (std::string const& def : this->MocDefinitions) {
|
|
|
- cmd.push_back("-D" + def);
|
|
|
- }
|
|
|
- // Execute command
|
|
|
- if (!this->RunCommand(cmd, output)) {
|
|
|
- this->LogCommandError(cmQtAutoGen::MOC,
|
|
|
- "moc_predefs generation failed", cmd, output);
|
|
|
- return false;
|
|
|
+ std::array<std::string const*, 2> const movePaths = {
|
|
|
+ { &Base().ProjectBinaryDir, &Base().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);
|
|
|
+ it = includes.erase(it);
|
|
|
+ } else {
|
|
|
+ ++it;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // (Re)write predefs file only on demand
|
|
|
- if (this->FileDiffers(this->MocPredefsFileAbs, output)) {
|
|
|
- if (this->FileWrite(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
|
|
|
- output)) {
|
|
|
- this->MocPredefsChanged = true;
|
|
|
- } else {
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, this->MocPredefsFileAbs,
|
|
|
- "moc_predefs file writing failed");
|
|
|
- return false;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Touch to update the time stamp
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::MOC,
|
|
|
- "Touching moc_predefs " + this->MocPredefsFileRel);
|
|
|
+ // Append remaining directories
|
|
|
+ Moc_.IncludePaths.insert(Moc_.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);
|
|
|
+ // Extract framework path
|
|
|
+ if (cmHasLiteralSuffix(path, ".framework/Headers")) {
|
|
|
+ // Go up twice to get to the framework root
|
|
|
+ std::vector<std::string> pathComponents;
|
|
|
+ cmSystemTools::SplitPath(path, pathComponents);
|
|
|
+ std::string frameworkPath = cmSystemTools::JoinPath(
|
|
|
+ pathComponents.begin(), pathComponents.end() - 2);
|
|
|
+ frameworkPaths.insert(frameworkPath);
|
|
|
}
|
|
|
- cmSystemTools::Touch(this->MocPredefsFileAbs, false);
|
|
|
+ }
|
|
|
+ // Append framework includes
|
|
|
+ for (std::string const& path : frameworkPaths) {
|
|
|
+ Moc_.Includes.push_back("-F");
|
|
|
+ Moc_.Includes.push_back(path);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // Add moc_predefs.h to moc file dependencies
|
|
|
- for (auto const& item : this->MocJobsIncluded) {
|
|
|
- item->Depends.insert(this->MocPredefsFileAbs);
|
|
|
- }
|
|
|
- for (auto const& item : this->MocJobsAuto) {
|
|
|
- item->Depends.insert(this->MocPredefsFileAbs);
|
|
|
+ // Setup single list with all options
|
|
|
+ {
|
|
|
+ // Add includes
|
|
|
+ Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
|
|
|
+ Moc().Includes.end());
|
|
|
+ // Add definitions
|
|
|
+ for (std::string const& def : Moc().Definitions) {
|
|
|
+ Moc_.AllOptions.push_back("-D" + def);
|
|
|
+ }
|
|
|
+ // Add options
|
|
|
+ Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
|
|
|
+ Moc().Options.end());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Generate moc files that are included by source files.
|
|
|
- for (auto const& item : this->MocJobsIncluded) {
|
|
|
- if (!this->MocGenerateFile(*item)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- // Generate moc files that are _not_ included by source files.
|
|
|
- bool autoNameGenerated = false;
|
|
|
- for (auto const& item : this->MocJobsAuto) {
|
|
|
- if (!this->MocGenerateFile(*item, &autoNameGenerated)) {
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool cmQtAutoGeneratorMocUic::Process()
|
|
|
+{
|
|
|
+ // Run libuv event loop
|
|
|
+ UVRequest().send();
|
|
|
+ if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
|
|
|
+ if (JobError_) {
|
|
|
return false;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
}
|
|
|
+ return true;
|
|
|
+}
|
|
|
|
|
|
- // Compose mocs compilation file content
|
|
|
- {
|
|
|
- std::string mocs =
|
|
|
- "// This file is autogenerated. Changes will be overwritten.\n";
|
|
|
- if (this->MocJobsAuto.empty()) {
|
|
|
- // Placeholder content
|
|
|
- mocs +=
|
|
|
- "// No files found that require moc or the moc files are included\n";
|
|
|
- mocs += "enum some_compilers { need_more_than_nothing };\n";
|
|
|
- } else {
|
|
|
- // Valid content
|
|
|
- for (const auto& item : this->MocJobsAuto) {
|
|
|
- mocs += "#include \"";
|
|
|
- mocs += item->BuildFileRel;
|
|
|
- mocs += "\"\n";
|
|
|
- }
|
|
|
- }
|
|
|
+void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle)
|
|
|
+{
|
|
|
+ reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage();
|
|
|
+}
|
|
|
|
|
|
- if (this->FileDiffers(this->MocCompFileAbs, mocs)) {
|
|
|
- // Actually write mocs compilation file
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogBold("Generating MOC compilation " + this->MocCompFileRel);
|
|
|
+void cmQtAutoGeneratorMocUic::PollStage()
|
|
|
+{
|
|
|
+ switch (Stage_) {
|
|
|
+ case StageT::SETTINGS_READ:
|
|
|
+ SettingsFileRead();
|
|
|
+ SetStage(StageT::CREATE_DIRECTORIES);
|
|
|
+ break;
|
|
|
+ case StageT::CREATE_DIRECTORIES:
|
|
|
+ CreateDirectories();
|
|
|
+ SetStage(StageT::PARSE_SOURCES);
|
|
|
+ break;
|
|
|
+ case StageT::PARSE_SOURCES:
|
|
|
+ if (ThreadsStartJobs(JobQueues_.Sources)) {
|
|
|
+ SetStage(StageT::PARSE_HEADERS);
|
|
|
}
|
|
|
- if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) {
|
|
|
- this->LogFileError(cmQtAutoGen::MOC, this->MocCompFileAbs,
|
|
|
- "mocs compilation file writing failed");
|
|
|
- return false;
|
|
|
+ break;
|
|
|
+ case StageT::PARSE_HEADERS:
|
|
|
+ if (ThreadsStartJobs(JobQueues_.Headers)) {
|
|
|
+ SetStage(StageT::MOC_PREDEFS);
|
|
|
}
|
|
|
- } else if (autoNameGenerated) {
|
|
|
- // Only touch mocs compilation file
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::MOC,
|
|
|
- "Touching mocs compilation " + this->MocCompFileRel);
|
|
|
+ break;
|
|
|
+ case StageT::MOC_PREDEFS:
|
|
|
+ if (ThreadsStartJobs(JobQueues_.MocPredefs)) {
|
|
|
+ SetStage(StageT::MOC_PROCESS);
|
|
|
}
|
|
|
- cmSystemTools::Touch(this->MocCompFileAbs, false);
|
|
|
- }
|
|
|
+ break;
|
|
|
+ case StageT::MOC_PROCESS:
|
|
|
+ if (ThreadsStartJobs(JobQueues_.Moc)) {
|
|
|
+ SetStage(StageT::MOCS_COMPILATION);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case StageT::MOCS_COMPILATION:
|
|
|
+ if (ThreadsJobsDone()) {
|
|
|
+ MocGenerateCompilation();
|
|
|
+ SetStage(StageT::UIC_PROCESS);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case StageT::UIC_PROCESS:
|
|
|
+ if (ThreadsStartJobs(JobQueues_.Uic)) {
|
|
|
+ SetStage(StageT::SETTINGS_WRITE);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case StageT::SETTINGS_WRITE:
|
|
|
+ SettingsFileWrite();
|
|
|
+ SetStage(StageT::FINISH);
|
|
|
+ break;
|
|
|
+ case StageT::FINISH:
|
|
|
+ if (ThreadsJobsDone()) {
|
|
|
+ // Clear all libuv handles
|
|
|
+ ThreadsStop();
|
|
|
+ UVRequest().reset();
|
|
|
+ // Set highest END stage manually
|
|
|
+ Stage_ = StageT::END;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case StageT::END:
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::MocGenerateFile(const MocJobAuto& mocJob,
|
|
|
- bool* generated)
|
|
|
+void cmQtAutoGeneratorMocUic::SetStage(StageT stage)
|
|
|
{
|
|
|
- bool success = true;
|
|
|
-
|
|
|
- std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath(
|
|
|
- this->AutogenBuildDir, mocJob.BuildFileRel);
|
|
|
-
|
|
|
- bool generate = false;
|
|
|
- std::string generateReason;
|
|
|
- if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
|
|
|
- generateReason += " from its source file ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- generateReason += " because it doesn't exist";
|
|
|
- }
|
|
|
- generate = true;
|
|
|
+ if (JobError_) {
|
|
|
+ stage = StageT::FINISH;
|
|
|
}
|
|
|
- if (!generate && this->MocSettingsChanged) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
|
|
|
- generateReason += " from ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- generateReason += " because the MOC settings changed";
|
|
|
- }
|
|
|
- generate = true;
|
|
|
+ // Only allow to increase the stage
|
|
|
+ if (Stage_ < stage) {
|
|
|
+ Stage_ = stage;
|
|
|
+ UVRequest().send();
|
|
|
}
|
|
|
- if (!generate && this->MocPredefsChanged) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
|
|
|
- generateReason += " from ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- generateReason += " because moc_predefs.h changed";
|
|
|
+}
|
|
|
+
|
|
|
+void cmQtAutoGeneratorMocUic::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);
|
|
|
}
|
|
|
- generate = true;
|
|
|
- }
|
|
|
- if (!generate) {
|
|
|
- std::string error;
|
|
|
- if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
|
|
|
- generateReason += " because it's older than its source file ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- }
|
|
|
- generate = true;
|
|
|
- } else {
|
|
|
- if (!error.empty()) {
|
|
|
- this->LogError(cmQtAutoGen::MOC, error);
|
|
|
- success = false;
|
|
|
+ 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, ";");
|
|
|
}
|
|
|
+ str += sep;
|
|
|
+ SettingsStringUic_ = crypt.HashString(str);
|
|
|
}
|
|
|
}
|
|
|
- if (success && !generate) {
|
|
|
- // Test if a dependency file is newer
|
|
|
- std::string error;
|
|
|
- for (std::string const& depFile : mocJob.Depends) {
|
|
|
- if (FileIsOlderThan(mocFileAbs, depFile, &error)) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocFileAbs);
|
|
|
- generateReason += " from ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- generateReason += " because it is older than ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(depFile);
|
|
|
+
|
|
|
+ // Read old settings and compare
|
|
|
+ {
|
|
|
+ std::string content;
|
|
|
+ if (FileSys().FileRead(content, SettingsFile_)) {
|
|
|
+ if (Moc().Enabled) {
|
|
|
+ if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
|
|
|
+ Moc_.SettingsChanged = true;
|
|
|
}
|
|
|
- generate = true;
|
|
|
- break;
|
|
|
}
|
|
|
- if (!error.empty()) {
|
|
|
- this->LogError(cmQtAutoGen::MOC, error);
|
|
|
- success = false;
|
|
|
- break;
|
|
|
+ if (Uic().Enabled) {
|
|
|
+ if (SettingsStringUic_ != SettingsFind(content, "uic")) {
|
|
|
+ Uic_.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_);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Settings file read failed
|
|
|
+ if (Moc().Enabled) {
|
|
|
+ Moc_.SettingsChanged = true;
|
|
|
+ }
|
|
|
+ if (Uic().Enabled) {
|
|
|
+ Uic_.SettingsChanged = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- if (generate) {
|
|
|
- // Log
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogBold("Generating MOC source " + mocJob.BuildFileRel);
|
|
|
- this->LogInfo(cmQtAutoGen::MOC, generateReason);
|
|
|
+void cmQtAutoGeneratorMocUic::SettingsFileWrite()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ // Only write if any setting changed
|
|
|
+ if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
|
|
|
+ if (Log().Verbose()) {
|
|
|
+ Log().Info(GeneratorT::GEN,
|
|
|
+ "Writing settings file " + Quoted(SettingsFile_));
|
|
|
}
|
|
|
-
|
|
|
- // Make sure the parent directory exists
|
|
|
- if (this->MakeParentDirectory(cmQtAutoGen::MOC, mocFileAbs)) {
|
|
|
- // Compose moc command
|
|
|
- std::vector<std::string> cmd;
|
|
|
- cmd.push_back(this->MocExecutable);
|
|
|
- // Add options
|
|
|
- cmd.insert(cmd.end(), this->MocAllOptions.begin(),
|
|
|
- this->MocAllOptions.end());
|
|
|
- // Add predefs include
|
|
|
- if (!this->MocPredefsFileAbs.empty()) {
|
|
|
- cmd.push_back("--include");
|
|
|
- cmd.push_back(this->MocPredefsFileAbs);
|
|
|
- }
|
|
|
- cmd.push_back("-o");
|
|
|
- cmd.push_back(mocFileAbs);
|
|
|
- cmd.push_back(mocJob.SourceFile);
|
|
|
-
|
|
|
- // Execute moc command
|
|
|
- std::string output;
|
|
|
- if (this->RunCommand(cmd, output)) {
|
|
|
- // Success
|
|
|
- if (generated != nullptr) {
|
|
|
- *generated = true;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Moc command failed
|
|
|
- {
|
|
|
- std::string emsg = "moc failed for\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(mocJob.SourceFile);
|
|
|
- this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output);
|
|
|
+ // Compose settings file content
|
|
|
+ std::string content;
|
|
|
+ {
|
|
|
+ auto SettingAppend = [&content](const char* key,
|
|
|
+ std::string const& value) {
|
|
|
+ if (!value.empty()) {
|
|
|
+ content += key;
|
|
|
+ content += ':';
|
|
|
+ content += value;
|
|
|
+ content += '\n';
|
|
|
}
|
|
|
- cmSystemTools::RemoveFile(mocFileAbs);
|
|
|
- success = false;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Parent directory creation failed
|
|
|
- success = false;
|
|
|
+ };
|
|
|
+ SettingAppend("moc", SettingsStringMoc_);
|
|
|
+ SettingAppend("uic", SettingsStringUic_);
|
|
|
+ }
|
|
|
+ // Write settings file
|
|
|
+ if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) {
|
|
|
+ Log().ErrorFile(GeneratorT::GEN, SettingsFile_,
|
|
|
+ "Settings file writing failed");
|
|
|
+ // Remove old settings file to trigger a full rebuild on the next run
|
|
|
+ FileSys().FileRemove(SettingsFile_);
|
|
|
+ RegisterJobError();
|
|
|
}
|
|
|
}
|
|
|
- return success;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief Tests if the file name is in the skip list
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::UicSkip(std::string const& absFilename) const
|
|
|
+void cmQtAutoGeneratorMocUic::CreateDirectories()
|
|
|
{
|
|
|
- if (this->UicEnabled()) {
|
|
|
- // Test if the file name is on the skip list
|
|
|
- if (!ListContains(this->UicSkipList, absFilename)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // Create AUTOGEN include directory
|
|
|
+ if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDirAbs)) {
|
|
|
+ RegisterJobError();
|
|
|
}
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::UicParseContent(std::string const& absFilename,
|
|
|
- std::string const& contentText)
|
|
|
+bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue)
|
|
|
{
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename);
|
|
|
- }
|
|
|
+ bool done = false;
|
|
|
+ std::size_t queueSize = queue.size();
|
|
|
|
|
|
- std::vector<std::string> includes;
|
|
|
- // Extracte includes
|
|
|
+ // Change the active queue
|
|
|
{
|
|
|
- const char* contentChars = contentText.c_str();
|
|
|
- if (strstr(contentChars, "ui_") != nullptr) {
|
|
|
- while (this->UicRegExpInclude.find(contentChars)) {
|
|
|
- includes.push_back(this->UicRegExpInclude.match(1));
|
|
|
- contentChars += this->UicRegExpInclude.end();
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ // Check if there are still unfinished jobs from the previous queue
|
|
|
+ if (JobsRemain_ == 0) {
|
|
|
+ if (!JobThreadsAbort_) {
|
|
|
+ JobQueue_.swap(queue);
|
|
|
+ JobsRemain_ = queueSize;
|
|
|
+ } else {
|
|
|
+ // Abort requested
|
|
|
+ queue.clear();
|
|
|
+ queueSize = 0;
|
|
|
}
|
|
|
+ done = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (std::string const& includeString : includes) {
|
|
|
- std::string uiInputFile;
|
|
|
- if (!UicFindIncludedFile(uiInputFile, absFilename, includeString)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- // Check if this file should be skipped
|
|
|
- if (this->UicSkip(uiInputFile)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Check if the job already exists
|
|
|
- bool jobExists = false;
|
|
|
- for (const auto& job : this->UicJobs) {
|
|
|
- if ((job->SourceFile == uiInputFile) &&
|
|
|
- (job->IncludeString == includeString)) {
|
|
|
- jobExists = true;
|
|
|
- break;
|
|
|
+ if (done && (queueSize != 0)) {
|
|
|
+ // Start new threads on demand
|
|
|
+ if (Workers_.empty()) {
|
|
|
+ Workers_.resize(Base().NumThreads);
|
|
|
+ for (auto& item : Workers_) {
|
|
|
+ item = cm::make_unique<WorkerT>(this, UVLoop());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Notify threads
|
|
|
+ if (queueSize == 1) {
|
|
|
+ JobsConditionRead_.notify_one();
|
|
|
+ } else {
|
|
|
+ JobsConditionRead_.notify_all();
|
|
|
}
|
|
|
- }
|
|
|
- if (!jobExists) {
|
|
|
- auto job = cm::make_unique<UicJob>();
|
|
|
- job->SourceFile = uiInputFile;
|
|
|
- job->BuildFileRel = this->AutogenIncludeDir;
|
|
|
- job->BuildFileRel += includeString;
|
|
|
- job->Includer = absFilename;
|
|
|
- job->IncludeString = includeString;
|
|
|
- this->UicJobs.push_back(std::move(job));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
+ return done;
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::UicFindIncludedFile(
|
|
|
- std::string& absFile, std::string const& sourceFile,
|
|
|
- std::string const& includeString)
|
|
|
+void cmQtAutoGeneratorMocUic::ThreadsStop()
|
|
|
{
|
|
|
- bool success = false;
|
|
|
- std::string searchFile =
|
|
|
- cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3);
|
|
|
- searchFile += ".ui";
|
|
|
- // Collect search paths list
|
|
|
- std::vector<std::string> testFiles;
|
|
|
- {
|
|
|
- std::string const searchPath = SubDirPrefix(includeString);
|
|
|
-
|
|
|
- std::string searchFileFull;
|
|
|
- if (!searchPath.empty()) {
|
|
|
- searchFileFull = searchPath;
|
|
|
- searchFileFull += searchFile;
|
|
|
- }
|
|
|
- // Vicinity of the source
|
|
|
+ if (!Workers_.empty()) {
|
|
|
+ // Clear all jobs
|
|
|
{
|
|
|
- std::string const sourcePath = SubDirPrefix(sourceFile);
|
|
|
- testFiles.push_back(sourcePath + searchFile);
|
|
|
- if (!searchPath.empty()) {
|
|
|
- testFiles.push_back(sourcePath + searchFileFull);
|
|
|
- }
|
|
|
- }
|
|
|
- // AUTOUIC search paths
|
|
|
- if (!this->UicSearchPaths.empty()) {
|
|
|
- for (std::string const& sPath : this->UicSearchPaths) {
|
|
|
- testFiles.push_back((sPath + "/").append(searchFile));
|
|
|
- }
|
|
|
- if (!searchPath.empty()) {
|
|
|
- for (std::string const& sPath : this->UicSearchPaths) {
|
|
|
- testFiles.push_back((sPath + "/").append(searchFileFull));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ JobThreadsAbort_ = true;
|
|
|
+ JobsRemain_ -= JobQueue_.size();
|
|
|
+ JobQueue_.clear();
|
|
|
+
|
|
|
+ JobQueues_.Sources.clear();
|
|
|
+ JobQueues_.Headers.clear();
|
|
|
+ JobQueues_.MocPredefs.clear();
|
|
|
+ JobQueues_.Moc.clear();
|
|
|
+ JobQueues_.Uic.clear();
|
|
|
+ }
|
|
|
+ // Wake threads
|
|
|
+ JobsConditionRead_.notify_all();
|
|
|
+ // Join and clear threads
|
|
|
+ Workers_.clear();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // Search for the .ui file!
|
|
|
- for (std::string const& testFile : testFiles) {
|
|
|
- if (cmSystemTools::FileExists(testFile.c_str())) {
|
|
|
- absFile = cmSystemTools::GetRealPath(testFile);
|
|
|
- success = true;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+bool cmQtAutoGeneratorMocUic::ThreadsJobsDone()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ return (JobsRemain_ == 0);
|
|
|
+}
|
|
|
|
|
|
- // Log error
|
|
|
- if (!success) {
|
|
|
- std::string emsg = "Could not find ";
|
|
|
- emsg += cmQtAutoGen::Quoted(searchFile);
|
|
|
- emsg += " in\n";
|
|
|
- for (std::string const& testFile : testFiles) {
|
|
|
- emsg += " ";
|
|
|
- emsg += cmQtAutoGen::Quoted(testFile);
|
|
|
- emsg += "\n";
|
|
|
+void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle)
|
|
|
+{
|
|
|
+ bool const jobProcessed(jobHandle);
|
|
|
+ if (jobProcessed) {
|
|
|
+ jobHandle.reset(nullptr);
|
|
|
+ }
|
|
|
+ {
|
|
|
+ std::unique_lock<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ // Reduce the remaining job count and notify the libuv loop
|
|
|
+ // when all jobs are done
|
|
|
+ if (jobProcessed) {
|
|
|
+ --JobsRemain_;
|
|
|
+ if (JobsRemain_ == 0) {
|
|
|
+ UVRequest().send();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Wait for new jobs
|
|
|
+ while (!JobThreadsAbort_ && JobQueue_.empty()) {
|
|
|
+ JobsConditionRead_.wait(jobsLock);
|
|
|
+ }
|
|
|
+ // Try to pick up a new job handle
|
|
|
+ if (!JobThreadsAbort_ && !JobQueue_.empty()) {
|
|
|
+ jobHandle = std::move(JobQueue_.front());
|
|
|
+ JobQueue_.pop_front();
|
|
|
}
|
|
|
- this->LogFileError(cmQtAutoGen::UIC, sourceFile, emsg);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return success;
|
|
|
+void cmQtAutoGeneratorMocUic::ParallelRegisterJobError()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ RegisterJobError();
|
|
|
}
|
|
|
|
|
|
-bool cmQtAutoGeneratorMocUic::UicGenerateAll()
|
|
|
+// Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be
|
|
|
+// locked
|
|
|
+void cmQtAutoGeneratorMocUic::RegisterJobError()
|
|
|
{
|
|
|
- if (!this->UicEnabled()) {
|
|
|
- return true;
|
|
|
+ JobError_ = true;
|
|
|
+ if (!JobThreadsAbort_) {
|
|
|
+ JobThreadsAbort_ = true;
|
|
|
+ // Clear remaining jobs
|
|
|
+ if (JobsRemain_ != 0) {
|
|
|
+ JobsRemain_ -= JobQueue_.size();
|
|
|
+ JobQueue_.clear();
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // Look for name collisions in included uic files
|
|
|
- {
|
|
|
- bool collision = false;
|
|
|
- std::map<std::string, std::vector<UicJob const*>> collisions;
|
|
|
- for (auto const& job : this->UicJobs) {
|
|
|
- auto& list = collisions[job->IncludeString];
|
|
|
- if (!list.empty()) {
|
|
|
- collision = true;
|
|
|
- }
|
|
|
- list.push_back(job.get());
|
|
|
- }
|
|
|
- if (collision) {
|
|
|
- std::string emsg =
|
|
|
- "Included uic files with the same name will be "
|
|
|
- "generated from different sources.\n"
|
|
|
- "Consider 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"
|
|
|
- "Include conflicts\n"
|
|
|
- "-----------------\n";
|
|
|
- const auto& colls = collisions;
|
|
|
- for (auto const& coll : colls) {
|
|
|
- if (coll.second.size() > 1) {
|
|
|
- emsg += cmQtAutoGen::Quoted(coll.first);
|
|
|
- emsg += " included in\n";
|
|
|
- for (const UicJob* job : coll.second) {
|
|
|
- emsg += " - ";
|
|
|
- emsg += cmQtAutoGen::Quoted(job->Includer);
|
|
|
- emsg += "\n";
|
|
|
- }
|
|
|
- emsg += "would be generated from\n";
|
|
|
- for (const UicJob* job : coll.second) {
|
|
|
- emsg += " - ";
|
|
|
- emsg += cmQtAutoGen::Quoted(job->SourceFile);
|
|
|
- emsg += "\n";
|
|
|
+bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ if (!JobThreadsAbort_) {
|
|
|
+ bool pushJobHandle = true;
|
|
|
+ // Do additional tests if this is an included moc job
|
|
|
+ const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle));
|
|
|
+ if (!mocJob.IncludeString.empty()) {
|
|
|
+ // Register included moc file and look for collisions
|
|
|
+ MocIncludedFiles_.emplace(mocJob.SourceFile);
|
|
|
+ if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) {
|
|
|
+ // Another source file includes the same moc file!
|
|
|
+ for (const JobHandleT& otherHandle : JobQueues_.Moc) {
|
|
|
+ const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle));
|
|
|
+ if (otherJob.IncludeString == mocJob.IncludeString) {
|
|
|
+ // Check if the same moc file would be generated from different
|
|
|
+ // source files which is an error.
|
|
|
+ if (otherJob.SourceFile != mocJob.SourceFile) {
|
|
|
+ // Include string collision
|
|
|
+ std::string error = "The two source files\n ";
|
|
|
+ error += Quoted(mocJob.IncluderFile);
|
|
|
+ error += " and\n ";
|
|
|
+ error += Quoted(otherJob.IncluderFile);
|
|
|
+ error += "\ncontain the 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(otherJob.SourceFile);
|
|
|
+ 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(GeneratorT::MOC, error);
|
|
|
+ RegisterJobError();
|
|
|
+ }
|
|
|
+ // Do not push this job in since the included moc file already
|
|
|
+ // gets generated by an other job.
|
|
|
+ pushJobHandle = false;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- this->LogError(cmQtAutoGen::UIC, emsg);
|
|
|
- return false;
|
|
|
+ }
|
|
|
+ // Push job on demand
|
|
|
+ if (pushJobHandle) {
|
|
|
+ JobQueues_.Moc.emplace_back(std::move(jobHandle));
|
|
|
}
|
|
|
}
|
|
|
+ return !JobError_;
|
|
|
+}
|
|
|
|
|
|
- // Generate ui header files
|
|
|
- for (const auto& item : this->UicJobs) {
|
|
|
- if (!this->UicGenerateFile(*item)) {
|
|
|
- return false;
|
|
|
+bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> jobsLock(JobsMutex_);
|
|
|
+ if (!JobThreadsAbort_) {
|
|
|
+ bool pushJobHandle = true;
|
|
|
+ // Look for include collisions.
|
|
|
+ const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
|
|
|
+ for (const JobHandleT& otherHandle : JobQueues_.Uic) {
|
|
|
+ const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle));
|
|
|
+ if (otherJob.IncludeString == uicJob.IncludeString) {
|
|
|
+ // Check if the same uic file would be generated from different
|
|
|
+ // source files which would be an error.
|
|
|
+ if (otherJob.SourceFile != uicJob.SourceFile) {
|
|
|
+ // Include string collision
|
|
|
+ std::string error = "The two source files\n ";
|
|
|
+ error += Quoted(uicJob.IncluderFile);
|
|
|
+ error += " and\n ";
|
|
|
+ error += Quoted(otherJob.IncluderFile);
|
|
|
+ error += "\ncontain the 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(otherJob.SourceFile);
|
|
|
+ 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(GeneratorT::UIC, error);
|
|
|
+ RegisterJobError();
|
|
|
+ }
|
|
|
+ // Do not push this job in since the uic file already
|
|
|
+ // gets generated by an other job.
|
|
|
+ pushJobHandle = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (pushJobHandle) {
|
|
|
+ JobQueues_.Uic.emplace_back(std::move(jobHandle));
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
+ return !JobError_;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::UicGenerateFile(const UicJob& uicJob)
|
|
|
+bool cmQtAutoGeneratorMocUic::ParallelMocIncluded(
|
|
|
+ std::string const& sourceFile)
|
|
|
{
|
|
|
- bool success = true;
|
|
|
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
|
|
|
+ return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
|
|
|
+}
|
|
|
|
|
|
- std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath(
|
|
|
- this->AutogenBuildDir, uicJob.BuildFileRel);
|
|
|
+void cmQtAutoGeneratorMocUic::ParallelMocAutoRegister(
|
|
|
+ std::string const& mocFile)
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
|
|
|
+ MocAutoFiles_.emplace(mocFile);
|
|
|
+}
|
|
|
|
|
|
- bool generate = false;
|
|
|
- std::string generateReason;
|
|
|
- if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
|
|
|
- generateReason += " from its source file ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
|
|
|
- generateReason += " because it doesn't exist";
|
|
|
- }
|
|
|
- generate = true;
|
|
|
- }
|
|
|
- if (!generate && this->UicSettingsChanged) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
|
|
|
- generateReason += " from ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
|
|
|
- generateReason += " because the UIC settings changed";
|
|
|
- }
|
|
|
- generate = true;
|
|
|
- }
|
|
|
- if (!generate) {
|
|
|
- std::string error;
|
|
|
- if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) {
|
|
|
- if (this->GetVerbose()) {
|
|
|
- generateReason = "Generating ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicFileAbs);
|
|
|
- generateReason += " because it's older than its source file ";
|
|
|
- generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile);
|
|
|
- }
|
|
|
- generate = true;
|
|
|
- } else {
|
|
|
- if (!error.empty()) {
|
|
|
- this->LogError(cmQtAutoGen::UIC, error);
|
|
|
- success = false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (generate) {
|
|
|
- // Log
|
|
|
- if (this->GetVerbose()) {
|
|
|
- this->LogBold("Generating UIC header " + uicJob.BuildFileRel);
|
|
|
- this->LogInfo(cmQtAutoGen::UIC, generateReason);
|
|
|
- }
|
|
|
+void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
|
|
|
+ MocAutoFileUpdated_ = true;
|
|
|
+}
|
|
|
|
|
|
- // Make sure the parent directory exists
|
|
|
- if (this->MakeParentDirectory(cmQtAutoGen::UIC, uicFileAbs)) {
|
|
|
- // Compose uic command
|
|
|
- std::vector<std::string> cmd;
|
|
|
- cmd.push_back(this->UicExecutable);
|
|
|
- {
|
|
|
- std::vector<std::string> allOpts = this->UicTargetOptions;
|
|
|
- auto optionIt = this->UicOptions.find(uicJob.SourceFile);
|
|
|
- if (optionIt != this->UicOptions.end()) {
|
|
|
- cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second,
|
|
|
- (this->QtVersionMajor == 5));
|
|
|
+void cmQtAutoGeneratorMocUic::MocGenerateCompilation()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> mocLock(JobsMutex_);
|
|
|
+ if (!JobThreadsAbort_ && Moc().Enabled) {
|
|
|
+ // Compose mocs compilation file content
|
|
|
+ {
|
|
|
+ std::string content =
|
|
|
+ "// This file is autogenerated. Changes will be overwritten.\n";
|
|
|
+ if (MocAutoFiles_.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
|
|
|
+ for (std::string const& mocfile : MocAutoFiles_) {
|
|
|
+ content += "#include \"";
|
|
|
+ content += mocfile;
|
|
|
+ content += "\"\n";
|
|
|
}
|
|
|
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
|
|
|
}
|
|
|
- cmd.push_back("-o");
|
|
|
- cmd.push_back(uicFileAbs);
|
|
|
- cmd.push_back(uicJob.SourceFile);
|
|
|
|
|
|
- std::string output;
|
|
|
- if (this->RunCommand(cmd, output)) {
|
|
|
- // Success
|
|
|
- } else {
|
|
|
- // Command failed
|
|
|
- {
|
|
|
- std::string emsg = "uic failed for\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(uicJob.SourceFile);
|
|
|
- emsg += "\nincluded by\n ";
|
|
|
- emsg += cmQtAutoGen::Quoted(uicJob.Includer);
|
|
|
- this->LogCommandError(cmQtAutoGen::UIC, emsg, cmd, output);
|
|
|
+ std::string const& compRel = Moc().CompFileRel;
|
|
|
+ std::string const& compAbs = Moc().CompFileAbs;
|
|
|
+ if (FileSys().FileDiffers(compAbs, content)) {
|
|
|
+ // Actually write mocs compilation file
|
|
|
+ if (Log().Verbose()) {
|
|
|
+ Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compRel);
|
|
|
}
|
|
|
- cmSystemTools::RemoveFile(uicFileAbs);
|
|
|
- success = false;
|
|
|
+ if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) {
|
|
|
+ Log().ErrorFile(GeneratorT::MOC, compAbs,
|
|
|
+ "mocs compilation file writing failed");
|
|
|
+ RegisterJobError();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else if (MocAutoFileUpdated_) {
|
|
|
+ // Only touch mocs compilation file
|
|
|
+ if (Log().Verbose()) {
|
|
|
+ Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compRel);
|
|
|
+ }
|
|
|
+ FileSys().Touch(compAbs);
|
|
|
}
|
|
|
- } else {
|
|
|
- // Parent directory creation failed
|
|
|
- success = false;
|
|
|
- }
|
|
|
- }
|
|
|
- return success;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief Tries to find the header file to the given file base path by
|
|
|
- * appending different header extensions
|
|
|
- * @return True on success
|
|
|
- */
|
|
|
-bool cmQtAutoGeneratorMocUic::FindHeader(std::string& header,
|
|
|
- std::string const& testBasePath) const
|
|
|
-{
|
|
|
- for (std::string const& ext : this->HeaderExtensions) {
|
|
|
- std::string testFilePath(testBasePath);
|
|
|
- testFilePath.push_back('.');
|
|
|
- testFilePath += ext;
|
|
|
- if (cmSystemTools::FileExists(testFilePath.c_str())) {
|
|
|
- header = testFilePath;
|
|
|
- return true;
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
}
|