summaryrefslogtreecommitdiffstats
path: root/Source/cmQtAutoGenInitializer.cxx
diff options
context:
space:
mode:
authorSebastian Holtermann <sebholt@xwmw.org>2019-05-02 09:03:13 (GMT)
committerSebastian Holtermann <sebholt@xwmw.org>2019-05-07 10:42:19 (GMT)
commit7d50e1c6118b292ea3061ec9fee0230c5d50a5ff (patch)
tree48d3f4c459c88cc2c02fa78b0279324e2fbb5cce /Source/cmQtAutoGenInitializer.cxx
parentc6f6e2b3053de02de149e80bd6a0f686a6731f68 (diff)
downloadCMake-7d50e1c6118b292ea3061ec9fee0230c5d50a5ff.zip
CMake-7d50e1c6118b292ea3061ec9fee0230c5d50a5ff.tar.gz
CMake-7d50e1c6118b292ea3061ec9fee0230c5d50a5ff.tar.bz2
Autogen: Refactor AUTOMOC and AUTOUIC and add source file parse data caching
New features ------------ CMake's `AUTOMOC` and `AUTOUIC` now cache information extracted when parsing source files in `CMakeFiles/<ORIGIN>_autogen.dir/ParseCache.txt`. This leads to faster `<ORIGIN>_autogen` target rebuilds, because source files will be parsed again only if they're newer than the `ParseCache.txt` file. The parse cache will be recomputed if it is older than the CMake executable. `AUTOMOC` and `AUTOUIC` now check if `moc` or `uic` output files are older than the `moc` or `uic` executable. If an output file is older than the compiler, it will be regenerated. Therefore if a new `moc` or `uic` version is installed, all output files will be regenerated. `AUTOMOC` and `AUTOUIC` error and warning messages are more detailed. Internal changes ---------------- `moc` and `uic` output file names are not computed in the `_autogen` target anymore but in `cmQtAutoGenInitializer`. This makes the available at the configuration stage for improved dependency computations (to be done). In `AutogenInfo.cmake`, equally sized lists for "source file names", "source file flags" and "compiler output file names" are passed to the `_autogen` target. This replaces the separate file lists for `AUTOMOC` and `AUTOUIC`. Files times are read from the file system only once by using `cmFileTime` instances instead of `cmQtAutoGenerator::FileSystem::FileIsOlderThan` calls. All calls to not thread safe file system functions are moved to non concurrent fence jobs (see `cmWorkerPool::JobT::IsFence()`). This renders the `cmQtAutoGenerator::FileSystem` wrapper class obsolete and it is removed. Instead of composing a single large settings string that is fed to the `cmCryptoHash`, now all setting sub strings are fed one by one to the `cmCryptoHash` and the finalized result is stored. The `std::mutex` in `cmQtAutoGenerator::Logger` is tagged `mutable` and most `cmQtAutoGenerator::Logger` methods become `const`. Outlook ------- This patch provides the framework required to - extract dependencies from `.ui` files in `AUTOUIC`. These will help to address issue #15420 "AUTOUIC: Track uic external inputs". - generate adaptive `make` and `ninja` files in the `_autogen` target. These will help to address issue #16776 "AUTOUIC: Ninja needs two passes to correctly build Qt project". - generate (possibly empty) `moc` and `uic` files for all headers instead of a `mocs_compilation.cpp` file. This will help to address issue #17277 "AUTOMOC: Provide a option to allow AUTOMOC to compile individual " "moc_x.cxx instead of including all in mocs_compilation.cxx"
Diffstat (limited to 'Source/cmQtAutoGenInitializer.cxx')
-rw-r--r--Source/cmQtAutoGenInitializer.cxx147
1 files changed, 104 insertions, 43 deletions
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index be96f1a..38f39fb 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -34,6 +34,7 @@
#include <map>
#include <set>
#include <string>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -77,7 +78,8 @@ static std::string FileProjectRelativePath(cmMakefile* makefile,
return res;
}
-/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its
+/**
+ * Tests if targetDepend is a STATIC_LIBRARY and if any of its
* recursive STATIC_LIBRARY dependencies depends on targetOrigin
* (STATIC_LIBRARY cycle).
*/
@@ -384,6 +386,10 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
} else {
AddCleanFile(makefile, this->AutogenTarget.SettingsFile);
}
+
+ this->AutogenTarget.ParseCacheFile = this->Dir.Info;
+ this->AutogenTarget.ParseCacheFile += "/ParseCache.txt";
+ AddCleanFile(makefile, this->AutogenTarget.ParseCacheFile);
}
// Autogen target: Compute user defined dependencies
@@ -1255,53 +1261,107 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
ofs.Write("AM_INCLUDE_DIR", this->Dir.Include);
ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude);
- // Use sorted sets
- std::set<std::string> headers;
- std::set<std::string> sources;
- std::set<std::string> moc_headers;
- std::set<std::string> moc_sources;
+ std::vector<std::string> headers;
+ std::vector<std::string> headersFlags;
+ std::vector<std::string> headersBuildPaths;
+ std::vector<std::string> sources;
+ std::vector<std::string> sourcesFlags;
std::set<std::string> moc_skip;
- std::set<std::string> uic_headers;
- std::set<std::string> uic_sources;
std::set<std::string> uic_skip;
+
// Filter headers
- for (auto const& pair : this->AutogenTarget.Headers) {
- MUFile const& muf = *pair.second;
- if (muf.Generated && !this->CMP0071Accept) {
- continue;
- }
- if (muf.SkipMoc) {
- moc_skip.insert(muf.RealPath);
+ {
+ auto headerCount = this->AutogenTarget.Headers.size();
+ headers.reserve(headerCount);
+ headersFlags.reserve(headerCount);
+
+ std::vector<MUFile const*> sortedHeaders;
+ {
+ sortedHeaders.reserve(headerCount);
+ for (auto const& pair : this->AutogenTarget.Headers) {
+ sortedHeaders.emplace_back(pair.second.get());
+ }
+ std::sort(sortedHeaders.begin(), sortedHeaders.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
}
- if (muf.SkipUic) {
- uic_skip.insert(muf.RealPath);
+
+ for (MUFile const* const muf : sortedHeaders) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ headers.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ headersFlags.emplace_back(std::move(flags));
+ }
}
- if (muf.MocIt && muf.UicIt) {
- headers.insert(muf.RealPath);
- } else if (muf.MocIt) {
- moc_headers.insert(muf.RealPath);
- } else if (muf.UicIt) {
- uic_headers.insert(muf.RealPath);
+ }
+ // Header build paths
+ {
+ cmFilePathChecksum const fpathCheckSum(makefile);
+ std::unordered_set<std::string> emitted;
+ for (std::string const& hdr : headers) {
+ std::string basePath = fpathCheckSum.getPart(hdr);
+ basePath += "/moc_";
+ basePath += cmSystemTools::GetFilenameWithoutLastExtension(hdr);
+ for (unsigned int ii = 1; ii != 1024; ++ii) {
+ std::string path = basePath;
+ if (ii > 1) {
+ path += '_';
+ path += std::to_string(ii);
+ }
+ path += ".cpp";
+ if (emitted.emplace(path).second) {
+ headersBuildPaths.emplace_back(std::move(path));
+ break;
+ }
+ }
}
}
+
// Filter sources
- for (auto const& pair : this->AutogenTarget.Sources) {
- MUFile const& muf = *pair.second;
- if (muf.Generated && !this->CMP0071Accept) {
- continue;
- }
- if (muf.SkipMoc) {
- moc_skip.insert(muf.RealPath);
- }
- if (muf.SkipUic) {
- uic_skip.insert(muf.RealPath);
+ {
+ auto sourcesCount = this->AutogenTarget.Sources.size();
+ sources.reserve(sourcesCount);
+ sourcesFlags.reserve(sourcesCount);
+
+ std::vector<MUFile const*> sorted;
+ sorted.reserve(sourcesCount);
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ sorted.emplace_back(pair.second.get());
}
- if (muf.MocIt && muf.UicIt) {
- sources.insert(muf.RealPath);
- } else if (muf.MocIt) {
- moc_sources.insert(muf.RealPath);
- } else if (muf.UicIt) {
- uic_sources.insert(muf.RealPath);
+ std::sort(sorted.begin(), sorted.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
+
+ for (MUFile const* const muf : sorted) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ sources.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ sourcesFlags.emplace_back(std::move(flags));
+ }
}
}
@@ -1311,17 +1371,20 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable);
ofs.Write("# Files\n");
+ ofs.Write("AM_CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
ofs.WriteConfig("AM_SETTINGS_FILE",
this->AutogenTarget.ConfigSettingsFile);
+ ofs.Write("AM_PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
ofs.WriteStrings("AM_HEADERS", headers);
+ ofs.WriteStrings("AM_HEADERS_FLAGS", headersFlags);
+ ofs.WriteStrings("AM_HEADERS_BUILD_PATHS", headersBuildPaths);
ofs.WriteStrings("AM_SOURCES", sources);
+ ofs.WriteStrings("AM_SOURCES_FLAGS", sourcesFlags);
// Write moc settings
if (this->Moc.Enabled) {
ofs.Write("# MOC settings\n");
- ofs.WriteStrings("AM_MOC_HEADERS", moc_headers);
- ofs.WriteStrings("AM_MOC_SOURCES", moc_sources);
ofs.WriteStrings("AM_MOC_SKIP", moc_skip);
ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines);
ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines);
@@ -1343,8 +1406,6 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
ofs.Write("# UIC settings\n");
- ofs.WriteStrings("AM_UIC_HEADERS", uic_headers);
- ofs.WriteStrings("AM_UIC_SOURCES", uic_sources);
ofs.WriteStrings("AM_UIC_SKIP", uic_skip);
ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options);
ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions);