diff options
author | Sebastian Holtermann <sebholt@xwmw.org> | 2018-01-03 15:59:40 (GMT) |
---|---|---|
committer | Sebastian Holtermann <sebholt@xwmw.org> | 2018-01-17 16:23:49 (GMT) |
commit | a008578deebfa71b38786281450e3d9cf84f5847 (patch) | |
tree | 70173006b0adc6a62626e59d9cc653826f950336 /Source/cmQtAutoGen.cxx | |
parent | 488baaf0d6144cd7cedfbbd3bb6eadcc72257fc4 (diff) | |
download | CMake-a008578deebfa71b38786281450e3d9cf84f5847.zip CMake-a008578deebfa71b38786281450e3d9cf84f5847.tar.gz CMake-a008578deebfa71b38786281450e3d9cf84f5847.tar.bz2 |
Autogen: Process files concurrently in AUTOMOC and AUTOUIC
This introduces concurrent thread processing in the `_autogen`
target wich processes AUTOMOC and AUTOUIC.
Source file parsing is distributed among the threads by
using a job queue from which the threads pull new parse jobs.
Each thread might start an independent ``moc`` or ``uic`` process.
Altogether this roughly speeds up the AUTOMOC and AUTOUIC build
process by the number of physical CPUs on the host system.
The exact number of threads to start in the `_autogen` target
is controlled by the new AUTOGEN_PARALLEL target property which
is initialized by the new CMAKE_AUTOGEN_PARALLEL variable.
If AUTOGEN_PARALLEL is empty or unset (which is the default)
the thread count is set to the number of physical CPUs on
the host system.
The AUTOMOC/AUTOUIC generator and the AUTORCC generator are
refactored to use a libuv loop internally.
Closes #17422.
Diffstat (limited to 'Source/cmQtAutoGen.cxx')
-rw-r--r-- | Source/cmQtAutoGen.cxx | 314 |
1 files changed, 120 insertions, 194 deletions
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 255a532..18ecbe7 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -2,16 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGen.h" #include "cmAlgorithms.h" -#include "cmProcessOutput.h" #include "cmSystemTools.h" -#include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <iterator> #include <sstream> -#include <stddef.h> // - Static variables @@ -21,8 +18,8 @@ std::string const genNameUic = "AutoUic"; std::string const genNameRcc = "AutoRcc"; std::string const mcNameSingle = "SINGLE"; -std::string const mcNameWrap = "WRAP"; -std::string const mcNameFull = "FULL"; +std::string const mcNameWrapper = "WRAPPER"; +std::string const mcNameMulti = "MULTI"; // - Static functions @@ -80,203 +77,53 @@ void MergeOptions(std::vector<std::string>& baseOpts, baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end()); } -/// @brief Reads the resource files list from from a .qrc file - Qt4 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt4(std::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage) -{ - bool allGood = true; - // Read qrc file content into string - std::string qrcContents; - { - cmsys::ifstream ifs(fileName.c_str()); - if (ifs) { - std::ostringstream osst; - osst << ifs.rdbuf(); - qrcContents = osst.str(); - } else { - if (errorMessage != nullptr) { - std::string& err = *errorMessage; - err = "rcc file not readable:\n "; - err += cmQtAutoGen::Quoted(fileName); - err += "\n"; - } - allGood = false; - } - } - if (allGood) { - // qrc file directory - std::string qrcDir(cmSystemTools::GetFilenamePath(fileName)); - if (!qrcDir.empty()) { - qrcDir += '/'; - } - - cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); - cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); - - size_t offset = 0; - while (fileMatchRegex.find(qrcContents.c_str() + offset)) { - std::string qrcEntry = fileMatchRegex.match(1); - offset += qrcEntry.size(); - { - fileReplaceRegex.find(qrcEntry); - std::string tag = fileReplaceRegex.match(1); - qrcEntry = qrcEntry.substr(tag.size()); - } - if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { - qrcEntry = qrcDir + qrcEntry; - } - files.push_back(qrcEntry); - } - } - return allGood; -} - -/// @brief Reads the resource files list from from a .qrc file - Qt5 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt5(std::string const& rccCommand, - std::vector<std::string> const& rccListOptions, - std::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage) -{ - if (rccCommand.empty()) { - cmSystemTools::Error("rcc executable not available"); - return false; - } - - std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); - std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); - - // Run rcc list command - bool result = false; - int retVal = 0; - std::string rccStdOut; - std::string rccStdErr; - { - std::vector<std::string> command; - command.push_back(rccCommand); - command.insert(command.end(), rccListOptions.begin(), - rccListOptions.end()); - command.push_back(fileNameName); - result = cmSystemTools::RunSingleCommand( - command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), - cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); - } - if (!result || retVal) { - if (errorMessage != nullptr) { - std::string& err = *errorMessage; - err = "rcc list process failed for:\n "; - err += cmQtAutoGen::Quoted(fileName); - err += "\n"; - err += rccStdOut; - err += "\n"; - err += rccStdErr; - err += "\n"; - } - return false; - } - - // Lambda to strip CR characters - auto StripCR = [](std::string& line) { - std::string::size_type cr = line.find('\r'); - if (cr != std::string::npos) { - line = line.substr(0, cr); - } - }; - - // Parse rcc std output - { - std::istringstream ostr(rccStdOut); - std::string oline; - while (std::getline(ostr, oline)) { - StripCR(oline); - if (!oline.empty()) { - files.push_back(oline); - } - } - } - // Parse rcc error output - { - std::istringstream estr(rccStdErr); - std::string eline; - while (std::getline(estr, eline)) { - StripCR(eline); - if (cmHasLiteralPrefix(eline, "RCC: Error in")) { - static std::string searchString = "Cannot find file '"; - - std::string::size_type pos = eline.find(searchString); - if (pos == std::string::npos) { - if (errorMessage != nullptr) { - std::string& err = *errorMessage; - err = "rcc lists unparsable output:\n"; - err += cmQtAutoGen::Quoted(eline); - err += "\n"; - } - return false; - } - pos += searchString.length(); - std::string::size_type sz = eline.size() - pos - 1; - files.push_back(eline.substr(pos, sz)); - } - } - } - - // Convert relative paths to absolute paths - for (std::string& resFile : files) { - resFile = cmSystemTools::CollapseCombinedPath(fileDir, resFile); - } - - return true; -} - // - Class definitions -std::string const cmQtAutoGen::listSep = "<<<S>>>"; +std::string const cmQtAutoGen::ListSep = "<<<S>>>"; +unsigned int const cmQtAutoGen::ParallelMax = 64; -std::string const& cmQtAutoGen::GeneratorName(Generator type) +std::string const& cmQtAutoGen::GeneratorName(GeneratorT type) { switch (type) { - case Generator::GEN: + case GeneratorT::GEN: return genNameGen; - case Generator::MOC: + case GeneratorT::MOC: return genNameMoc; - case Generator::UIC: + case GeneratorT::UIC: return genNameUic; - case Generator::RCC: + case GeneratorT::RCC: return genNameRcc; } return genNameGen; } -std::string cmQtAutoGen::GeneratorNameUpper(Generator genType) +std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType) { return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType)); } -std::string const& cmQtAutoGen::MultiConfigName(MultiConfig config) +std::string const& cmQtAutoGen::MultiConfigName(MultiConfigT config) { switch (config) { - case MultiConfig::SINGLE: + case MultiConfigT::SINGLE: return mcNameSingle; - case MultiConfig::WRAP: - return mcNameWrap; - case MultiConfig::FULL: - return mcNameFull; + case MultiConfigT::WRAPPER: + return mcNameWrapper; + case MultiConfigT::MULTI: + return mcNameMulti; } - return mcNameWrap; + return mcNameWrapper; } -cmQtAutoGen::MultiConfig cmQtAutoGen::MultiConfigType(std::string const& name) +cmQtAutoGen::MultiConfigT cmQtAutoGen::MultiConfigType(std::string const& name) { if (name == mcNameSingle) { - return MultiConfig::SINGLE; + return MultiConfigT::SINGLE; } - if (name == mcNameFull) { - return MultiConfig::FULL; + if (name == mcNameMulti) { + return MultiConfigT::MULTI; } - return MultiConfig::WRAP; + return MultiConfigT::WRAPPER; } std::string cmQtAutoGen::Quoted(std::string const& text) @@ -294,6 +141,33 @@ std::string cmQtAutoGen::Quoted(std::string const& text) return res; } +std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command) +{ + std::string res; + for (std::string const& item : command) { + if (!res.empty()) { + res.push_back(' '); + } + std::string const cesc = cmQtAutoGen::Quoted(item); + if (item.empty() || (cesc.size() > (item.size() + 2)) || + (cesc.find(' ') != std::string::npos)) { + res += cesc; + } else { + res += item; + } + } + return res; +} + +std::string cmQtAutoGen::SubDirPrefix(std::string const& filename) +{ + std::string res(cmSystemTools::GetFilenamePath(filename)); + if (!res.empty()) { + res += '/'; + } + return res; +} + std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename, std::string const& suffix) { @@ -333,27 +207,79 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts, MergeOptions(baseOpts, newOpts, valueOpts, isQt5); } -bool cmQtAutoGen::RccListInputs(std::string const& rccCommand, - std::vector<std::string> const& rccListOptions, - std::string const& fileName, - std::vector<std::string>& files, - std::string* errorMessage) +void cmQtAutoGen::RccListParseContent(std::string const& content, + std::vector<std::string>& files) { - bool allGood = false; - if (cmSystemTools::FileExists(fileName.c_str())) { - if (rccListOptions.empty()) { - allGood = RccListInputsQt4(fileName, files, errorMessage); - } else { - allGood = RccListInputsQt5(rccCommand, rccListOptions, fileName, files, - errorMessage); + cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); + cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); + + const char* contentChars = content.c_str(); + while (fileMatchRegex.find(contentChars)) { + std::string const qrcEntry = fileMatchRegex.match(1); + contentChars += qrcEntry.size(); + { + fileReplaceRegex.find(qrcEntry); + std::string const tag = fileReplaceRegex.match(1); + files.push_back(qrcEntry.substr(tag.size())); } - } else { - if (errorMessage != nullptr) { - std::string& err = *errorMessage; - err = "rcc resource file does not exist:\n "; - err += cmQtAutoGen::Quoted(fileName); - err += "\n"; + } +} + +bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut, + std::string const& rccStdErr, + std::vector<std::string>& files, + std::string& error) +{ + // Lambda to strip CR characters + auto StripCR = [](std::string& line) { + std::string::size_type cr = line.find('\r'); + if (cr != std::string::npos) { + line = line.substr(0, cr); } + }; + + // Parse rcc std output + { + std::istringstream ostr(rccStdOut); + std::string oline; + while (std::getline(ostr, oline)) { + StripCR(oline); + if (!oline.empty()) { + files.push_back(oline); + } + } + } + // Parse rcc error output + { + std::istringstream estr(rccStdErr); + std::string eline; + while (std::getline(estr, eline)) { + StripCR(eline); + if (cmHasLiteralPrefix(eline, "RCC: Error in")) { + static std::string const searchString = "Cannot find file '"; + + std::string::size_type pos = eline.find(searchString); + if (pos == std::string::npos) { + error = "rcc lists unparsable output:\n"; + error += cmQtAutoGen::Quoted(eline); + error += "\n"; + return false; + } + pos += searchString.length(); + std::string::size_type sz = eline.size() - pos - 1; + files.push_back(eline.substr(pos, sz)); + } + } + } + + return true; +} + +void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir, + std::vector<std::string>& files) +{ + for (std::string& entry : files) { + std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry); + entry = std::move(tmp); } - return allGood; } |