Commit 71d6a145 authored by Sebastian Holtermann's avatar Sebastian Holtermann
Browse files

Autogen: Evaluate compiler features for the same exectuable only once

To speed up the `AUTOGEN` configuration process, evaluate the compiler
features only once.  The feature evaluation result is stored in the new class
`cmQtAutoGen::CompilerFeatures`, and the instance is shared by using
`std::shared_ptr`.
parent 0bf53483
......@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
......@@ -40,6 +41,15 @@ public:
}
};
class CompilerFeatures
{
public:
bool Evaluated = false;
std::string HelpOutput;
std::vector<std::string> ListOptions;
};
typedef std::shared_ptr<CompilerFeatures> CompilerFeaturesHandle;
/// @brief AutoGen generator type
enum class GenT
{
......
......@@ -203,19 +203,16 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
}
}
bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
cmQtAutoGen::CompilerFeaturesHandle
cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
std::string const& generator, std::string const& executable,
std::string& error, std::string* output)
std::string& error)
{
// Check if we have cached output
// Check if we have cached features
{
auto it = this->ExecutableTestOutputs_.find(executable);
if (it != this->ExecutableTestOutputs_.end()) {
// Return output on demand
if (output != nullptr) {
*output = it->second;
}
return true;
auto it = this->CompilerFeatures_.find(executable);
if (it != this->CompilerFeatures_.end()) {
return it->second;
}
}
......@@ -226,7 +223,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += "\" executable ";
error += cmQtAutoGen::Quoted(executable);
error += " does not exist.";
return false;
return cmQtAutoGen::CompilerFeaturesHandle();
}
// Test the executable
......@@ -234,7 +231,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
{
std::string stdErr;
std::vector<std::string> command;
command.push_back(executable);
command.emplace_back(executable);
command.emplace_back("-h");
int retVal = 0;
const bool runResult = cmSystemTools::RunSingleCommand(
......@@ -250,19 +247,19 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += stdOut;
error += "\n";
error += stdErr;
return false;
return cmQtAutoGen::CompilerFeaturesHandle();
}
}
// Return executable output on demand
if (output != nullptr) {
*output = stdOut;
}
// Create valid handle
cmQtAutoGen::CompilerFeaturesHandle res =
std::make_shared<cmQtAutoGen::CompilerFeatures>();
res->HelpOutput = std::move(stdOut);
// Register executable and output
this->ExecutableTestOutputs_.emplace(executable, std::move(stdOut));
// Register compiler features
this->CompilerFeatures_.emplace(executable, res);
return true;
return res;
}
bool cmQtAutoGenGlobalInitializer::generate()
......
......@@ -5,6 +5,8 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmQtAutoGen.h"
#include <map>
#include <memory> // IWYU pragma: keep
#include <string>
......@@ -68,15 +70,16 @@ private:
void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
std::string const& targetName);
bool GetExecutableTestOutput(std::string const& generator,
std::string const& executable,
std::string& error, std::string* output);
cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures(
std::string const& generator, std::string const& executable,
std::string& error);
private:
std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
std::unordered_map<std::string, std::string> ExecutableTestOutputs_;
std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>
CompilerFeatures_;
Keywords const Keywords_;
};
......
......@@ -511,7 +511,7 @@ bool cmQtAutoGenInitializer::InitMoc()
// Moc executable
{
if (!this->GetQtExecutable(this->Moc, "moc", false, nullptr)) {
if (!this->GetQtExecutable(this->Moc, "moc", false)) {
return false;
}
// Let the _autogen target depend on the moc executable
......@@ -565,7 +565,7 @@ bool cmQtAutoGenInitializer::InitUic()
// Uic executable
{
if (!this->GetQtExecutable(this->Uic, "uic", true, nullptr)) {
if (!this->GetQtExecutable(this->Uic, "uic", true)) {
return false;
}
// Let the _autogen target depend on the uic executable
......@@ -582,17 +582,22 @@ bool cmQtAutoGenInitializer::InitRcc()
{
// Rcc executable
{
std::string stdOut;
if (!this->GetQtExecutable(this->Rcc, "rcc", false, &stdOut)) {
if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
return false;
}
// Evaluate test output
if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
if (stdOut.find("--list") != std::string::npos) {
this->Rcc.ListOptions.emplace_back("--list");
} else if (stdOut.find("-list") != std::string::npos) {
this->Rcc.ListOptions.emplace_back("-list");
// Evaluate test output on demand
CompilerFeatures& features = *this->Rcc.ExecutableFeatures;
if (!features.Evaluated) {
// Look for list options
if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
if (features.HelpOutput.find("--list") != std::string::npos) {
features.ListOptions.emplace_back("--list");
} else if (features.HelpOutput.find("-list") != std::string::npos) {
features.ListOptions.emplace_back("-list");
}
}
// Evaluation finished
features.Evaluated = true;
}
}
......@@ -931,7 +936,8 @@ bool cmQtAutoGenInitializer::InitScanFiles()
for (Qrc& qrc : this->Rcc.Qrcs) {
if (!qrc.Generated) {
std::string error;
RccLister const lister(this->Rcc.Executable, this->Rcc.ListOptions);
RccLister const lister(this->Rcc.Executable,
this->Rcc.ExecutableFeatures->ListOptions);
if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
cmSystemTools::Error(error);
return false;
......@@ -1437,7 +1443,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
ofs.Write("# Rcc executable\n");
ofs.Write("ARCC_RCC_EXECUTABLE", this->Rcc.Executable);
ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS", this->Rcc.ListOptions);
ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS",
this->Rcc.ExecutableFeatures->ListOptions);
ofs.Write("# Rcc job\n");
ofs.Write("ARCC_LOCK_FILE", qrc.LockFile);
......@@ -1600,8 +1607,7 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
const std::string& executable,
bool ignoreMissingTarget,
std::string* output) const
bool ignoreMissingTarget) const
{
auto print_err = [this, &genVars](std::string const& err) {
std::string msg = genVars.GenNameUpper;
......@@ -1631,9 +1637,9 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
return false;
}
// Check if the provided executable already exists (it's possible for it
// not to exist when building Qt itself).
genVars.ExecutableExists = cmSystemTools::FileExists(genVars.Executable);
// Create empty compiler features.
genVars.ExecutableFeatures =
std::make_shared<cmQtAutoGen::CompilerFeatures>();
return true;
}
}
......@@ -1664,6 +1670,9 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
}
} else {
if (ignoreMissingTarget) {
// Create empty compiler features.
genVars.ExecutableFeatures =
std::make_shared<cmQtAutoGen::CompilerFeatures>();
return true;
}
std::string err = "Could not find ";
......@@ -1675,15 +1684,15 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
}
}
// Test executable
// Get executable features
{
std::string err;
if (!this->GlobalInitializer->GetExecutableTestOutput(
executable, genVars.Executable, err, output)) {
genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
executable, genVars.Executable, err);
if (!genVars.ExecutableFeatures) {
print_err(err);
return false;
}
genVars.ExecutableExists = true;
}
return true;
......
......@@ -67,7 +67,7 @@ public:
std::string ExecutableTargetName;
cmGeneratorTarget* ExecutableTarget = nullptr;
std::string Executable;
bool ExecutableExists = false;
CompilerFeaturesHandle ExecutableFeatures;
/// @brief Constructor
GenVarsT(GenT gen)
......@@ -148,7 +148,7 @@ private:
void AddCleanFile(std::string const& fileName);
bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
bool ignoreMissingTarget, std::string* output) const;
bool ignoreMissingTarget) const;
private:
cmQtAutoGenGlobalInitializer* GlobalInitializer;
......@@ -230,7 +230,6 @@ private:
struct RccT : public GenVarsT
{
bool GlobalTarget = false;
std::vector<std::string> ListOptions;
std::vector<Qrc> Qrcs;
/// @brief Constructor
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment