Commit 2d6cfe26 authored by Sebastian Holtermann's avatar Sebastian Holtermann
Browse files

Autogen: Split initializer main method

parent 84bdae88
......@@ -195,15 +195,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator();
// Verbosity
{
this->Verbosity = makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE");
if (!this->Verbosity.empty()) {
unsigned long iVerb = 0;
if (!cmSystemTools::StringToULong(this->Verbosity.c_str(), &iVerb)) {
// Non numeric verbosity
this->Verbosity =
cmSystemTools::IsOn(this->Verbosity.c_str()) ? "1" : "0";
}
this->Verbosity = makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE");
if (!this->Verbosity.empty()) {
unsigned long iVerb = 0;
if (!cmSystemTools::StringToULong(this->Verbosity.c_str(), &iVerb)) {
// Non numeric verbosity
this->Verbosity =
cmSystemTools::IsOn(this->Verbosity.c_str()) ? "1" : "0";
}
}
......@@ -247,6 +245,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
this->DirBuild += this->AutogenTargetName;
}
cmSystemTools::ConvertToUnixSlashes(this->DirBuild);
// Remove build directories on cleanup
AddCleanFile(makefile, this->DirBuild);
// Working directory
this->DirWork = cbd;
......@@ -268,13 +268,23 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
// Autogen files
// Autogen info and settings files
{
this->AutogenInfoFile = this->DirInfo;
this->AutogenInfoFile += "/AutogenInfo.cmake";
this->AutogenSettingsFile = this->DirInfo;
this->AutogenSettingsFile += "/AutogenOldSettings.txt";
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
std::string& filename = this->AutogenConfigSettingsFile[cfg];
filename = AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg);
AddCleanFile(makefile, filename);
}
} else {
AddCleanFile(makefile, this->AutogenSettingsFile);
}
}
// Autogen target FOLDER property
......@@ -294,60 +304,228 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
std::set<std::string> autogenDependFiles;
std::set<cmTarget*> autogenDependTargets;
std::vector<std::string> autogenProvides;
if (this->Moc.Enabled || this->Uic.Enabled) {
// Init moc specific settings
if (this->Moc.Enabled && !InitMoc()) {
return false;
}
// Init uic specific settings
if (this->Uic.Enabled && !InitUic()) {
return false;
}
// Autogen target: Compute user defined dependencies
{
std::string const deps =
this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
if (!deps.empty()) {
std::vector<std::string> extraDeps;
cmSystemTools::ExpandListArgument(deps, extraDeps);
for (std::string const& depName : extraDeps) {
// Allow target and file dependencies
auto* depTarget = makefile->FindTargetToUse(depName);
if (depTarget != nullptr) {
this->AutogenDependTargets.insert(depTarget);
} else {
this->AutogenDependFiles.insert(depName);
}
}
}
}
}
// Init rcc specific settings
if (this->Rcc.Enabled && !InitRcc()) {
return false;
}
// Add autogen include directory to the origin target INCLUDE_DIRECTORIES
if (this->Moc.Enabled || this->Uic.Enabled ||
(this->Rcc.Enabled && this->MultiConfig)) {
this->Target->AddIncludeDirectory(this->DirInclude, true);
}
// Scan files
if (!this->InitScanFiles()) {
return false;
}
// Create autogen target
if ((this->Moc.Enabled || this->Uic.Enabled) && !this->InitAutogenTarget()) {
return false;
}
// Remove build directories on cleanup
AddCleanFile(makefile, this->DirBuild);
// Remove old settings on cleanup
// Create rcc targets
if (this->Rcc.Enabled && !this->InitRccTargets()) {
return false;
}
return true;
}
bool cmQtAutoGenInitializer::InitMoc()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
// Mocs compilation file
this->Moc.MocsCompilation = this->DirBuild;
this->Moc.MocsCompilation += "/mocs_compilation.cpp";
// Moc predefs command
if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") &&
this->QtVersionGreaterOrEqual(5, 8)) {
this->Moc.PredefsCmd =
makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND");
}
// Moc includes
{
std::string base = this->DirInfo;
base += "/AutogenOldSettings";
auto GetIncludeDirs = [this,
localGen](std::string const& cfg) -> std::string {
// Get the include dirs for this target, without stripping the implicit
// include dirs off, see
// https://gitlab.kitware.com/cmake/cmake/issues/13667
std::vector<std::string> dirs;
localGen->GetIncludeDirectories(dirs, this->Target, "CXX", cfg, false);
return cmJoin(dirs, ";");
};
// Default configuration include directories
this->Moc.Includes = GetIncludeDirs(this->ConfigDefault);
// Other configuration settings
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
std::string filename = base;
filename += '_';
filename += cfg;
filename += ".cmake";
AddCleanFile(makefile, filename);
std::string dirs = GetIncludeDirs(cfg);
if (dirs != this->Moc.Includes) {
this->Moc.ConfigIncludes[cfg] = std::move(dirs);
}
}
} else {
AddCleanFile(makefile, base.append(".cmake"));
}
}
if (this->Moc.Enabled && !InitCustomTargetsMoc()) {
return false;
// Moc compile definitions
{
auto GetCompileDefinitions =
[this, localGen](std::string const& cfg) -> std::string {
std::set<std::string> defines;
localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX");
return cmJoin(defines, ";");
};
// Default configuration defines
this->Moc.Defines = GetCompileDefinitions(this->ConfigDefault);
// Other configuration defines
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
std::string defines = GetCompileDefinitions(cfg);
if (defines != this->Moc.Defines) {
this->Moc.ConfigDefines[cfg] = std::move(defines);
}
}
}
}
if (this->Uic.Enabled && !InitCustomTargetsUic()) {
// Moc executable
if (!GetMocExecutable()) {
return false;
}
if (this->Uic.Enabled && !InitCustomTargetsRcc()) {
return false;
return true;
}
bool cmQtAutoGenInitializer::InitUic()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
// Uic search paths
{
std::string const usp =
this->Target->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
if (!usp.empty()) {
cmSystemTools::ExpandListArgument(usp, this->Uic.SearchPaths);
std::string const srcDir = makefile->GetCurrentSourceDirectory();
for (std::string& path : this->Uic.SearchPaths) {
path = cmSystemTools::CollapseFullPath(path, srcDir);
}
}
}
// Uic target options
{
auto UicGetOpts = [this](std::string const& cfg) -> std::string {
std::vector<std::string> opts;
this->Target->GetAutoUicOptions(opts, cfg);
return cmJoin(opts, ";");
};
// Acquire rcc executable and features
if (this->Rcc.Enabled) {
if (!GetRccExecutable()) {
return false;
// Default settings
this->Uic.Options = UicGetOpts(this->ConfigDefault);
// Configuration specific settings
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
std::string options = UicGetOpts(cfg);
if (options != this->Uic.Options) {
this->Uic.ConfigOptions[cfg] = std::move(options);
}
}
}
}
// .ui files skip and options
{
std::string const uiExt = "ui";
std::string pathError;
for (cmSourceFile* sf : makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->GetFullPath() ...
// Since we're iterating over source files that might be not in the
// target we need to check for path errors (not existing files).
std::string const& fPath = sf->GetFullPath(&pathError);
if (!pathError.empty()) {
pathError.clear();
continue;
}
if (sf->GetExtension() == uiExt) {
std::string const absFile = cmSystemTools::GetRealPath(fPath);
// Check if the .ui file should be skipped
if (sf->GetPropertyAsBool("SKIP_AUTOUIC") ||
sf->GetPropertyAsBool("SKIP_AUTOGEN")) {
this->Uic.Skip.insert(absFile);
}
// Check if the .ui file has uic options
std::string const uicOpts = sf->GetSafeProperty("AUTOUIC_OPTIONS");
if (!uicOpts.empty()) {
// Check if file isn't skipped
if (this->Uic.Skip.count(absFile) == 0) {
this->Uic.FileFiles.push_back(absFile);
std::vector<std::string> optsVec;
cmSystemTools::ExpandListArgument(uicOpts, optsVec);
this->Uic.FileOptions.push_back(std::move(optsVec));
}
}
}
}
}
// Add autogen includes directory to the origin target INCLUDE_DIRECTORIES
if (this->Moc.Enabled || this->Uic.Enabled ||
(this->Rcc.Enabled && this->MultiConfig)) {
this->Target->AddIncludeDirectory(this->DirInclude, true);
// Uic executable
if (!GetUicExecutable()) {
return false;
}
if (this->Moc.Enabled) {
this->AddGeneratedSource(this->Moc.MocsCompilation, GeneratorT::MOC);
autogenProvides.push_back(this->Moc.MocsCompilation);
return true;
}
bool cmQtAutoGenInitializer::InitRcc()
{
if (!GetRccExecutable()) {
return false;
}
return true;
}
bool cmQtAutoGenInitializer::InitScanFiles()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
// Extract relevant source files
std::vector<std::string> generatedSources;
std::vector<std::string> generatedHeaders;
// Scan through target files
{
std::string const qrcExt = "qrc";
std::vector<cmSourceFile*> srcFiles;
......@@ -372,15 +550,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
const bool generated = sf->GetPropertyAsBool("GENERATED");
if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
if (generated) {
generatedHeaders.push_back(absPath);
this->MocUic.HeadersGenerated.push_back(absPath);
} else {
this->Headers.push_back(absPath);
this->MocUic.Headers.push_back(absPath);
}
} else {
if (generated) {
generatedSources.push_back(absPath);
this->MocUic.SourcesGenerated.push_back(absPath);
} else {
this->Sources.push_back(absPath);
this->MocUic.Sources.push_back(absPath);
}
}
}
......@@ -407,125 +585,126 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
}
// cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's
// sources meta data cache. Clear it so that OBJECT library targets that
// are AUTOGEN initialized after this target get their added
// mocs_compilation.cpp source acknowledged by this target.
this->Target->ClearSourcesCache();
}
// Read skip files from makefile sources
// cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's
// sources meta data cache. Clear it so that OBJECT library targets that
// are AUTOGEN initialized after this target get their added
// mocs_compilation.cpp source acknowledged by this target.
this->Target->ClearSourcesCache();
if (this->Moc.Enabled || this->Uic.Enabled) {
std::string pathError;
for (cmSourceFile* sf : makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->GetFullPath() ...
// Since we're iterating over source files that might be not in the
// target we need to check for path errors (not existing files).
std::string const& fPath = sf->GetFullPath(&pathError);
if (!pathError.empty()) {
pathError.clear();
continue;
}
cmSystemTools::FileFormat const fileType =
cmSystemTools::GetFileFormat(sf->GetExtension().c_str());
if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) &&
!(fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
continue;
}
const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN");
const bool mocSkip = this->Moc.Enabled &&
(skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC"));
const bool uicSkip = this->Uic.Enabled &&
(skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC"));
if (mocSkip || uicSkip) {
std::string const absFile = cmSystemTools::GetRealPath(fPath);
if (mocSkip) {
this->Moc.Skip.insert(absFile);
// Read skip files from makefile sources
{
std::string pathError;
for (cmSourceFile* sf : makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->GetFullPath() ...
// Since we're iterating over source files that might be not in the
// target we need to check for path errors (not existing files).
std::string const& fPath = sf->GetFullPath(&pathError);
if (!pathError.empty()) {
pathError.clear();
continue;
}
if (uicSkip) {
this->Uic.Skip.insert(absFile);
cmSystemTools::FileFormat const fileType =
cmSystemTools::GetFileFormat(sf->GetExtension().c_str());
if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) &&
!(fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
continue;
}
const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN");
const bool mocSkip = this->Moc.Enabled &&
(skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC"));
const bool uicSkip = this->Uic.Enabled &&
(skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC"));
if (mocSkip || uicSkip) {
std::string const absFile = cmSystemTools::GetRealPath(fPath);
if (mocSkip) {
this->Moc.Skip.insert(absFile);
}
if (uicSkip) {
this->Uic.Skip.insert(absFile);
}
}
}
}
}
// Process GENERATED sources and headers
if (!generatedSources.empty() || !generatedHeaders.empty()) {
// Check status of policy CMP0071
bool policyAccept = false;
bool policyWarn = false;
cmPolicies::PolicyStatus const CMP0071_status =
makefile->GetPolicyStatus(cmPolicies::CMP0071);
switch (CMP0071_status) {
case cmPolicies::WARN:
policyWarn = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
// Ignore GENERATED file
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Process GENERATED file
policyAccept = true;
break;
}
if (policyAccept) {
// Accept GENERATED sources
for (std::string const& absFile : generatedHeaders) {
this->Headers.push_back(absFile);
autogenDependFiles.insert(absFile);
}
for (std::string const& absFile : generatedSources) {
this->Sources.push_back(absFile);
autogenDependFiles.insert(absFile);
// Process GENERATED sources and headers
if (!this->MocUic.SourcesGenerated.empty() ||
!this->MocUic.HeadersGenerated.empty()) {
// Check status of policy CMP0071
bool policyAccept = false;
bool policyWarn = false;
cmPolicies::PolicyStatus const CMP0071_status =
makefile->GetPolicyStatus(cmPolicies::CMP0071);
switch (CMP0071_status) {
case cmPolicies::WARN:
policyWarn = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
// Ignore GENERATED file
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Process GENERATED file
policyAccept = true;
break;
}
} else {
if (policyWarn) {
std::string msg;
msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
msg += "\n";
std::string tools;
std::string property;
if (this->Moc.Enabled && this->Uic.Enabled) {
tools = "AUTOMOC and AUTOUIC";
property = "SKIP_AUTOGEN";
} else if (this->Moc.Enabled) {
tools = "AUTOMOC";
property = "SKIP_AUTOMOC";
} else if (this->Uic.Enabled) {
tools = "AUTOUIC";
property = "SKIP_AUTOUIC";
if (policyAccept) {
// Accept GENERATED sources
for (std::string const& absFile : this->MocUic.HeadersGenerated) {
this->MocUic.Headers.push_back(absFile);
this->AutogenDependFiles.insert(absFile);
}
msg += "For compatibility, CMake is excluding the GENERATED source "
"file(s):\n";
for (const std::string& absFile : generatedHeaders) {
msg.append(" ").append(Quoted(absFile)).append("\n");
for (std::string const& absFile : this->MocUic.SourcesGenerated) {
this->MocUic.Sources.push_back(absFile);
this->AutogenDependFiles.insert(absFile);
}
for (const std::string& absFile : generatedSources) {
msg.append(" ").append(Quoted(absFile)).append("\n");
} else {
if (policyWarn) {
std::string msg;
msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
msg += "\n";
std::string tools;
std::string property;
if (this->Moc.Enabled && this->Uic.Enabled) {
tools = "AUTOMOC and AUTOUIC";
property = "SKIP_AUTOGEN";
} else if (this->Moc.Enabled) {
tools = "AUTOMOC";
property = "SKIP_AUTOMOC";
} else if (this->Uic.Enabled) {
tools = "AUTOUIC";
property = "SKIP_AUTOUIC";
}
msg += "For compatibility, CMake is excluding the GENERATED source "
"file(s):\n";
for (const std::string& absFile : this->MocUic.HeadersGenerated) {
msg.append(" ").append(Quoted(absFile)).append("\n");
}
for (const std::string& absFile : this->MocUic.SourcesGenerated) {
msg.append(" ").append(Quoted(absFile)).append("\n");
}
msg += "from processing by ";
msg += tools;
msg +=
". If any of the files should be processed, set CMP0071 to NEW. "
"If any of the files should not be processed, "
"explicitly exclude them by setting the source file property ";
msg += property;
msg += ":\n set_property(SOURCE file.h PROPERTY ";
msg += property;
msg += " ON)\n";
makefile->IssueMessage(cmake::AUTHOR_WARNING, msg);
}
msg += "from processing by ";
msg += tools;
msg +=
". If any of the files should be processed, set CMP0071 to NEW. "
"If any of the files should not be processed, "
"explicitly exclude them by setting the source file property ";
msg += property;
msg += ":\n set_property(SOURCE file.h PROPERTY ";
msg += property;
msg += " ON)\n";
makefile->IssueMessage(cmake::AUTHOR_WARNING, msg);
}
}
// Clear lists
generatedSources.clear();
generatedHeaders.clear();
}
// Sort headers and sources
if (this->Moc.Enabled || this->Uic.Enabled) {
std::sort(this->Headers.begin(), this->Headers.end());
std::sort(this->Sources.begin(), this->Sources.end());
// Sort headers and sources
if (this->Moc.Enabled || this->Uic.Enabled) {
std::sort(this->MocUic.Headers.begin(), this->MocUic.Headers.end());
std::sort(this->MocUic.Sources.begin(), this->MocUic.Sources.end());
}
}
// Process qrc files
......@@ -576,6 +755,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
qrc.SettingsFile = base;
qrc.SettingsFile += "Settings.txt";
if (this->MultiConfig) {
for (std::string const& cfg : this->ConfigsList) {
qrc.ConfigSettingsFile[cfg] =
AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg);
}
}
}
}
}
......@@ -601,401 +787,258 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
RccMergeOptions(opts, qrc.Options, QtV5);
qrc.Options = std::move(opts);
}
// RCC resources
for (Qrc& qrc : this->Rcc.Qrcs) {
// Register file at target
this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC);
std::vector<std::string> ccOutput;
ccOutput.push_back(qrc.RccFile);
cmCustomCommandLines commandLines;
if (this->MultiConfig) {
// Build for all configurations
for (std::string const& config : this->