diff options
author | Sebastian Holtermann <sebholt@xwmw.org> | 2019-05-02 09:03:13 (GMT) |
---|---|---|
committer | Sebastian Holtermann <sebholt@xwmw.org> | 2019-05-07 10:42:19 (GMT) |
commit | 7d50e1c6118b292ea3061ec9fee0230c5d50a5ff (patch) | |
tree | 48d3f4c459c88cc2c02fa78b0279324e2fbb5cce /Source/cmQtAutoGenInitializer.cxx | |
parent | c6f6e2b3053de02de149e80bd6a0f686a6731f68 (diff) | |
download | CMake-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.cxx | 147 |
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); |