Autogen: AUTO*_EXECUTABLE: add support for per-config values
* Per-config values were added to `AUTO*_EXECUTABLE`.
* Dependency order was refactored for `cmake_autogen` and `cmake_autorcc` to avoid unnecessary rebuilds.
* A new parameter was added for `cmake_autogen` and `cmake_autorcc` to specify the config name of the `auto*_executable` to be used.
* Add `AUTOGEN_BETTER_GRAPH_MULTI_CONFIG` target property to change the behavior of the dependency graph.
* The timestamp target is split into three targets for per-config to avoid redundant `mocs_compilation` builds when `AUTOGEN_BETTER_GRAPH_MULTI_CONFIG` is ON
* Per-config `DEP_FILE_RULE_NAME` values were added to `AutogenInfo.json` for `Multi-Config` usage.
* Some functions were refactored to avoid code duplication.
This commit reimplements fddd0f0443
Fixes: #20074
stage/master/nightly/2024/01/18
parent
31dead97ed
commit
7c39dabdbc
|
@ -78,6 +78,7 @@ syn keyword cmakeProperty contained
|
|||
\ AUTOGEN_TARGETS_FOLDER
|
||||
\ AUTOGEN_TARGET_DEPENDS
|
||||
\ AUTOGEN_USE_SYSTEM_INCLUDE
|
||||
\ AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
\ AUTOMOC
|
||||
\ AUTOMOC_COMPILER_PREDEFINES
|
||||
\ AUTOMOC_DEPEND_FILTERS
|
||||
|
@ -766,6 +767,7 @@ syn keyword cmakeVariable contained
|
|||
\ CMAKE_ASM_STANDARD_REQUIRED
|
||||
\ CMAKE_ASM_SUPPORTED
|
||||
\ CMAKE_ASM_VISIBILITY_PRESET
|
||||
\ CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
\ CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
\ CMAKE_AUTOGEN_ORIGIN_DEPENDS
|
||||
\ CMAKE_AUTOGEN_PARALLEL
|
||||
|
|
|
@ -129,6 +129,7 @@ Properties on Targets
|
|||
/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG
|
||||
/prop_tgt/ARCHIVE_OUTPUT_NAME
|
||||
/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG
|
||||
/prop_tgt/AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
/prop_tgt/AUTOGEN_BUILD_DIR
|
||||
/prop_tgt/AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
/prop_tgt/AUTOGEN_ORIGIN_DEPENDS
|
||||
|
|
|
@ -389,6 +389,7 @@ Variables that Control the Build
|
|||
/variable/CMAKE_APPLE_SILICON_PROCESSOR
|
||||
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY
|
||||
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG
|
||||
/variable/CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
/variable/CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS
|
||||
/variable/CMAKE_AUTOGEN_PARALLEL
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
---------------------------------
|
||||
|
||||
.. versionadded:: 3.29
|
||||
|
||||
``AUTOGEN_BETTER_GRAPH_MULTI_CONFIG`` is a boolean property that can be set
|
||||
on a target to have better dependency graph for multi-configuration generators.
|
||||
When this property is enabled, ``CMake`` will generate more per-config targets.
|
||||
Thus, the dependency graph will be more accurate for multi-configuration
|
||||
generators and some recompilations will be avoided.
|
||||
|
||||
If the Qt version is 6.8 or newer, this property is enabled by default.
|
||||
If the Qt version is older than 6.8, this property is disabled by default.
|
||||
Consult the Qt documentation to check if the property can be enabled for older
|
||||
Qt versions.
|
||||
|
||||
See the :manual:`cmake-qt(7)` manual for more information on using CMake
|
||||
with Qt.
|
||||
|
||||
This property is initialized by the
|
||||
:variable:`CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG` variable if it is set when
|
||||
a target is created.
|
|
@ -0,0 +1,10 @@
|
|||
CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
|
||||
---------------------------------------
|
||||
|
||||
.. versionadded:: 3.29
|
||||
|
||||
This variable is used to initialize the
|
||||
:prop_tgt:`AUTOGEN_BETTER_GRAPH_MULTI_CONFIG` property on all targets as they
|
||||
are created. See that target property for additional information.
|
||||
|
||||
By default ``CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG`` is unset.
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/string_view>
|
||||
|
@ -16,6 +17,22 @@
|
|||
class cmQtAutoGen
|
||||
{
|
||||
public:
|
||||
/** String value with per configuration variants. */
|
||||
class ConfigString
|
||||
{
|
||||
public:
|
||||
std::string Default;
|
||||
std::unordered_map<std::string, std::string> Config;
|
||||
};
|
||||
|
||||
/** String values with per configuration variants. */
|
||||
template <typename C>
|
||||
class ConfigStrings
|
||||
{
|
||||
public:
|
||||
C Default;
|
||||
std::unordered_map<std::string, C> Config;
|
||||
};
|
||||
/** Integer version. */
|
||||
struct IntegerVersion
|
||||
{
|
||||
|
|
|
@ -213,24 +213,81 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
|
|||
}
|
||||
}
|
||||
|
||||
cmQtAutoGen::CompilerFeaturesHandle
|
||||
cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>
|
||||
cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
|
||||
std::string const& generator, std::string const& executable,
|
||||
std::string& error)
|
||||
std::string const& generator, cmQtAutoGen::ConfigString const& executable,
|
||||
std::string& error, bool const isMultiConfig, bool UseBetterGraph)
|
||||
{
|
||||
cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> res;
|
||||
if (isMultiConfig && UseBetterGraph) {
|
||||
for (auto const& config : executable.Config) {
|
||||
auto const exe = config.second;
|
||||
// Check if we have cached features
|
||||
{
|
||||
auto it = this->CompilerFeatures_.Config[config.first].find(exe);
|
||||
if (it != this->CompilerFeatures_.Config[config.first].end()) {
|
||||
res.Config[config.first] = it->second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the executable exists
|
||||
if (!cmSystemTools::FileExists(exe, true)) {
|
||||
error = cmStrCat("The \"", generator, "\" executable ",
|
||||
cmQtAutoGen::Quoted(exe), " does not exist.");
|
||||
res.Config[config.first] = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
// Test the executable
|
||||
std::string stdOut;
|
||||
{
|
||||
std::string stdErr;
|
||||
std::vector<std::string> command;
|
||||
command.emplace_back(exe);
|
||||
command.emplace_back("-h");
|
||||
int retVal = 0;
|
||||
const bool runResult = cmSystemTools::RunSingleCommand(
|
||||
command, &stdOut, &stdErr, &retVal, nullptr,
|
||||
cmSystemTools::OUTPUT_NONE, cmDuration::zero(),
|
||||
cmProcessOutput::Auto);
|
||||
if (!runResult) {
|
||||
error = cmStrCat("Test run of \"", generator, "\" executable ",
|
||||
cmQtAutoGen::Quoted(exe), " failed.\n",
|
||||
cmQtAutoGen::QuotedCommand(command), '\n', stdOut,
|
||||
'\n', stdErr);
|
||||
res.Config[config.first] = {};
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Create valid handle
|
||||
res.Config[config.first] =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
res.Config[config.first]->HelpOutput = std::move(stdOut);
|
||||
|
||||
// Register compiler features
|
||||
this->CompilerFeatures_.Config[config.first].emplace(
|
||||
exe, res.Config[config.first]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Check if we have cached features
|
||||
{
|
||||
auto it = this->CompilerFeatures_.find(executable);
|
||||
if (it != this->CompilerFeatures_.end()) {
|
||||
return it->second;
|
||||
auto it = this->CompilerFeatures_.Default.find(executable.Default);
|
||||
if (it != this->CompilerFeatures_.Default.end()) {
|
||||
res.Default = it->second;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the executable exists
|
||||
if (!cmSystemTools::FileExists(executable, true)) {
|
||||
error = cmStrCat("The \"", generator, "\" executable ",
|
||||
cmQtAutoGen::Quoted(executable), " does not exist.");
|
||||
return cmQtAutoGen::CompilerFeaturesHandle();
|
||||
if (!cmSystemTools::FileExists(executable.Default, true)) {
|
||||
error =
|
||||
cmStrCat("The \"", generator, "\" executable ",
|
||||
cmQtAutoGen::Quoted(executable.Default), " does not exist.");
|
||||
return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>();
|
||||
}
|
||||
|
||||
// Test the executable
|
||||
|
@ -238,7 +295,7 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
|
|||
{
|
||||
std::string stdErr;
|
||||
std::vector<std::string> command;
|
||||
command.emplace_back(executable);
|
||||
command.emplace_back(executable.Default);
|
||||
command.emplace_back("-h");
|
||||
int retVal = 0;
|
||||
const bool runResult = cmSystemTools::RunSingleCommand(
|
||||
|
@ -246,20 +303,18 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
|
|||
cmDuration::zero(), cmProcessOutput::Auto);
|
||||
if (!runResult) {
|
||||
error = cmStrCat("Test run of \"", generator, "\" executable ",
|
||||
cmQtAutoGen::Quoted(executable), " failed.\n",
|
||||
cmQtAutoGen::Quoted(executable.Default), " failed.\n",
|
||||
cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n',
|
||||
stdErr);
|
||||
return cmQtAutoGen::CompilerFeaturesHandle();
|
||||
return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>();
|
||||
}
|
||||
}
|
||||
|
||||
// Create valid handle
|
||||
cmQtAutoGen::CompilerFeaturesHandle res =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
res->HelpOutput = std::move(stdOut);
|
||||
res.Default = std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
res.Default->HelpOutput = std::move(stdOut);
|
||||
|
||||
// Register compiler features
|
||||
this->CompilerFeatures_.emplace(executable, res);
|
||||
this->CompilerFeatures_.Default.emplace(executable.Default, res.Default);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -66,14 +66,17 @@ private:
|
|||
void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
|
||||
std::string const& targetName);
|
||||
|
||||
cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures(
|
||||
std::string const& generator, std::string const& executable,
|
||||
std::string& error);
|
||||
cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>
|
||||
GetCompilerFeatures(std::string const& generator,
|
||||
cmQtAutoGen::ConfigString const& executable,
|
||||
std::string& error, bool isMultiConfig,
|
||||
bool UseBetterGraph);
|
||||
|
||||
std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
|
||||
std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
|
||||
std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
|
||||
std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>
|
||||
cmQtAutoGen::ConfigStrings<
|
||||
std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>>
|
||||
CompilerFeatures_;
|
||||
Keywords const Keywords_;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmQtAutoGenInitializer.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <initializer_list>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <cm/algorithm>
|
||||
#include <cm/iterator>
|
||||
#include <cm/memory>
|
||||
#include <cm/string_view>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
|
@ -301,15 +303,22 @@ bool InfoWriter::Save(std::string const& filename)
|
|||
return fileStream.Close();
|
||||
}
|
||||
|
||||
void AddAutogenExecutableToDependencies(
|
||||
cmQtAutoGenInitializer::GenVarsT const& genVars,
|
||||
std::vector<std::string>& dependencies)
|
||||
cmQtAutoGen::ConfigStrings<std::vector<std::string>> generateListOptions(
|
||||
cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> const&
|
||||
executableFeatures,
|
||||
bool IsMultiConfig)
|
||||
{
|
||||
if (genVars.ExecutableTarget != nullptr) {
|
||||
dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
|
||||
} else if (!genVars.Executable.empty()) {
|
||||
dependencies.push_back(genVars.Executable);
|
||||
cmQtAutoGen::ConfigStrings<std::vector<std::string>> tempListOptions;
|
||||
if (IsMultiConfig) {
|
||||
for (auto const& executableFeature : executableFeatures.Config) {
|
||||
tempListOptions.Config[executableFeature.first] =
|
||||
executableFeature.second->ListOptions;
|
||||
}
|
||||
} else {
|
||||
tempListOptions.Default = executableFeatures.Default->ListOptions;
|
||||
}
|
||||
|
||||
return tempListOptions;
|
||||
}
|
||||
|
||||
} // End of unnamed namespace
|
||||
|
@ -334,6 +343,42 @@ cmQtAutoGenInitializer::cmQtAutoGenInitializer(
|
|||
this->Rcc.GlobalTarget = globalAutoRccTarget;
|
||||
this->CrossConfig =
|
||||
!this->Makefile->GetSafeDefinition("CMAKE_CROSS_CONFIGS").empty();
|
||||
this->UseBetterGraph =
|
||||
this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsSet()
|
||||
? this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsOn()
|
||||
: (this->QtVersion >= IntegerVersion(6, 8));
|
||||
// AUTOGEN_BETTER_GRAPH_MULTI_CONFIG is set explicitly because it is read by
|
||||
// the qt library
|
||||
this->GenTarget->Target->SetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG",
|
||||
this->UseBetterGraph ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
void cmQtAutoGenInitializer::AddAutogenExecutableToDependencies(
|
||||
cmQtAutoGenInitializer::GenVarsT const& genVars,
|
||||
std::vector<std::string>& dependencies) const
|
||||
{
|
||||
if (genVars.ExecutableTarget != nullptr) {
|
||||
dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
|
||||
} else if (this->MultiConfig && this->UseBetterGraph) {
|
||||
cm::string_view const& configGenexWithCommandConfig =
|
||||
"$<COMMAND_CONFIG:$<$<CONFIG:";
|
||||
cm::string_view const& configGenex = "$<$<CONFIG:";
|
||||
cm::string_view const& configGenexEnd = ">";
|
||||
cm::string_view const& configGenexEndWithCommandConfig = ">>";
|
||||
auto genexBegin =
|
||||
this->CrossConfig ? configGenexWithCommandConfig : configGenex;
|
||||
auto genexEnd =
|
||||
this->CrossConfig ? configGenexEndWithCommandConfig : configGenexEnd;
|
||||
for (auto const& config : genVars.Executable.Config) {
|
||||
auto executableWithConfig =
|
||||
cmStrCat(genexBegin, config.first, ">:", config.second, genexEnd);
|
||||
dependencies.emplace_back(std::move(executableWithConfig));
|
||||
}
|
||||
} else {
|
||||
if (!genVars.Executable.Default.empty()) {
|
||||
dependencies.push_back(genVars.Executable.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoGenInitializer::InitCustomTargets()
|
||||
|
@ -811,18 +856,30 @@ bool cmQtAutoGenInitializer::InitRcc()
|
|||
return false;
|
||||
}
|
||||
// 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");
|
||||
auto& features = this->Rcc.ExecutableFeatures;
|
||||
auto checkAndAddOptions = [this](CompilerFeaturesHandle& feature) {
|
||||
if (!feature->Evaluated) {
|
||||
// Look for list options
|
||||
if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
|
||||
static std::array<std::string, 2> const listOptions{ { "--list",
|
||||
"-list" } };
|
||||
for (std::string const& opt : listOptions) {
|
||||
if (feature->HelpOutput.find(opt) != std::string::npos) {
|
||||
feature->ListOptions.emplace_back(opt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Evaluation finished
|
||||
feature->Evaluated = true;
|
||||
}
|
||||
// Evaluation finished
|
||||
features.Evaluated = true;
|
||||
};
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
checkAndAddOptions(features.Config[config]);
|
||||
}
|
||||
} else {
|
||||
checkAndAddOptions(features.Default);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1158,8 +1215,14 @@ bool cmQtAutoGenInitializer::InitScanFiles()
|
|||
// Path checksum
|
||||
qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
|
||||
// Output file name
|
||||
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
|
||||
"/qrc_", qrc.QrcName, ".cpp");
|
||||
if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
|
||||
this->UseBetterGraph) {
|
||||
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
|
||||
"_$<CONFIG>", "/qrc_", qrc.QrcName, ".cpp");
|
||||
} else {
|
||||
qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
|
||||
"/qrc_", qrc.QrcName, ".cpp");
|
||||
}
|
||||
std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
|
||||
qrc.QrcName, '_', qrc.QrcPathChecksum);
|
||||
qrc.LockFile = cmStrCat(base, "_Lock.lock");
|
||||
|
@ -1191,11 +1254,25 @@ bool cmQtAutoGenInitializer::InitScanFiles()
|
|||
for (Qrc& qrc : this->Rcc.Qrcs) {
|
||||
if (!qrc.Generated) {
|
||||
std::string error;
|
||||
RccLister const lister(this->Rcc.Executable,
|
||||
this->Rcc.ExecutableFeatures->ListOptions);
|
||||
if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
|
||||
cmSystemTools::Error(error);
|
||||
return false;
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
RccLister const lister(
|
||||
this->Rcc.Executable.Config[config],
|
||||
this->Rcc.ExecutableFeatures.Config[config]->ListOptions);
|
||||
if (!lister.list(qrc.QrcFile, qrc.Resources.Config[config],
|
||||
error)) {
|
||||
cmSystemTools::Error(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RccLister const lister(
|
||||
this->Rcc.Executable.Default,
|
||||
this->Rcc.ExecutableFeatures.Default->ListOptions);
|
||||
if (!lister.list(qrc.QrcFile, qrc.Resources.Default, error)) {
|
||||
cmSystemTools::Error(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1223,8 +1300,9 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
|||
if (this->Moc.Enabled) {
|
||||
this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
|
||||
if (useDepfile) {
|
||||
if (this->MultiConfig && this->CrossConfig &&
|
||||
this->GlobalGen->GetName().find("Ninja") != std::string::npos) {
|
||||
if (this->CrossConfig &&
|
||||
this->GlobalGen->GetName().find("Ninja") != std::string::npos &&
|
||||
!this->UseBetterGraph) {
|
||||
// Make all mocs_compilation_<CONFIG>.cpp files byproducts of the
|
||||
// ${target}_autogen/timestamp custom command.
|
||||
// We cannot just use Moc.CompilationFileGenex here, because that
|
||||
|
@ -1267,28 +1345,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
|||
// Compose command lines
|
||||
// FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
|
||||
// instead of fiddling with the include directories
|
||||
std::vector<std::string> configs;
|
||||
this->GlobalGen->GetQtAutoGenConfigs(configs);
|
||||
|
||||
bool constexpr stdPipesUTF8 = true;
|
||||
cmCustomCommandLines commandLines;
|
||||
if (!this->CrossConfig) {
|
||||
std::string autogenInfoFileConfig;
|
||||
if (this->MultiConfig) {
|
||||
autogenInfoFileConfig = "$<CONFIG>";
|
||||
} else {
|
||||
autogenInfoFileConfig = configs[0];
|
||||
}
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
|
||||
this->AutogenTarget.InfoFile, autogenInfoFileConfig }));
|
||||
|
||||
} else {
|
||||
for (auto const& config : configs) {
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
|
||||
this->AutogenTarget.InfoFile, config }));
|
||||
}
|
||||
}
|
||||
AddCMakeProcessToCommandLines(this->AutogenTarget.InfoFile, "cmake_autogen",
|
||||
commandLines);
|
||||
|
||||
// Use PRE_BUILD on demand
|
||||
bool usePRE_BUILD = false;
|
||||
|
@ -1456,18 +1517,47 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
|||
|
||||
AddAutogenExecutableToDependencies(this->Moc, dependencies);
|
||||
AddAutogenExecutableToDependencies(this->Uic, dependencies);
|
||||
|
||||
std::string outputFile;
|
||||
std::string depFile;
|
||||
// Create the custom command that outputs the timestamp file.
|
||||
const char timestampFileName[] = "timestamp";
|
||||
const std::string outputFile =
|
||||
cmStrCat(this->Dir.Build, "/", timestampFileName);
|
||||
this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps");
|
||||
this->AutogenTarget.DepFileRuleName =
|
||||
cmStrCat(this->Dir.RelativeBuild, "/", timestampFileName);
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
// create timestamp file with $<CONFIG> in the name so that
|
||||
// every cmake_autogen target has its own timestamp file
|
||||
std::string const configView = "$<CONFIG>";
|
||||
std::string const timestampFileWithoutConfig = "timestamp_";
|
||||
std::string const depFileWithoutConfig =
|
||||
cmStrCat(this->Dir.Build, "/deps_");
|
||||
std::string const timestampFileName =
|
||||
timestampFileWithoutConfig + configView;
|
||||
outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName);
|
||||
auto const depFileWithConfig =
|
||||
cmStrCat(depFileWithoutConfig, configView);
|
||||
depFile = depFileWithConfig;
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
|
||||
|
||||
this->AddGeneratedSource(outputFile, this->Moc);
|
||||
ConfigString outputFileWithConfig;
|
||||
for (std::string const& config : this->ConfigsList) {
|
||||
auto tempTimestampFileName = timestampFileWithoutConfig + config;
|
||||
auto tempDepFile = depFileWithoutConfig + config;
|
||||
outputFileWithConfig.Config[config] = tempTimestampFileName;
|
||||
this->AutogenTarget.DepFileRuleName.Config[config] =
|
||||
cmStrCat(this->Dir.RelativeBuild, "/", tempTimestampFileName);
|
||||
this->AutogenTarget.DepFile.Config[config] = tempDepFile;
|
||||
}
|
||||
this->AddGeneratedSource(outputFileWithConfig, this->Moc);
|
||||
} else {
|
||||
cm::string_view const timestampFileName = "timestamp";
|
||||
outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName);
|
||||
this->AutogenTarget.DepFile.Default =
|
||||
cmStrCat(this->Dir.Build, "/deps");
|
||||
depFile = this->AutogenTarget.DepFile.Default;
|
||||
this->AutogenTarget.DepFileRuleName.Default =
|
||||
cmStrCat(this->Dir.RelativeBuild, "/", timestampFileName);
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
|
||||
this->AddGeneratedSource(outputFile, this->Moc);
|
||||
}
|
||||
cc = cm::make_unique<cmCustomCommand>();
|
||||
cc->SetOutputs(outputFile);
|
||||
cc->SetByproducts(timestampByproducts);
|
||||
|
@ -1476,14 +1566,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
|||
cc->SetComment(autogenComment.c_str());
|
||||
cc->SetWorkingDirectory(this->Dir.Work.c_str());
|
||||
cc->SetEscapeOldStyle(false);
|
||||
cc->SetDepfile(this->AutogenTarget.DepFile);
|
||||
cc->SetDepfile(depFile);
|
||||
cc->SetStdPipesUTF8(stdPipesUTF8);
|
||||
this->LocalGen->AddCustomCommandToOutput(std::move(cc));
|
||||
|
||||
// Alter variables for the autogen target which now merely wraps the
|
||||
// custom command
|
||||
dependencies.clear();
|
||||
dependencies.emplace_back(outputFile);
|
||||
dependencies.emplace_back(std::move(outputFile));
|
||||
commandLines.clear();
|
||||
autogenComment.clear();
|
||||
}
|
||||
|
@ -1535,6 +1622,36 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
|
|||
return true;
|
||||
}
|
||||
|
||||
void cmQtAutoGenInitializer::AddCMakeProcessToCommandLines(
|
||||
std::string const& infoFile, std::string const& processName,
|
||||
cmCustomCommandLines& commandLines)
|
||||
{
|
||||
if (this->CrossConfig && this->UseBetterGraph) {
|
||||
commandLines.push_back(cmMakeCommandLine(
|
||||
{ cmSystemTools::GetCMakeCommand(), "-E", processName, infoFile,
|
||||
"$<CONFIG>", "$<COMMAND_CONFIG:$<CONFIG>>" }));
|
||||
} else if ((this->MultiConfig && this->GlobalGen->IsXcode()) ||
|
||||
this->CrossConfig) {
|
||||
for (std::string const& config : this->ConfigsList) {
|
||||
commandLines.push_back(
|
||||
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
|
||||
processName, infoFile, config }));
|
||||
}
|
||||
} else {
|
||||
std::string autoInfoFileConfig;
|
||||
if (this->MultiConfig) {
|
||||
autoInfoFileConfig = "$<CONFIG>";
|
||||
} else {
|
||||
std::vector<std::string> configs;
|
||||
this->GlobalGen->GetQtAutoGenConfigs(configs);
|
||||
autoInfoFileConfig = configs[0];
|
||||
}
|
||||
commandLines.push_back(
|
||||
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", processName,
|
||||
infoFile, autoInfoFileConfig }));
|
||||
}
|
||||
}
|
||||
|
||||
bool cmQtAutoGenInitializer::InitRccTargets()
|
||||
{
|
||||
for (Qrc const& qrc : this->Rcc.Qrcs) {
|
||||
|
@ -1555,18 +1672,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
|
|||
ccDepends.push_back(qrc.InfoFile);
|
||||
|
||||
cmCustomCommandLines commandLines;
|
||||
if (this->MultiConfig) {
|
||||
// Build for all configurations
|
||||
for (std::string const& config : this->ConfigsList) {
|
||||
commandLines.push_back(
|
||||
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
|
||||
"cmake_autorcc", qrc.InfoFile, config }));
|
||||
}
|
||||
} else {
|
||||
commandLines.push_back(
|
||||
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
|
||||
"cmake_autorcc", qrc.InfoFile, "$<CONFIG>" }));
|
||||
}
|
||||
AddCMakeProcessToCommandLines(qrc.InfoFile, "cmake_autorcc", commandLines);
|
||||
|
||||
std::string const ccComment =
|
||||
cmStrCat("Automatic RCC for ",
|
||||
|
@ -1617,13 +1723,28 @@ bool cmQtAutoGenInitializer::InitRccTargets()
|
|||
// Create custom rcc command
|
||||
{
|
||||
// Add the resource files to the dependencies
|
||||
for (std::string const& fileName : qrc.Resources) {
|
||||
// Add resource file to the custom command dependencies
|
||||
ccDepends.push_back(fileName);
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
// Add resource file to the custom command dependencies
|
||||
auto resourceFilesWithConfig = cmStrCat(
|
||||
"$<$<CONFIG:", config,
|
||||
">:", cmList{ qrc.Resources.Config.at(config) }.to_string(),
|
||||
">");
|
||||
ccDepends.emplace_back(std::move(resourceFilesWithConfig));
|
||||
}
|
||||
} else {
|
||||
for (std::string const& fileName : qrc.Resources.Default) {
|
||||
// Add resource file to the custom command dependencies
|
||||
ccDepends.push_back(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->Rcc.ExecutableTargetName.empty()) {
|
||||
ccDepends.push_back(this->Rcc.ExecutableTargetName);
|
||||
}
|
||||
|
||||
AddAutogenExecutableToDependencies(this->Rcc, ccDepends);
|
||||
|
||||
cc->SetOutputs(ccOutput);
|
||||
cc->SetDepends(ccDepends);
|
||||
this->LocalGen->AddCustomCommandToOutput(std::move(cc));
|
||||
|
@ -1723,6 +1844,8 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
|||
|
||||
// General
|
||||
info.SetBool("MULTI_CONFIG", this->MultiConfig);
|
||||
info.SetBool("CROSS_CONFIG", this->CrossConfig);
|
||||
info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
|
||||
info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
|
||||
#ifdef _WIN32
|
||||
info.SetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
|
||||
|
@ -1740,14 +1863,14 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
|||
|
||||
info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
|
||||
info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
|
||||
info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable);
|
||||
info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable);
|
||||
info.SetConfig("QT_MOC_EXECUTABLE", this->Moc.Executable);
|
||||
info.SetConfig("QT_UIC_EXECUTABLE", this->Uic.Executable);
|
||||
|
||||
info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
|
||||
info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
|
||||
info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
|
||||
info.Set("DEP_FILE", this->AutogenTarget.DepFile);
|
||||
info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
|
||||
info.SetConfig("DEP_FILE", this->AutogenTarget.DepFile);
|
||||
info.SetConfig("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
|
||||
info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
|
||||
info.SetArray("HEADER_EXTENSIONS",
|
||||
this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
|
||||
|
@ -1874,6 +1997,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
|
|||
|
||||
// General
|
||||
info.SetBool("MULTI_CONFIG", this->MultiConfig);
|
||||
info.SetBool("CROSS_CONFIG", this->CrossConfig);
|
||||
info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
|
||||
info.SetUInt("VERBOSITY", this->Verbosity);
|
||||
info.Set("GENERATOR", this->GlobalGen->GetName());
|
||||
|
||||
|
@ -1890,16 +2015,17 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
|
|||
info.SetConfig("INCLUDE_DIR", this->Dir.Include);
|
||||
|
||||
// rcc executable
|
||||
info.Set("RCC_EXECUTABLE", this->Rcc.Executable);
|
||||
info.SetArray("RCC_LIST_OPTIONS",
|
||||
this->Rcc.ExecutableFeatures->ListOptions);
|
||||
info.SetConfig("RCC_EXECUTABLE", this->Rcc.Executable);
|
||||
info.SetConfigArray(
|
||||
"RCC_LIST_OPTIONS",
|
||||
generateListOptions(this->Rcc.ExecutableFeatures, this->MultiConfig));
|
||||
|
||||
// qrc file
|
||||
info.Set("SOURCE", qrc.QrcFile);
|
||||
info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
|
||||
info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile));
|
||||
info.SetArray("OPTIONS", qrc.Options);
|
||||
info.SetArray("INPUTS", qrc.Resources);
|
||||
info.SetConfigArray("INPUTS", qrc.Resources);
|
||||
|
||||
info.Save(qrc.InfoFile);
|
||||
}
|
||||
|
@ -2244,16 +2370,32 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
|
|||
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
|
||||
cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt);
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
|
||||
genVars.Executable = cge->Evaluate(this->LocalGen, "");
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
genVars.Executable.Config[config] =
|
||||
cge->Evaluate(this->LocalGen, config);
|
||||
}
|
||||
} else {
|
||||
genVars.Executable.Default = cge->Evaluate(this->LocalGen, "");
|
||||
}
|
||||
}
|
||||
if (genVars.Executable.empty() && !ignoreMissingTarget) {
|
||||
|
||||
if (genVars.Executable.Default.empty() &&
|
||||
genVars.Executable.Config.empty() && !ignoreMissingTarget) {
|
||||
print_err(prop + " evaluates to an empty value");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create empty compiler features.
|
||||
genVars.ExecutableFeatures =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
genVars.ExecutableFeatures.Config[config] =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
}
|
||||
} else {
|
||||
genVars.ExecutableFeatures.Default =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2278,15 +2420,39 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
|
|||
genVars.ExecutableTargetName = targetName;
|
||||
genVars.ExecutableTarget = genTarget;
|
||||
if (genTarget->IsImported()) {
|
||||
genVars.Executable = genTarget->ImportedGetLocation("");
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
genVars.Executable.Config[config] =
|
||||
genTarget->ImportedGetLocation(config);
|
||||
}
|
||||
} else {
|
||||
genVars.Executable.Default =
|
||||
genTarget->ImportedGetLocation(this->ConfigDefault);
|
||||
}
|
||||
|
||||
} else {
|
||||
genVars.Executable = genTarget->GetLocation("");
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
genVars.Executable.Config[config] = genTarget->GetLocation(config);
|
||||
}
|
||||
} else {
|
||||
genVars.Executable.Default =
|
||||
genTarget->GetLocation(this->ConfigDefault);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ignoreMissingTarget) {
|
||||
// Create empty compiler features.
|
||||
genVars.ExecutableFeatures =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
genVars.ExecutableFeatures.Config[config] =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
}
|
||||
} else {
|
||||
genVars.ExecutableFeatures.Default =
|
||||
std::make_shared<cmQtAutoGen::CompilerFeatures>();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
print_err(cmStrCat("Could not find ", executable, " executable target ",
|
||||
|
@ -2299,10 +2465,22 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
|
|||
{
|
||||
std::string err;
|
||||
genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
|
||||
executable, genVars.Executable, err);
|
||||
if (!genVars.ExecutableFeatures) {
|
||||
print_err(err);
|
||||
return false;
|
||||
executable, genVars.Executable, err, this->MultiConfig,
|
||||
this->UseBetterGraph);
|
||||
if (this->MultiConfig && this->UseBetterGraph) {
|
||||
for (auto const& config : this->ConfigsList) {
|
||||
if (!genVars.ExecutableFeatures.Config[config]) {
|
||||
if (!genVars.ExecutableFeatures.Config[config]) {
|
||||
print_err(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!genVars.ExecutableFeatures.Default) {
|
||||
print_err(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "cmFilePathChecksum.h"
|
||||
#include "cmQtAutoGen.h"
|
||||
|
||||
class cmCustomCommandLines;
|
||||
class cmGeneratorTarget;
|
||||
class cmGlobalGenerator;
|
||||
class cmLocalGenerator;
|
||||
|
@ -33,23 +34,6 @@ class cmTarget;
|
|||
class cmQtAutoGenInitializer : public cmQtAutoGen
|
||||
{
|
||||
public:
|
||||
/** String value with per configuration variants. */
|
||||
class ConfigString
|
||||
{
|
||||
public:
|
||||
std::string Default;
|
||||
std::unordered_map<std::string, std::string> Config;
|
||||
};
|
||||
|
||||
/** String values with per configuration variants. */
|
||||
template <typename C>
|
||||
class ConfigStrings
|
||||
{
|
||||
public:
|
||||
C Default;
|
||||
std::unordered_map<std::string, C> Config;
|
||||
};
|
||||
|
||||
/** rcc job. */
|
||||
class Qrc
|
||||
{
|
||||
|
@ -64,7 +48,7 @@ public:
|
|||
bool Generated = false;
|
||||
bool Unique = false;
|
||||
std::vector<std::string> Options;
|
||||
std::vector<std::string> Resources;
|
||||
ConfigStrings<std::vector<std::string>> Resources;
|
||||
};
|
||||
|
||||
/** moc and/or uic file. */
|
||||
|
@ -91,8 +75,8 @@ public:
|
|||
// Executable
|
||||
std::string ExecutableTargetName;
|
||||
cmGeneratorTarget* ExecutableTarget = nullptr;
|
||||
std::string Executable;
|
||||
CompilerFeaturesHandle ExecutableFeatures;
|
||||
ConfigString Executable;
|
||||
ConfigStrings<CompilerFeaturesHandle> ExecutableFeatures;
|
||||
|
||||
GenVarsT(GenT gen)
|
||||
: Gen(gen)
|
||||
|
@ -142,6 +126,9 @@ private:
|
|||
GenVarsT const& genVars, bool prepend = false);
|
||||
void AddToSourceGroup(std::string const& fileName,
|
||||
cm::string_view genNameUpper);
|
||||
void AddCMakeProcessToCommandLines(std::string const& infoFile,
|
||||
std::string const& processName,
|
||||
cmCustomCommandLines& commandLines);
|
||||
void AddCleanFile(std::string const& fileName);
|
||||
|
||||
void ConfigFileNames(ConfigString& configString, cm::string_view prefix,
|
||||
|
@ -156,6 +143,9 @@ private:
|
|||
bool ignoreMissingTarget) const;
|
||||
|
||||
void handleSkipPch(cmSourceFile* sf);
|
||||
void AddAutogenExecutableToDependencies(
|
||||
cmQtAutoGenInitializer::GenVarsT const& genVars,
|
||||
std::vector<std::string>& dependencies) const;
|
||||
|
||||
cmQtAutoGenGlobalInitializer* GlobalInitializer = nullptr;
|
||||
cmGeneratorTarget* GenTarget = nullptr;
|
||||
|
@ -169,6 +159,7 @@ private:
|
|||
unsigned int Verbosity = 0;
|
||||
bool MultiConfig = false;
|
||||
bool CrossConfig = false;
|
||||
bool UseBetterGraph = false;
|
||||
bool CMP0071Accept = false;
|
||||
bool CMP0071Warn = false;
|
||||
bool CMP0100Accept = false;
|
||||
|
@ -205,8 +196,8 @@ private:
|
|||
bool DependOrigin = false;
|
||||
std::set<std::string> DependFiles;
|
||||
std::set<cmTarget*> DependTargets;
|
||||
std::string DepFile;
|
||||
std::string DepFileRuleName;
|
||||
ConfigString DepFile;
|
||||
ConfigString DepFileRuleName;
|
||||
// Sources to process
|
||||
std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
|
||||
std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
|
||||
|
|
|
@ -430,10 +430,12 @@ std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const
|
|||
return cmQtAutoGen::Quoted(res);
|
||||
}
|
||||
|
||||
bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config)
|
||||
bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig)
|
||||
{
|
||||
// Info config
|
||||
this->InfoConfig_ = std::string(config);
|
||||
this->ExecutableConfig_ = std::string(executableConfig);
|
||||
|
||||
// Info file
|
||||
this->InfoFile_ = std::string(infoFile);
|
||||
|
|
|
@ -90,6 +90,10 @@ public:
|
|||
std::string const& InfoDir() const { return this->InfoDir_; }
|
||||
cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; }
|
||||
std::string const& InfoConfig() const { return this->InfoConfig_; }
|
||||
std::string const& ExecutableConfig() const
|
||||
{
|
||||
return this->ExecutableConfig_;
|
||||
}
|
||||
|
||||
// -- Info file parsing
|
||||
/** Info file reader class. */
|
||||
|
@ -151,7 +155,8 @@ public:
|
|||
std::string MessagePath(cm::string_view path) const;
|
||||
|
||||
// -- Run
|
||||
bool Run(cm::string_view infoFile, cm::string_view config);
|
||||
bool Run(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig);
|
||||
|
||||
protected:
|
||||
// -- Abstract processing interface
|
||||
|
@ -170,6 +175,7 @@ private:
|
|||
std::string InfoDir_;
|
||||
cmFileTime InfoFileTime_;
|
||||
std::string InfoConfig_;
|
||||
std::string ExecutableConfig_;
|
||||
// -- Directories
|
||||
ProjectDirsT ProjectDirs_;
|
||||
};
|
||||
|
|
|
@ -171,6 +171,8 @@ public:
|
|||
// -- Attributes
|
||||
// - Config
|
||||
bool MultiConfig = false;
|
||||
bool CrossConfig = false;
|
||||
bool UseBetterGraph = false;
|
||||
IntegerVersion QtVersion = { 4, 0 };
|
||||
unsigned int ThreadCount = 0;
|
||||
unsigned int MaxCommandLineLength =
|
||||
|
@ -2380,6 +2382,9 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
|
|||
{
|
||||
// -- Required settings
|
||||
if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) ||
|
||||
!info.GetBool("CROSS_CONFIG", this->BaseConst_.CrossConfig, true) ||
|
||||
!info.GetBool("USE_BETTER_GRAPH", this->BaseConst_.UseBetterGraph,
|
||||
true) ||
|
||||
!info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major,
|
||||
true) ||
|
||||
!info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor,
|
||||
|
@ -2396,19 +2401,49 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
|
|||
true) ||
|
||||
!info.GetStringConfig("PARSE_CACHE_FILE",
|
||||
this->BaseConst_.ParseCacheFile, true) ||
|
||||
!info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) ||
|
||||
!info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName,
|
||||
false) ||
|
||||
!info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
|
||||
!info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) ||
|
||||
!info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions,
|
||||
true) ||
|
||||
!info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable,
|
||||
false) ||
|
||||
!info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable,
|
||||
false)) {
|
||||
true)) {
|
||||
return false;
|
||||
}
|
||||
if (this->BaseConst().UseBetterGraph) {
|
||||
if (!info.GetStringConfig("DEP_FILE", this->BaseConst_.DepFile, false) ||
|
||||
!info.GetStringConfig("DEP_FILE_RULE_NAME",
|
||||
this->BaseConst_.DepFileRuleName, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->BaseConst_.CrossConfig) {
|
||||
std::string const mocExecutableWithConfig =
|
||||
"QT_MOC_EXECUTABLE_" + this->ExecutableConfig();
|
||||
std::string const uicExecutableWithConfig =
|
||||
"QT_UIC_EXECUTABLE_" + this->ExecutableConfig();
|
||||
if (!info.GetString(mocExecutableWithConfig, this->MocConst_.Executable,
|
||||
false) ||
|
||||
!info.GetString(uicExecutableWithConfig, this->UicConst_.Executable,
|
||||
false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!info.GetStringConfig("QT_MOC_EXECUTABLE",
|
||||
this->MocConst_.Executable, false) ||
|
||||
!info.GetStringConfig("QT_UIC_EXECUTABLE",
|
||||
this->UicConst_.Executable, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable,
|
||||
false) ||
|
||||
!info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable,
|
||||
false) ||
|
||||
!info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) ||
|
||||
!info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName,
|
||||
false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Checks
|
||||
if (!this->BaseConst_.CMakeExecutableTime.Load(
|
||||
|
@ -3075,7 +3110,8 @@ std::string cmQtAutoMocUicT::AbsoluteIncludePath(
|
|||
|
||||
} // End of unnamed namespace
|
||||
|
||||
bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config)
|
||||
bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig)
|
||||
{
|
||||
return cmQtAutoMocUicT().Run(infoFile, config);
|
||||
return cmQtAutoMocUicT().Run(infoFile, config, executableConfig);
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
* Process AUTOMOC and AUTOUIC
|
||||
* @return true on success
|
||||
*/
|
||||
bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config);
|
||||
bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig);
|
||||
|
|
|
@ -35,6 +35,11 @@ public:
|
|||
private:
|
||||
// -- Utility
|
||||
bool IsMultiConfig() const { return this->MultiConfig_; }
|
||||
std::string const& GetGenerator() const { return this->Generator_; }
|
||||
bool IsXcode() const
|
||||
{
|
||||
return this->GetGenerator().find("Xcode") != std::string::npos;
|
||||
}
|
||||
std::string MultiConfigOutput() const;
|
||||
|
||||
// -- Abstract processing interface
|
||||
|
@ -53,6 +58,9 @@ private:
|
|||
|
||||
// -- Config settings
|
||||
bool MultiConfig_ = false;
|
||||
bool CrossConfig_ = false;
|
||||
bool UseBetterGraph_ = false;
|
||||
std::string Generator_;
|
||||
// -- Directories
|
||||
std::string AutogenBuildDir_;
|
||||
std::string IncludeDir_;
|
||||
|
@ -92,26 +100,57 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
|
|||
{
|
||||
// -- Required settings
|
||||
if (!info.GetBool("MULTI_CONFIG", this->MultiConfig_, true) ||
|
||||
!info.GetString("GENERATOR", this->Generator_, true) ||
|
||||
!info.GetBool("CROSS_CONFIG", this->CrossConfig_, true) ||
|
||||
!info.GetBool("USE_BETTER_GRAPH", this->UseBetterGraph_, true) ||
|
||||
!info.GetString("BUILD_DIR", this->AutogenBuildDir_, true) ||
|
||||
!info.GetStringConfig("INCLUDE_DIR", this->IncludeDir_, true) ||
|
||||
!info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) ||
|
||||
!info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) ||
|
||||
!info.GetArrayConfig("RCC_LIST_OPTIONS", this->RccListOptions_, false) ||
|
||||
!info.GetString("LOCK_FILE", this->LockFile_, true) ||
|
||||
!info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
|
||||
!info.GetString("SOURCE", this->QrcFile_, true) ||
|
||||
!info.GetString("OUTPUT_CHECKSUM", this->RccPathChecksum_, true) ||
|
||||
!info.GetString("OUTPUT_NAME", this->RccFileName_, true) ||
|
||||
!info.GetArray("OPTIONS", this->Options_, false) ||
|
||||
!info.GetArray("INPUTS", this->Inputs_, false)) {
|
||||
!info.GetArray("OPTIONS", this->Options_, false)) {
|
||||
return false;
|
||||
}
|
||||
if (this->UseBetterGraph_) {
|
||||
if (!info.GetArrayConfig("INPUTS", this->Inputs_, false)) {
|
||||
return false;
|
||||
}
|
||||
if (this->CrossConfig_) {
|
||||
std::string const rccExecutableWithConfig =
|
||||
"RCC_EXECUTABLE_" + this->ExecutableConfig();
|
||||
if (!info.GetString(rccExecutableWithConfig, this->RccExecutable_,
|
||||
true)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!info.GetStringConfig("RCC_EXECUTABLE", this->RccExecutable_,
|
||||
true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) ||
|
||||
!info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) ||
|
||||
!info.GetArray("INPUTS", this->Inputs_, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Derive information
|
||||
this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_);
|
||||
this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_);
|
||||
this->RccFilePublic_ =
|
||||
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
|
||||
this->RccFileName_);
|
||||
if (IsMultiConfig() && !this->IsXcode() && this->UseBetterGraph_) {
|
||||
this->RccFilePublic_ =
|
||||
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, "_",
|
||||
this->InfoConfig(), '/', this->RccFileName_);
|
||||
} else {
|
||||
this->RccFilePublic_ =
|
||||
cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
|
||||
this->RccFileName_);
|
||||
}
|
||||
|
||||
// rcc output file name
|
||||
if (this->IsMultiConfig()) {
|
||||
|
@ -520,7 +559,8 @@ bool cmQtAutoRccT::GenerateWrapper()
|
|||
|
||||
} // End of unnamed namespace
|
||||
|
||||
bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config)
|
||||
bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig)
|
||||
{
|
||||
return cmQtAutoRccT().Run(infoFile, config);
|
||||
return cmQtAutoRccT().Run(infoFile, config, executableConfig);
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
* Process AUTORCC
|
||||
* @return true on success
|
||||
*/
|
||||
bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config);
|
||||
bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config,
|
||||
cm::string_view executableConfig);
|
||||
|
|
|
@ -556,6 +556,7 @@ TargetProperty const StaticTargetProperties[] = {
|
|||
{ "AUTOGEN_ORIGIN_DEPENDS"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_PARALLEL"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_USE_SYSTEM_INCLUDE"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_BETTER_GRAPH_MULTI_CONFIG"_s, IC::CanCompileSources },
|
||||
// -- moc
|
||||
{ "AUTOMOC_DEPEND_FILTERS"_s, IC::CanCompileSources },
|
||||
// -- C++
|
||||
|
|
|
@ -1443,13 +1443,17 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
|
|||
if ((args[1] == "cmake_autogen") && (args.size() >= 4)) {
|
||||
cm::string_view const infoFile = args[2];
|
||||
cm::string_view const config = args[3];
|
||||
return cmQtAutoMocUic(infoFile, config) ? 0 : 1;
|
||||
cm::string_view const executableConfig =
|
||||
(args.size() >= 5) ? cm::string_view(args[4]) : cm::string_view();
|
||||
return cmQtAutoMocUic(infoFile, config, executableConfig) ? 0 : 1;
|
||||
}
|
||||
if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
|
||||
cm::string_view const infoFile = args[2];
|
||||
cm::string_view const config =
|
||||
(args.size() > 3) ? cm::string_view(args[3]) : cm::string_view();
|
||||
return cmQtAutoRcc(infoFile, config) ? 0 : 1;
|
||||
cm::string_view const executableConfig =
|
||||
(args.size() >= 5) ? cm::string_view(args[4]) : cm::string_view();
|
||||
return cmQtAutoRcc(infoFile, config, executableConfig) ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -128,65 +128,339 @@ if (DEFINED with_qt_version)
|
|||
if(QtCore_VERSION VERSION_GREATER_EQUAL 5.15.0)
|
||||
if (RunCMake_GENERATOR MATCHES "Ninja Multi-Config")
|
||||
set(config_list Debug Release RelWithDebInfo)
|
||||
set(use_better_graph_list ON OFF)
|
||||
else()
|
||||
set(config_list single-config)
|
||||
set(use_better_graph_list OFF)
|
||||
endif()
|
||||
foreach(config IN ITEMS ${config_list})
|
||||
block()
|
||||
if (config STREQUAL "single-config")
|
||||
set(config_suffix "")
|
||||
else()
|
||||
set(config_suffix "_${config}")
|
||||
endif()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtAutoMocDeps${config_suffix}-build)
|
||||
run_cmake(QtAutoMocDeps)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
# Build the project.
|
||||
if (config STREQUAL "single-config")
|
||||
set(config_param "")
|
||||
else()
|
||||
set(config_param "--config ${config}")
|
||||
endif()
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose ${config_param})
|
||||
# Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
|
||||
# for app_with_qt target.
|
||||
file(TOUCH "${RunCMake_SOURCE_DIR}/simple_lib.cpp")
|
||||
|
||||
# Build and assert that AUTOMOC was not run for app_with_qt, sub_exe_1 and sub_exe_2.
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose ${config_param})
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
unset(RunCMake_TEST_NOT_EXPECT_stdout)
|
||||
|
||||
macro(check_file_exists file)
|
||||
if (EXISTS "${file}")
|
||||
set(check_result "PASSED")
|
||||
set(message_type "STATUS")
|
||||
foreach(use_better_graph IN ITEMS ${use_better_graph_list})
|
||||
foreach(config IN ITEMS ${config_list})
|
||||
block()
|
||||
if (config STREQUAL "single-config")
|
||||
set(config_suffix "")
|
||||
else()
|
||||
set(check_result "FAILED")
|
||||
set(message_type "FATAL_ERROR")
|
||||
set(config_path "_${config}")
|
||||
if (use_better_graph)
|
||||
set(config_suffix "_${config}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(${message_type} "QtAutoMocDeps-build-\"${file}\" was generated - ${check_result}")
|
||||
endmacro()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtAutoMocDeps${config_path}-build)
|
||||
run_cmake_with_options(QtAutoMocDeps ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG=${use_better_graph})
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
# Build the project.
|
||||
if (config STREQUAL "single-config")
|
||||
set(config_param "")
|
||||
else()
|
||||
set(config_param "--config ${config}")
|
||||
endif()
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose ${config_param})
|
||||
# Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
|
||||
# for app_with_qt target.
|
||||
file(TOUCH "${RunCMake_SOURCE_DIR}/simple_lib.cpp")
|
||||
set(RunCMake_TEST_NOT_EXPECT_stdout "Automatic MOC for target app_with_qt|\
|
||||
Automatic MOC for target sub_exe_1|\
|
||||
Automatic MOC for target sub_exe_2")
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-Don't execute AUTOMOC for 'app_with_qt', 'sub_exe_1' and 'sub_exe_2'")
|
||||
# Build and assert that AUTOMOC was not run for app_with_qt, sub_exe_1 and sub_exe_2.
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose ${config_param})
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
unset(RunCMake_TEST_NOT_EXPECT_stdout)
|
||||
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/app_with_qt_autogen/deps")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir1/sub_exe_1_autogen/deps")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir2/sub_exe_2_autogen/deps")
|
||||
macro(check_file_exists file)
|
||||
if (EXISTS "${file}")
|
||||
set(check_result "PASSED")
|
||||
set(message_type "STATUS")
|
||||
else()
|
||||
set(check_result "FAILED")
|
||||
set(message_type "FATAL_ERROR")
|
||||
endif()
|
||||
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/app_with_qt_autogen/timestamp")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir1/sub_exe_1_autogen/timestamp")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir2/sub_exe_2_autogen/timestamp")
|
||||
message(${message_type} "QtAutoMocDeps-build-\"${file}\" was generated - ${check_result}")
|
||||
endmacro()
|
||||
|
||||
# Touch a header file to make sure an automoc dependency cycle is not introduced.
|
||||
file(TOUCH "${RunCMake_SOURCE_DIR}/MyWindow.h")
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-First build after touch to detect dependency cycle")
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose)
|
||||
# Need to run a second time to hit the dependency cycle.
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-Don't hit dependency cycle")
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose)
|
||||
endblock()
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/app_with_qt_autogen/deps${config_suffix}")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir1/sub_exe_1_autogen/deps${config_suffix}")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir2/sub_exe_2_autogen/deps${config_suffix}")
|
||||
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/app_with_qt_autogen/timestamp${config_suffix}")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir1/sub_exe_1_autogen/timestamp${config_suffix}")
|
||||
check_file_exists("${RunCMake_TEST_BINARY_DIR}/QtSubDir2/sub_exe_2_autogen/timestamp${config_suffix}")
|
||||
|
||||
# Touch a header file to make sure an automoc dependency cycle is not introduced.
|
||||
file(TOUCH "${RunCMake_SOURCE_DIR}/MyWindow.h")
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-First build after touch to detect dependency cycle")
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose)
|
||||
# Need to run a second time to hit the dependency cycle.
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-Don't hit dependency cycle")
|
||||
run_cmake_command(QtAutoMocDeps-build ${CMAKE_COMMAND} --build . --verbose)
|
||||
endblock()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
endblock()
|
||||
endif()
|
||||
|
||||
function(run_make_program dir)
|
||||
execute_process(
|
||||
COMMAND "${RunCMake_MAKE_PROGRAM}" ${ARGN}
|
||||
WORKING_DIRECTORY "${dir}"
|
||||
OUTPUT_VARIABLE make_program_stdout
|
||||
ERROR_VARIABLE make_program_stderr
|
||||
RESULT_VARIABLE make_program_result
|
||||
)
|
||||
if (NOT DEFINED RunMakeProgram_expected_result)
|
||||
set(RunMakeProgram_expected_result 0)
|
||||
endif()
|
||||
if(NOT "${make_program_result}" MATCHES "${RunMakeProgram_expected_result}")
|
||||
message(STATUS "
|
||||
============ beginning of ${RunCMake_MAKE_PROGRAM}'s stdout ============
|
||||
${make_program_stdout}
|
||||
=============== end of ${RunCMake_MAKE_PROGRAM}'s stdout ===============
|
||||
")
|
||||
message(STATUS "
|
||||
============ beginning of ${RunCMake_MAKE_PROGRAM}'s stderr ============
|
||||
${make_program_stderr}
|
||||
=============== end of ${RunCMake_MAKE_PROGRAM}'s stderr ===============
|
||||
")
|
||||
message(FATAL_ERROR
|
||||
"top ${RunCMake_MAKE_PROGRAM} build failed exited with status ${make_program_result}")
|
||||
endif()
|
||||
set(make_program_stdout "${make_program_stdout}" PARENT_SCOPE)
|
||||
endfunction(run_make_program)
|
||||
|
||||
function(count_substring STRING SUBSTRING COUNT_VAR)
|
||||
string(LENGTH "${STRING}" STRING_LENGTH)
|
||||
string(LENGTH "${SUBSTRING}" SUBSTRING_LENGTH)
|
||||
if (SUBSTRING_LENGTH EQUAL 0)
|
||||
message(FATAL_ERROR "SUBSTRING_LENGTH is 0")
|
||||
endif()
|
||||
|
||||
if (STRING_LENGTH EQUAL 0)
|
||||
message(FATAL_ERROR "STRING_LENGTH is 0")
|
||||
endif()
|
||||
|
||||
if (STRING_LENGTH LESS SUBSTRING_LENGTH)
|
||||
message(FATAL_ERROR "STRING_LENGTH is less than SUBSTRING_LENGTH")
|
||||
endif()
|
||||
|
||||
set(COUNT 0)
|
||||
string(FIND "${STRING}" "${SUBSTRING}" SUBSTRING_START)
|
||||
while(SUBSTRING_START GREATER_EQUAL 0)
|
||||
math(EXPR COUNT "${COUNT} + 1")
|
||||
math(EXPR SUBSTRING_START "${SUBSTRING_START} + ${SUBSTRING_LENGTH}")
|
||||
string(SUBSTRING "${STRING}" ${SUBSTRING_START} -1 STRING)
|
||||
string(FIND "${STRING}" "${SUBSTRING}" SUBSTRING_START)
|
||||
endwhile()
|
||||
|
||||
set(${COUNT_VAR} ${COUNT} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(expect_only_once make_program_stdout expected_output test_name)
|
||||
count_substring("${make_program_stdout}" "${expected_output}" count)
|
||||
if(NOT count EQUAL 1)
|
||||
message(STATUS "${test_name}-expect_only_once - FAILED")
|
||||
message(FATAL_ERROR "Expected to find ${expected_output} exactly once in ${make_program_stdout} but found ${count} occurrences of ${expected_output}")
|
||||
else()
|
||||
message(STATUS "${test_name}-expect_only_once - PASSED")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(expect_n_times string_to_check expected_output expected_count test_name)
|
||||
count_substring("${string_to_check}" "${expected_output}" count)
|
||||
if(NOT count EQUAL ${expected_count})
|
||||
message(STATUS "${test_name}-expect_${expected_count}_times - FAILED")
|
||||
message(FATAL_ERROR "Expected to find ${expected_output} exactly ${expected_count} times in ${string_to_check} but found ${count} occurrences of ${expected_output}")
|
||||
else()
|
||||
message(STATUS "${test_name}-expect_${expected_count}_times - PASSED")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(not_expect make_program_stdout unexpected_output test_name)
|
||||
count_substring("${make_program_stdout}" "${unexpected_output}" count)
|
||||
if(NOT count EQUAL 0)
|
||||
message(STATUS "${test_name}-not_expect - FAILED")
|
||||
message(FATAL_ERROR "Expected to find ${unexpected_output} exactly 0 times in ${make_program_stdout} but found ${count} occurrences of ${unexpected_output}")
|
||||
else()
|
||||
message(STATUS "${test_name}-not_expect - PASSED")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if (QtCore_VERSION VERSION_GREATER_EQUAL 5.15.0)
|
||||
foreach(exe IN ITEMS Moc Uic Rcc)
|
||||
if(RunCMake_GENERATOR MATCHES "Ninja Multi-Config")
|
||||
block()
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMake-configure")
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Auto${exe}ExecutableConfig-multi-config-build)
|
||||
run_cmake_with_options(Auto${exe}ExecutableConfig ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTOGEN_VERBOSE=ON -DCMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG=ON)
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
set(RunCMake_TEST_EXPECT_stdout ".*running_exe_${config}*")
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-${config}-expect_running_exe_${config}")
|
||||
run_cmake_command(Auto${exe}ExecutableConfig-multi-config-build ${CMAKE_COMMAND} --build . --config ${config})
|
||||
endblock()
|
||||
endforeach()
|
||||
set(RunCMake_TEST_EXPECT_stdout "ninja: no work to do")
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-${config}-expect_no_work_to_do")
|
||||
run_cmake_command(Auto${exe}ExecutableConfig-multi-config-build ${CMAKE_COMMAND} --build . --config ${config})
|
||||
endblock()
|
||||
endforeach()
|
||||
endblock()
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Auto${exe}ExecutableConfig-build)
|
||||
run_cmake_with_options(Auto${exe}ExecutableConfig ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTOGEN_VERBOSE=ON -DCMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG=ON)
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
run_make_program(${RunCMake_TEST_BINARY_DIR} --verbose -f build-${config}.ninja)
|
||||
|
||||
set(expected_output "running_exe_${config}")
|
||||
expect_only_once("${make_program_stdout}" "${expected_output}" "Auto${exe}ExecutableConfig-${config}-${expected_output}")
|
||||
|
||||
foreach(sub_config IN ITEMS Debug Release RelWithDebInfo)
|
||||
if(NOT sub_config STREQUAL config)
|
||||
set(unexpected_output "running_exe_${sub_config}")
|
||||
not_expect("${make_program_stdout}" "${unexpected_output}" "Auto${exe}ExecutableConfig-${config}-${unexpected_output}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (exe STREQUAL "Moc" OR exe STREQUAL "Uic")
|
||||
set(expected_output "cmake_autogen")
|
||||
else()
|
||||
set(expected_output "cmake_autorcc")
|
||||
endif()
|
||||
expect_only_once("${make_program_stdout}" "${expected_output}" "Auto${exe}ExecutableConfig-${config}-${expected_output}")
|
||||
endblock()
|
||||
endforeach()
|
||||
endblock()
|
||||
block()
|
||||
foreach(ninja_config IN ITEMS Debug Release RelWithDebInfo)
|
||||
foreach(target_config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
set(TEST_SUFFIX "-CrossConfig-${ninja_config}-${target_config}")
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Auto${exe}ExecutableConfig${TEST_SUFFIX}-build)
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION ${TEST_SUFFIX})
|
||||
run_cmake_with_options(Auto${exe}ExecutableConfig ${RunCMake_TEST_OPTIONS} -DCMAKE_CROSS_CONFIGS=all -DCMAKE_DEFAULT_BUILD_TYPE=${ninja_config} -DCMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG=ON)
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
|
||||
run_make_program(${RunCMake_TEST_BINARY_DIR} --verbose -f build-${ninja_config}.ninja dummy:${target_config})
|
||||
|
||||
set(expected_output "running_exe_${ninja_config}")
|
||||
expect_only_once("${make_program_stdout}" "${expected_output}" "Auto${exe}ExecutableConfig${TEST_SUFFIX}-${expected_output}")
|
||||
|
||||
foreach(sub_config IN ITEMS Debug Release RelWithDebInfo)
|
||||
if(NOT sub_config STREQUAL ninja_config)
|
||||
set(unexpected_output "running_exe_${sub_config}")
|
||||
not_expect("${make_program_stdout}" "${unexpected_output}" "Auto${exe}ExecutableConfig${TEST_SUFFIX}-${unexpected_output}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (exe STREQUAL "Moc" OR exe STREQUAL "Uic")
|
||||
set(expected_output "cmake_autogen")
|
||||
else()
|
||||
set(expected_output "cmake_autorcc")
|
||||
endif()
|
||||
expect_only_once("${make_program_stdout}" "${expected_output}" "Auto${exe}ExecutableConfig${TEST_SUFFIX}-${expected_output}")
|
||||
endblock()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endblock()
|
||||
block()
|
||||
foreach(ninja_config IN ITEMS Debug Release RelWithDebInfo)
|
||||
set(TEST_SUFFIX "-CrossConfig-${ninja_config}-all-all")
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Auto${exe}ExecutableConfig${TEST_SUFFIX}-build)
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION ${TEST_SUFFIX})
|
||||
run_cmake_with_options(Auto${exe}ExecutableConfig ${RunCMake_TEST_OPTIONS} -DCMAKE_CROSS_CONFIGS=all -DCMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG=ON)
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
run_make_program(${RunCMake_TEST_BINARY_DIR} --verbose -f build-${ninja_config}.ninja all:all)
|
||||
endforeach()
|
||||
endblock()
|
||||
elseif (RunCMake_GENERATOR MATCHES "Ninja|Make")
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Auto${exe}ExecutableConfig-build)
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-${config}")
|
||||
run_cmake_with_options(Auto${exe}ExecutableConfig ${RunCMake_TEST_OPTIONS} -DCMAKE_BUILD_TYPE=${config} -DCMAKE_AUTOGEN_VERBOSE=ON)
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
set(RunCMake_TEST_EXPECT_stdout ".*running_exe_${config}*")
|
||||
run_cmake_command(Auto${exe}ExecutableConfig-${config}-build ${CMAKE_COMMAND} --build .)
|
||||
endblock()
|
||||
endforeach()
|
||||
endblock()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Visual Studio specific dependency tests
|
||||
if (RunCMake_GENERATOR MATCHES "Visual Studio")
|
||||
foreach(exe IN ITEMS Moc Uic Rcc)
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${exe}Example-build)
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMake-configure")
|
||||
run_cmake_with_options(${exe}Example ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTOGEN_VERBOSE=ON)
|
||||
unset(RunCMake_TEST_VARIANT_DESCRIPTION)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-${config}-first-build")
|
||||
run_cmake_command(${exe}Example-build ${CMAKE_COMMAND} --build . --config ${config})
|
||||
endblock()
|
||||
endforeach()
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
if (exe STREQUAL "Moc" OR exe STREQUAL "Uic")
|
||||
set(RunCMake_TEST_NOT_EXPECT_stdout "Auto${exe}")
|
||||
set(not_expect_descripton "Auto${exe}")
|
||||
else ()
|
||||
set(RunCMake_TEST_NOT_EXPECT_stdout "Auto${exe}")
|
||||
set(not_expect_descripton "Auto${exe}")
|
||||
endif()
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-second-build-${config}_expect_no_${not_expect_descripton}")
|
||||
run_cmake_command(${exe}Example-build ${CMAKE_COMMAND} --build . --config ${config})
|
||||
endblock()
|
||||
endforeach()
|
||||
endblock()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (RunCMake_GENERATOR MATCHES "Xcode")
|
||||
foreach(exe IN ITEMS Moc Uic Rcc)
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${exe}Example-build)
|
||||
set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMake-configure")
|
||||
set(RunCMake_TEST_EXPECT_stderr ".*")
|
||||
run_cmake_with_options(${exe}Example ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTOGEN_VERBOSE=ON)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
set(RunCMake_MAKE_PROGRAM ${CMAKE_COMMAND})
|
||||
run_make_program(${RunCMake_TEST_BINARY_DIR} --build . --config Debug)
|
||||
if (exe STREQUAL "Moc")
|
||||
set(expected_count 16)
|
||||
elseif (exe STREQUAL "Uic")
|
||||
set(expected_count 4)
|
||||
else()
|
||||
set(expected_count 12)
|
||||
endif()
|
||||
expect_n_times("${make_program_stdout}" "Auto${exe}:" ${expected_count} "${exe}Example-build-Auto${exe}")
|
||||
expect_n_times("${make_program_stdout}" "Auto${exe}:" ${expected_count} "${exe}Example-build-Auto${exe}")
|
||||
|
||||
if (exe STREQUAL "Moc" OR exe STREQUAL "Uic")
|
||||
expect_n_times("${make_program_stdout}" "AutoGen:" 20 "${exe}Example-build-AutoGen:")
|
||||
endif()
|
||||
|
||||
foreach(config IN ITEMS Debug Release RelWithDebInfo)
|
||||
block()
|
||||
run_make_program(${RunCMake_TEST_BINARY_DIR} --build . --config ${config})
|
||||
not_expect("${make_program_stdout}" "Auto${exe}" "${exe}Example-${config}_Auto${exe}")
|
||||
not_expect("${make_program_stdout}" "AutoGen:" "${exe}Example-${config}_AutoGen")
|
||||
endblock()
|
||||
endforeach()
|
||||
endblock()
|
||||
endforeach()
|
||||
endif()
|
||||
endif ()
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/affine">
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,5 @@
|
|||
#include "example.h"
|
||||
|
||||
Example::Example()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef EXAMPLE_H
|
||||
#define EXAMPLE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Example : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Example();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
#include "example_ui.h"
|
||||
|
||||
Example::Example()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef EXAMPLE_UI_H
|
||||
#define EXAMPLE_UI_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "ui_uiA.h"
|
||||
|
||||
class Example : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Example();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef EXE_COMMON_H
|
||||
#define EXE_COMMON_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
inline int runRealExe(const int argc, char** argv)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
std::string realMocPath;
|
||||
std::string const pathArg = "EXE_PATH=";
|
||||
std::string cmd;
|
||||
if (argc > 1) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string const arg = argv[i];
|
||||
if (arg.find(pathArg) != std::string::npos) {
|
||||
realMocPath = arg.substr(pathArg.length());
|
||||
// if EXE_PATH contains spaces, wrap it in quotes
|
||||
if (realMocPath.find(" ") != std::string::npos) {
|
||||
realMocPath = "\"" + realMocPath + "\"";
|
||||
}
|
||||
} else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
cmd += "cmd /C \"";
|
||||
#endif
|
||||
cmd += realMocPath + " ";
|
||||
for (auto arg : args) {
|
||||
// if arg contains spaces, wrap it in quotes
|
||||
if (arg.find(' ') != std::string::npos) {
|
||||
cmd += " \"" + arg + "\"";
|
||||
} else {
|
||||
cmd += " " + arg;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
cmd += "\"";
|
||||
#endif
|
||||
std::cout << "Running real exe:" << cmd << std::endl;
|
||||
return std::system(cmd.c_str());
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "exe_common.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "running_exe_Debug\n";
|
||||
return runRealExe(argc, argv);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "exe_common.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "running_exe_Release\n";
|
||||
return runRealExe(argc, argv);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "exe_common.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "running_exe_RelWithDebInfo\n";
|
||||
return runRealExe(argc, argv);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UiA</class>
|
||||
<widget class="QWidget" name="UiA">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in New Issue