Commit c310480c authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

Merge topic 'autogen_global_target'

0e97ef74 Autogen: Add release notes for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
2ef8fe22 Autogen: Add documentation for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
8c8731b4 Autogen: Add test for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
3baa817c Autogen: Add support for global ``autogen`` and ``autorcc`` targets
3327d3bb

 Autogen: Add cmQtAutoGenGlobalInitializer class
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !2567
parents a16b24c9 0e97ef74
Pipeline #123650 passed with stage
in 0 seconds
......@@ -236,6 +236,7 @@ when either
:prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN`
or :policy:`CMP0071`
- :prop_tgt:`AUTOGEN_TARGET_DEPENDS` lists a source file
- :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled
qtmain.lib on Windows
=====================
......
......@@ -345,6 +345,10 @@ Variables that Control the Build
/variable/CMAKE_FOLDER
/variable/CMAKE_Fortran_FORMAT
/variable/CMAKE_Fortran_MODULE_DIRECTORY
/variable/CMAKE_GLOBAL_AUTOGEN_TARGET
/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
/variable/CMAKE_GLOBAL_AUTORCC_TARGET
/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME
/variable/CMAKE_GNUtoMS
/variable/CMAKE_INCLUDE_CURRENT_DIR
/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
......
......@@ -86,5 +86,9 @@ enabling :prop_sf:`SKIP_AUTOMOC` or the broader :prop_sf:`SKIP_AUTOGEN`.
The number of parallel ``moc`` processes to start can be modified by
setting :prop_tgt:`AUTOGEN_PARALLEL`.
A global ``autogen`` target that depends on all :prop_tgt:`AUTOMOC` generated
``<ORIGIN>_autogen`` targets in the project can be generated by enabling
:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
......@@ -35,5 +35,9 @@ generate unspecified unique names for ``rcc``. Therefore if
Source files can be excluded from :prop_tgt:`AUTORCC` processing by
enabling :prop_sf:`SKIP_AUTORCC` or the broader :prop_sf:`SKIP_AUTOGEN`.
A global ``autorcc`` target that depends on all :prop_tgt:`AUTORCC` targets
in the project can be generated by enabling
:variable:`CMAKE_GLOBAL_AUTORCC_TARGET`.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
......@@ -36,5 +36,9 @@ enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
The number of parallel ``uic`` processes to start can be modified by
setting :prop_tgt:`AUTOGEN_PARALLEL`.
A global ``autogen`` target that depends on all :prop_tgt:`AUTOUIC` generated
``<ORIGIN>_autogen`` targets in the project can be generated by enabling
:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
autogen_global_target
---------------------
* The new variables :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`,
:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`,
:variable:`CMAKE_GLOBAL_AUTORCC_TARGET` and
:variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME` control the generation
of global ``autogen`` and ``autorcc`` targets.
CMAKE_GLOBAL_AUTOGEN_TARGET
---------------------------
Switch to enable generation of a global ``autogen`` target.
When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
``autogen`` is generated. This target depends on all :prop_tgt:`AUTOMOC` and
:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project.
By building the global ``autogen`` target, all :prop_tgt:`AUTOMOC` and
:prop_tgt:`AUTOUIC` files in the project will be generated.
The name of the global ``autogen`` target can be changed by setting
:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`.
By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is unset.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
--------------------------------
Change the name of the global ``autogen`` target.
When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a global custom target
named ``autogen`` is created. :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`
allows to set a different name for that target.
By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
CMAKE_GLOBAL_AUTORCC_TARGET
---------------------------
Switch to enable generation of a global ``autorcc`` target.
When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
``autorcc`` is generated. This target depends on all :prop_tgt:`AUTORCC`
generated ``<ORIGIN>_arcc_<QRC>`` targets in the project.
By building the global ``autorcc`` target, all :prop_tgt:`AUTORCC`
files in the project will be generated.
The name of the global ``autorcc`` target can be changed by setting
:variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`.
By default :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is unset.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
CMAKE_GLOBAL_AUTORCC_TARGET_NAME
--------------------------------
Change the name of the global ``autorcc`` target.
When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a global custom target
named ``autorcc`` is created. :variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`
allows to set a different name for that target.
By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
......@@ -320,6 +320,8 @@ set(SRCS
cmQtAutoGen.h
cmQtAutoGenerator.cxx
cmQtAutoGenerator.h
cmQtAutoGenGlobalInitializer.cxx
cmQtAutoGenGlobalInitializer.h
cmQtAutoGenInitializer.cxx
cmQtAutoGenInitializer.h
cmQtAutoGeneratorMocUic.cxx
......
......@@ -34,8 +34,6 @@
#include "cmMakefile.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenInitializer.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
......@@ -46,6 +44,7 @@
#if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmCryptoHash.h"
# include "cmQtAutoGenGlobalInitializer.h"
# include "cm_jsoncpp_value.h"
# include "cm_jsoncpp_writer.h"
#endif
......@@ -1469,64 +1468,11 @@ bool cmGlobalGenerator::ComputeTargetDepends()
bool cmGlobalGenerator::QtAutoGen()
{
#ifdef CMAKE_BUILD_WITH_CMAKE
std::vector<std::unique_ptr<cmQtAutoGenInitializer>> autogenInits;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets =
localGen->GetGeneratorTargets();
// Find targets that require AUTOGEN processing
for (cmGeneratorTarget* target : targets) {
if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
continue;
}
if (target->GetType() != cmStateEnums::EXECUTABLE &&
target->GetType() != cmStateEnums::STATIC_LIBRARY &&
target->GetType() != cmStateEnums::SHARED_LIBRARY &&
target->GetType() != cmStateEnums::MODULE_LIBRARY &&
target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
continue;
}
if (target->IsImported()) {
continue;
}
const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC");
const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC");
const bool rccEnabled = target->GetPropertyAsBool("AUTORCC");
if (!mocEnabled && !uicEnabled && !rccEnabled) {
continue;
}
auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
// don't do anything if there is no Qt4 or Qt5Core (which contains moc)
if (qtVersion.Major != 4 && qtVersion.Major != 5) {
continue;
}
autogenInits.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
target, mocEnabled, uicEnabled, rccEnabled, qtVersion));
}
}
if (!autogenInits.empty()) {
// Initialize custom targets
for (auto& autoGen : autogenInits) {
if (!autoGen->InitCustomTargets()) {
return false;
}
}
// Setup custom targets
for (auto& autoGen : autogenInits) {
if (!autoGen->SetupCustomTargets()) {
return false;
}
autoGen.reset(nullptr);
}
}
#endif
cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators);
return initializer.generate();
#else
return true;
#endif
}
cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(
......
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGenGlobalInitializer.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenInitializer.h"
#include "cmAlgorithms.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include <memory>
#include <utility>
cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators)
{
for (cmLocalGenerator* localGen : localGenerators) {
// Detect global autogen and autorcc target names
bool globalAutoGenTarget = false;
bool globalAutoRccTarget = false;
{
cmMakefile* makefile = localGen->GetMakefile();
// Detect global autogen target name
if (cmSystemTools::IsOn(
makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET"))) {
std::string targetName =
makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME");
if (targetName.empty()) {
targetName = "autogen";
}
GlobalAutoGenTargets_.emplace(localGen, std::move(targetName));
globalAutoGenTarget = true;
}
// Detect global autorcc target name
if (cmSystemTools::IsOn(
makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET"))) {
std::string targetName =
makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME");
if (targetName.empty()) {
targetName = "autorcc";
}
GlobalAutoRccTargets_.emplace(localGen, std::move(targetName));
globalAutoRccTarget = true;
}
}
// Find targets that require AUTOMOC/UIC/RCC processing
for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
// Process only certain target types
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY:
// Process target
break;
default:
// Don't process target
continue;
}
if (target->IsImported()) {
// Don't process target
continue;
}
bool const moc = target->GetPropertyAsBool("AUTOMOC");
bool const uic = target->GetPropertyAsBool("AUTOUIC");
bool const rcc = target->GetPropertyAsBool("AUTORCC");
if (moc || uic || rcc) {
// We support Qt4 and Qt5
auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
if ((qtVersion.Major == 4) || (qtVersion.Major == 5)) {
// Create autogen target initializer
Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget,
globalAutoRccTarget));
}
}
}
}
}
cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer()
{
}
void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
cmLocalGenerator* localGen, std::string const& name,
std::string const& comment)
{
// Test if the target already exists
if (localGen->FindGeneratorTargetToUse(name) == nullptr) {
cmMakefile* makefile = localGen->GetMakefile();
// Create utility target
cmTarget* target = makefile->AddUtilityCommand(
name, cmMakefile::TargetOrigin::Generator, true,
makefile->GetHomeOutputDirectory().c_str() /*work dir*/,
std::vector<std::string>() /*output*/,
std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false,
comment.c_str());
localGen->AddGeneratorTarget(new cmGeneratorTarget(target, localGen));
// Set FOLDER property in the target
{
char const* folder =
makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
if (folder != nullptr) {
target->SetProperty("FOLDER", folder);
}
}
}
}
void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
cmLocalGenerator* localGen, std::string const& targetName)
{
auto it = GlobalAutoGenTargets_.find(localGen);
if (it != GlobalAutoGenTargets_.end()) {
cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
if (target != nullptr) {
target->Target->AddUtility(targetName, localGen->GetMakefile());
}
}
}
void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
cmLocalGenerator* localGen, std::string const& targetName)
{
auto it = GlobalAutoRccTargets_.find(localGen);
if (it != GlobalAutoRccTargets_.end()) {
cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
if (target != nullptr) {
target->Target->AddUtility(targetName, localGen->GetMakefile());
}
}
}
bool cmQtAutoGenGlobalInitializer::generate()
{
return (InitializeCustomTargets() && SetupCustomTargets());
}
bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
{
// Initialize global autogen targets
{
std::string const comment = "Global AUTOGEN target";
for (auto const& pair : GlobalAutoGenTargets_) {
GetOrCreateGlobalTarget(pair.first, pair.second, comment);
}
}
// Initialize global autorcc targets
{
std::string const comment = "Global AUTORCC target";
for (auto const& pair : GlobalAutoRccTargets_) {
GetOrCreateGlobalTarget(pair.first, pair.second, comment);
}
}
// Initialize per target autogen targets
for (auto& initializer : Initializers_) {
if (!initializer->InitCustomTargets()) {
return false;
}
}
return true;
}
bool cmQtAutoGenGlobalInitializer::SetupCustomTargets()
{
for (auto& initializer : Initializers_) {
if (!initializer->SetupCustomTargets()) {
return false;
}
}
return true;
}
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmQtAutoGenGlobalInitializer_h
#define cmQtAutoGenGlobalInitializer_h
#include "cmConfigure.h" // IWYU pragma: keep
#include <map>
#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
class cmLocalGenerator;
class cmQtAutoGenInitializer;
/// @brief Initializes the QtAutoGen generators
class cmQtAutoGenGlobalInitializer
{
public:
cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators);
~cmQtAutoGenGlobalInitializer();
bool generate();
private:
friend class cmQtAutoGenInitializer;
bool InitializeCustomTargets();
bool SetupCustomTargets();
void GetOrCreateGlobalTarget(cmLocalGenerator* localGen,
std::string const& name,
std::string const& comment);
void AddToGlobalAutoGen(cmLocalGenerator* localGen,
std::string const& targetName);
void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
std::string const& targetName);
private:
std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
};
#endif
......@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGenInitializer.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenGlobalInitializer.h"
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
......@@ -174,17 +175,19 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
return cycle;
}
cmQtAutoGenInitializer::cmQtAutoGenInitializer(cmGeneratorTarget* target,
bool mocEnabled,
bool uicEnabled,
bool rccEnabled,
IntegerVersion const& qtVersion)
: Target(target)
cmQtAutoGenInitializer::cmQtAutoGenInitializer(
cmQtAutoGenGlobalInitializer* globalInitializer, cmGeneratorTarget* target,
IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled,
bool rccEnabled, bool globalAutogenTarget, bool globalAutoRccTarget)
: GlobalInitializer(globalInitializer)
, Target(target)
, QtVersion(qtVersion)
{
AutogenTarget.GlobalTarget = globalAutogenTarget;
Moc.Enabled = mocEnabled;
Uic.Enabled = uicEnabled;
Rcc.Enabled = rccEnabled;
Rcc.GlobalTarget = globalAutoRccTarget;
}
bool cmQtAutoGenInitializer::InitCustomTargets()
......@@ -882,6 +885,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
if (!this->AutogenTarget.DependFiles.empty()) {
usePRE_BUILD = false;
}
// Cannot use PRE_BUILD when a global autogen target is in place
if (AutogenTarget.GlobalTarget) {
usePRE_BUILD = false;
}
}
// Create the autogen target/command
if (usePRE_BUILD) {
......@@ -961,6 +968,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
// Add autogen target to the origin target dependencies
this->Target->Target->AddUtility(this->AutogenTarget.Name, makefile);
// Add autogen target to the global autogen target dependencies
if (this->AutogenTarget.GlobalTarget) {
this->GlobalInitializer->AddToGlobalAutoGen(localGen,
this->AutogenTarget.Name);
}
}
return true;
......@@ -1004,7 +1017,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
std::string ccComment = "Automatic RCC for ";
ccComment += FileProjectRelativePath(makefile, qrc.QrcFile);
if (qrc.Generated) {
if (qrc.Generated || this->Rcc.GlobalTarget) {
// Create custom rcc target
std::string ccName;
{
......@@ -1035,6 +1048,11 @@ bool cmQtAutoGenInitializer::InitRccTargets()
}
// Add autogen target to the origin target dependencies
this->Target->Target->AddUtility(ccName, makefile);
// Add autogen target to the global autogen target dependencies
if (this->Rcc.GlobalTarget) {
this->GlobalInitializer->AddToGlobalAutoRcc(localGen, ccName);
}
} else {
// Create custom rcc command
{
......
......@@ -13,6 +13,7 @@
class cmGeneratorTarget;
class cmTarget;
class cmQtAutoGenGlobalInitializer;
/// @brief Initializes the QtAutoGen generators
class cmQtAutoGenInitializer : public cmQtAutoGen
......@@ -46,9 +47,11 @@ public:
public:
static IntegerVersion GetQtVersion(cmGeneratorTarget const* target);
cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled,
cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer,
cmGeneratorTarget* target,
IntegerVersion const& qtVersion, bool mocEnabled,
bool uicEnabled, bool rccEnabled,
IntegerVersion const& qtVersion);
bool globalAutogenTarget, bool globalAutoRccTarget);
bool InitCustomTargets();
bool SetupCustomTargets();
......@@ -76,6 +79,7 @@ private:
std::string& errorMessage);
private:
cmQtAutoGenGlobalInitializer* GlobalInitializer;
cmGeneratorTarget* Target;
// Configuration
......@@ -100,6 +104,7 @@ private:
struct
{
std::string Name;
bool GlobalTarget = false;
// Settings
std::string Parallel;
// Configuration files
......@@ -148,6 +153,7 @@ private:
struct
{
bool Enabled = false;
bool GlobalTarget = false;
std::string Executable;
std::vector<std::string> ListOptions;
std::vector<Qrc> Qrcs;
......
......@@ -7,6 +7,7 @@ ADD_AUTOGEN_TEST(UicOnly uicOnly)
ADD_AUTOGEN_TEST(RccOnly rccOnly)
ADD_AUTOGEN_TEST(RccEmpty rccEmpty)
ADD_AUTOGEN_TEST(RccOffMocLibrary)
ADD_AUTOGEN_TEST(GlobalAutogenTarget)
if(QT_TEST_ALLOW_QT_MACROS)
ADD_AUTOGEN_TEST(MocSkipSource)
endif()
......
cmake_minimum_required(VERSION 3.12)
project(GlobalAutogenTarget)
include("../AutogenTest.cmake")
# This tests
# CMAKE_GLOBAL_AUTOGEN_TARGET,
# CMAKE_GLOBAL_AUTORCC_TARGET,
# CMAKE_GLOBAL_AUTOGEN_TARGET_NAME and
# CMAKE_GLOBAL_AUTORCC_TARGET_NAME
# for the latter two with different values in different subdirectories.
# Directories
set(GAT_SDIR "