Merge topic 'automoc-macro-names'

c5c3aff1f5 Autogen: Add INTERFACE_AUTOMOC_MACRO_NAMES target property
69cf9700e6 Autogen: Defer setup until Generate step
7cecb6353e cmGeneratorTarget: Factor out EvaluatedTargetProperty infrastructure
2daba01ddf cmGeneratorTarget: Avoid incidental include-what-you-use warning
850b4d990c IWYU: Add mapping for 'std::remove_reference<Defer &>::type'

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !8391
This commit is contained in:
Craig Scott 2023-04-10 22:05:54 +00:00 committed by Kitware Robot
commit e245b4df75
24 changed files with 550 additions and 201 deletions

View File

@ -220,6 +220,7 @@ syn keyword cmakeProperty contained
\ INSTALL_RPATH
\ INSTALL_RPATH_USE_LINK_PATH
\ INTERFACE_AUTOUIC_OPTIONS
\ INTERFACE_AUTOMOC_MACRO_NAMES
\ INTERFACE_COMPILE_DEFINITIONS
\ INTERFACE_COMPILE_FEATURES
\ INTERFACE_COMPILE_OPTIONS

View File

@ -273,6 +273,7 @@ Properties on Targets
/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH
/prop_tgt/INSTALL_RPATH
/prop_tgt/INSTALL_RPATH_USE_LINK_PATH
/prop_tgt/INTERFACE_AUTOMOC_MACRO_NAMES
/prop_tgt/INTERFACE_AUTOUIC_OPTIONS
/prop_tgt/INTERFACE_COMPILE_DEFINITIONS
/prop_tgt/INTERFACE_COMPILE_FEATURES

View File

@ -3,7 +3,7 @@ AUTOMOC_MACRO_NAMES
.. versionadded:: 3.10
A :ref:`semicolon-separated list <CMake Language Lists>` list of macro names used by
A :ref:`semicolon-separated list <CMake Language Lists>` of macro names used by
:prop_tgt:`AUTOMOC` to determine if a C++ file needs to be processed by ``moc``.
This property is only used if the :prop_tgt:`AUTOMOC` property is ``ON``
@ -21,6 +21,8 @@ then the file will be processed by ``moc``.
By default ``AUTOMOC_MACRO_NAMES`` is initialized from
:variable:`CMAKE_AUTOMOC_MACRO_NAMES`.
See also the :prop_tgt:`INTERFACE_AUTOMOC_MACRO_NAMES` target property.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
@ -29,6 +31,8 @@ Example
In this case the ``Q_OBJECT`` macro is hidden inside another macro
called ``CUSTOM_MACRO``. To let CMake know that source files that contain
``CUSTOM_MACRO`` need to be ``moc`` processed, we call::
``CUSTOM_MACRO`` need to be ``moc`` processed, we call:
.. code-block:: cmake
set_property(TARGET tgt APPEND PROPERTY AUTOMOC_MACRO_NAMES "CUSTOM_MACRO")

View File

@ -0,0 +1,89 @@
INTERFACE_AUTOMOC_MACRO_NAMES
-----------------------------
.. versionadded:: 3.27
A :ref:`semicolon-separated list <CMake Language Lists>` of macro names for
:prop_tgt:`AUTOMOC` to be propagated to consumers.
When a target with :prop_tgt:`AUTOMOC` enabled links to a library that sets
``INTERFACE_AUTOMOC_MACRO_NAMES``, the target inherits the listed macro names
and merges them with those specified in its own :prop_tgt:`AUTOMOC_MACRO_NAMES`
property. The target will then automatically generate MOC files for source
files that contain the inherited macro names too, not just the macro names
specified in its own :prop_tgt:`AUTOMOC_MACRO_NAMES` property.
By default ``INTERFACE_AUTOMOC_MACRO_NAMES`` is empty.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
Example 1
^^^^^^^^^
In this example, ``myapp`` inherits the macro names ``STATIC_LIB_1`` and
``STATIC_LIB_2`` from ``static_lib``. The ``moc`` tool will then automatically
be run on any of the ``myapp`` sources which contain ``STATIC_LIB_1`` or
``STATIC_LIB_2``.
.. code-block:: cmake
set(AUTOMOC ON)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE static_lib)
add_library(static_lib STATIC static.cpp)
set_property(TARGET static_lib PROPERTY
INTERFACE_AUTOMOC_MACRO_NAMES "STATIC_LIB_1;STATIC_LIB_2"
)
Example 2
^^^^^^^^^
In this example, the ``INTERFACE_AUTOMOC_MACRO_NAMES`` target property of the
various ``*_deep_lib`` libraries will propagate to ``shared_lib``,
``static_lib`` and ``interface_lib``. Because the linking relationships are
specified as ``PUBLIC`` and ``INTERFACE``, those macro names will also further
propagate transitively up to ``app``.
.. code-block:: cmake
set(AUTOMOC ON)
add_library(shared_deep_lib SHARED deep_lib.cpp)
add_library(static_deep_lib STATIC deep_lib.cpp)
add_library(interface_deep_lib INTERFACE)
set_property(TARGET shared_deep_lib PROPERTY
INTERFACE_AUTOMOC_MACRO_NAMES "SHARED_LINK_LIB"
)
set_property(TARGET static_deep_lib PROPERTY
INTERFACE_AUTOMOC_MACRO_NAMES "STATIC_LINK_LIB"
)
set_property(TARGET interface_deep_lib PROPERTY
INTERFACE_AUTOMOC_MACRO_NAMES "INTERFACE_LINK_LIB"
)
add_library(shared_lib SHARED lib.cpp)
add_library(static_lib STATIC lib.cpp)
add_library(interface_lib INTERFACE)
# PUBLIC and INTERFACE here ensure the macro names propagate to any
# consumers of shared_lib, static_lib or interface_lib too
target_link_libraries(shared_lib PUBLIC shared_deep_lib)
target_link_libraries(static_lib PUBLIC static_deep_lib)
target_link_libraries(interface_lib INTERFACE interface_deep_lib)
# This consumer will receive all three of the above custom macro names as
# transitive usage requirements
add_executable(app main.cpp)
target_link_libraries(app PRIVATE shared_lib static_lib interface_lib)
In the above:
* ``shared_lib`` sources will be processed by ``moc`` if they contain
``SHARED_LINK_LIB``.
* ``static_lib`` sources will be processed by ``moc`` if they contain
``STATIC_LINK_LIB``.
* ``app`` sources will be processed by ``moc`` if they contain
``SHARED_LINK_LIB``, ``STATIC_LINK_LIB`` or ``INTERFACE_LINK_LIB``.

View File

@ -0,0 +1,5 @@
automoc-macro-names
-------------------
* The :prop_tgt:`INTERFACE_AUTOMOC_MACRO_NAMES` target property was added to
specify macro names for ``moc`` as a transitive usage requirement.

View File

@ -193,6 +193,8 @@ add_library(
cmDyndepCollation.h
cmELF.h
cmELF.cxx
cmEvaluatedTargetProperty.cxx
cmEvaluatedTargetProperty.h
cmExprParserHelper.cxx
cmExportBuildAndroidMKGenerator.h
cmExportBuildAndroidMKGenerator.cxx

View File

@ -0,0 +1,111 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmEvaluatedTargetProperty.h"
#include <unordered_map>
#include <utility>
#include "cmGeneratorExpressionContext.h"
#include "cmGeneratorTarget.h"
#include "cmLinkItem.h"
#include "cmStringAlgorithms.h"
struct cmGeneratorExpressionDAGChecker;
EvaluatedTargetPropertyEntry::EvaluatedTargetPropertyEntry(
cmLinkImplItem const& item, cmListFileBacktrace bt)
: LinkImplItem(item)
, Backtrace(std::move(bt))
{
}
EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
cmGeneratorTarget::TargetPropertyEntry& entry)
{
EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
thisTarget, dagChecker, lang),
ee.Values);
if (entry.GetHadContextSensitiveCondition()) {
ee.ContextDependent = true;
}
return ee;
}
EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
in)
{
EvaluatedTargetPropertyEntries out;
out.Entries.reserve(in.size());
for (auto const& entry : in) {
out.Entries.emplace_back(EvaluateTargetPropertyEntry(
thisTarget, config, lang, dagChecker, *entry));
}
return out;
}
namespace {
void addInterfaceEntry(cmGeneratorTarget const* headTarget,
std::string const& config, std::string const& prop,
std::string const& lang,
cmGeneratorExpressionDAGChecker* dagChecker,
EvaluatedTargetPropertyEntries& entries,
cmGeneratorTarget::LinkInterfaceFor interfaceFor,
std::vector<cmLinkImplItem> const& libraries)
{
for (cmLinkImplItem const& lib : libraries) {
if (lib.Target) {
EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
// Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
// caller's property and hand-evaluate it as if it were compiled.
// Create a context as cmCompiledGeneratorExpression::Evaluate does.
cmGeneratorExpressionContext context(
headTarget->GetLocalGenerator(), config, false, headTarget, headTarget,
true, lib.Backtrace, lang);
cmExpandList(lib.Target->EvaluateInterfaceProperty(
prop, &context, dagChecker, interfaceFor),
ee.Values);
ee.ContextDependent = context.HadContextSensitiveCondition;
entries.Entries.emplace_back(std::move(ee));
}
}
}
}
void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
std::string const& config, std::string const& prop,
std::string const& lang,
cmGeneratorExpressionDAGChecker* dagChecker,
EvaluatedTargetPropertyEntries& entries,
IncludeRuntimeInterface searchRuntime,
cmGeneratorTarget::LinkInterfaceFor interfaceFor)
{
if (searchRuntime == IncludeRuntimeInterface::Yes) {
if (cmLinkImplementation const* impl =
headTarget->GetLinkImplementation(config, interfaceFor)) {
entries.HadContextSensitiveCondition =
impl->HadContextSensitiveCondition;
auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang);
if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) {
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, runtimeLibIt->second);
}
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, impl->Libraries);
}
} else {
if (cmLinkImplementationLibraries const* impl =
headTarget->GetLinkImplementationLibraries(config, interfaceFor)) {
entries.HadContextSensitiveCondition =
impl->HadContextSensitiveCondition;
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, impl->Libraries);
}
}
}

View File

@ -0,0 +1,80 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "cmGeneratorTarget.h"
#include "cmListFileCache.h"
class cmLinkImplItem;
struct cmGeneratorExpressionDAGChecker;
// Represent a target property entry after evaluating generator expressions
// and splitting up lists.
struct EvaluatedTargetPropertyEntry
{
EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
cmListFileBacktrace bt);
// Move-only.
EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
delete;
EvaluatedTargetPropertyEntry& operator=(
EvaluatedTargetPropertyEntry const&) = delete;
cmLinkImplItem const& LinkImplItem;
cmListFileBacktrace Backtrace;
std::vector<std::string> Values;
bool ContextDependent = false;
};
EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
cmGeneratorTarget::TargetPropertyEntry& entry);
struct EvaluatedTargetPropertyEntries
{
std::vector<EvaluatedTargetPropertyEntry> Entries;
bool HadContextSensitiveCondition = false;
};
EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
in);
// IncludeRuntimeInterface is used to break the cycle in computing
// the necessary transitive dependencies of targets that can occur
// now that we have implicit language runtime targets.
//
// To determine the set of languages that a target has we need to iterate
// all the sources which includes transitive INTERFACE sources.
// Therefore we can't determine what language runtimes are needed
// for a target until after all sources are computed.
//
// Therefore while computing the applicable INTERFACE_SOURCES we
// must ignore anything in LanguageRuntimeLibraries or we would
// create a cycle ( INTERFACE_SOURCES requires LanguageRuntimeLibraries,
// LanguageRuntimeLibraries requires INTERFACE_SOURCES).
//
enum class IncludeRuntimeInterface
{
Yes,
No
};
void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
std::string const& config, std::string const& prop,
std::string const& lang,
cmGeneratorExpressionDAGChecker* dagChecker,
EvaluatedTargetPropertyEntries& entries,
IncludeRuntimeInterface searchRuntime,
cmGeneratorTarget::LinkInterfaceFor interfaceFor =
cmGeneratorTarget::LinkInterfaceFor::Usage);

View File

@ -106,6 +106,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
cmGeneratorExpression::BuildInterface,
properties);
this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gte,
cmGeneratorExpression::BuildInterface,
properties);
this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
cmGeneratorExpression::BuildInterface,
properties);

View File

@ -110,6 +110,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
properties);
this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt,
cmGeneratorExpression::InstallInterface,
properties);
this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
cmGeneratorExpression::InstallInterface,
properties);

View File

@ -27,6 +27,7 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmEvaluatedTargetProperty.h"
#include "cmFileSet.h"
#include "cmFileTimes.h"
#include "cmGeneratedFileStream.h"
@ -89,31 +90,38 @@ cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
return tgt->GetLocation(config);
}
class cmGeneratorTarget::TargetPropertyEntry
{
protected:
static cmLinkImplItem NoLinkImplItem;
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
{
public:
TargetPropertyEntry(cmLinkImplItem const& item)
: LinkImplItem(item)
TargetPropertyEntryString(BT<std::string> propertyValue,
cmLinkImplItem const& item = NoLinkImplItem)
: cmGeneratorTarget::TargetPropertyEntry(item)
, PropertyValue(std::move(propertyValue))
{
}
virtual ~TargetPropertyEntry() = default;
virtual const std::string& Evaluate(
cmLocalGenerator* lg, const std::string& config,
cmGeneratorTarget const* headTarget,
cmGeneratorExpressionDAGChecker* dagChecker,
std::string const& language) const = 0;
const std::string& Evaluate(cmLocalGenerator*, const std::string&,
cmGeneratorTarget const*,
cmGeneratorExpressionDAGChecker*,
std::string const&) const override
{
return this->PropertyValue.Value;
}
virtual cmListFileBacktrace GetBacktrace() const = 0;
virtual std::string const& GetInput() const = 0;
virtual bool GetHadContextSensitiveCondition() const { return false; }
cmListFileBacktrace GetBacktrace() const override
{
return this->PropertyValue.Backtrace;
}
std::string const& GetInput() const override
{
return this->PropertyValue.Value;
}
cmLinkImplItem const& LinkImplItem;
private:
BT<std::string> PropertyValue;
};
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
{
@ -150,37 +158,6 @@ private:
const std::unique_ptr<cmCompiledGeneratorExpression> ge;
};
class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
{
public:
TargetPropertyEntryString(BT<std::string> propertyValue,
cmLinkImplItem const& item = NoLinkImplItem)
: cmGeneratorTarget::TargetPropertyEntry(item)
, PropertyValue(std::move(propertyValue))
{
}
const std::string& Evaluate(cmLocalGenerator*, const std::string&,
cmGeneratorTarget const*,
cmGeneratorExpressionDAGChecker*,
std::string const&) const override
{
return this->PropertyValue.Value;
}
cmListFileBacktrace GetBacktrace() const override
{
return this->PropertyValue.Backtrace;
}
std::string const& GetInput() const override
{
return this->PropertyValue.Value;
}
private:
BT<std::string> PropertyValue;
};
class TargetPropertyEntryFileSet
: public cmGeneratorTarget::TargetPropertyEntry
{
@ -263,6 +240,18 @@ std::unique_ptr<
cm::make_unique<TargetPropertyEntryString>(propertyValue));
}
cmGeneratorTarget::TargetPropertyEntry::TargetPropertyEntry(
cmLinkImplItem const& item)
: LinkImplItem(item)
{
}
bool cmGeneratorTarget::TargetPropertyEntry::GetHadContextSensitiveCondition()
const
{
return false;
}
static void CreatePropertyGeneratorExpressions(
cmake& cmakeInstance, cmBTStringRange entries,
std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
@ -274,69 +263,6 @@ static void CreatePropertyGeneratorExpressions(
}
}
namespace {
// Represent a target property entry after evaluating generator expressions
// and splitting up lists.
struct EvaluatedTargetPropertyEntry
{
EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
cmListFileBacktrace bt)
: LinkImplItem(item)
, Backtrace(std::move(bt))
{
}
// Move-only.
EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
delete;
EvaluatedTargetPropertyEntry& operator=(
EvaluatedTargetPropertyEntry const&) = delete;
cmLinkImplItem const& LinkImplItem;
cmListFileBacktrace Backtrace;
std::vector<std::string> Values;
bool ContextDependent = false;
};
EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
cmGeneratorTarget::TargetPropertyEntry& entry)
{
EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
thisTarget, dagChecker, lang),
ee.Values);
if (entry.GetHadContextSensitiveCondition()) {
ee.ContextDependent = true;
}
return ee;
}
struct EvaluatedTargetPropertyEntries
{
std::vector<EvaluatedTargetPropertyEntry> Entries;
bool HadContextSensitiveCondition = false;
};
EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
cmGeneratorTarget const* thisTarget, std::string const& config,
std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
in)
{
EvaluatedTargetPropertyEntries out;
out.Entries.reserve(in.size());
for (auto const& entry : in) {
out.Entries.emplace_back(EvaluateTargetPropertyEntry(
thisTarget, config, lang, dagChecker, *entry));
}
return out;
}
}
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
: Target(t)
{
@ -1607,84 +1533,6 @@ void AddLangSpecificImplicitIncludeDirectories(
}
}
void addInterfaceEntry(cmGeneratorTarget const* headTarget,
std::string const& config, std::string const& prop,
std::string const& lang,
cmGeneratorExpressionDAGChecker* dagChecker,
EvaluatedTargetPropertyEntries& entries,
LinkInterfaceFor interfaceFor,
std::vector<cmLinkImplItem> const& libraries)
{
for (cmLinkImplItem const& lib : libraries) {
if (lib.Target) {
EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
// Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
// caller's property and hand-evaluate it as if it were compiled.
// Create a context as cmCompiledGeneratorExpression::Evaluate does.
cmGeneratorExpressionContext context(
headTarget->GetLocalGenerator(), config, false, headTarget, headTarget,
true, lib.Backtrace, lang);
cmExpandList(lib.Target->EvaluateInterfaceProperty(
prop, &context, dagChecker, interfaceFor),
ee.Values);
ee.ContextDependent = context.HadContextSensitiveCondition;
entries.Entries.emplace_back(std::move(ee));
}
}
}
// IncludeRuntimeInterface is used to break the cycle in computing
// the necessary transitive dependencies of targets that can occur
// now that we have implicit language runtime targets.
//
// To determine the set of languages that a target has we need to iterate
// all the sources which includes transitive INTERFACE sources.
// Therefore we can't determine what language runtimes are needed
// for a target until after all sources are computed.
//
// Therefore while computing the applicable INTERFACE_SOURCES we
// must ignore anything in LanguageRuntimeLibraries or we would
// create a cycle ( INTERFACE_SOURCES requires LanguageRuntimeLibraries,
// LanguageRuntimeLibraries requires INTERFACE_SOURCES).
//
enum class IncludeRuntimeInterface
{
Yes,
No
};
void AddInterfaceEntries(
cmGeneratorTarget const* headTarget, std::string const& config,
std::string const& prop, std::string const& lang,
cmGeneratorExpressionDAGChecker* dagChecker,
EvaluatedTargetPropertyEntries& entries,
IncludeRuntimeInterface searchRuntime,
LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage)
{
if (searchRuntime == IncludeRuntimeInterface::Yes) {
if (cmLinkImplementation const* impl =
headTarget->GetLinkImplementation(config, interfaceFor)) {
entries.HadContextSensitiveCondition =
impl->HadContextSensitiveCondition;
auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang);
if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) {
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, runtimeLibIt->second);
}
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, impl->Libraries);
}
} else {
if (cmLinkImplementationLibraries const* impl =
headTarget->GetLinkImplementationLibraries(config, interfaceFor)) {
entries.HadContextSensitiveCondition =
impl->HadContextSensitiveCondition;
addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries,
interfaceFor, impl->Libraries);
}
}
}
void AddObjectEntries(cmGeneratorTarget const* headTarget,
std::string const& config,
cmGeneratorExpressionDAGChecker* dagChecker,
@ -8977,10 +8825,10 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
cmGeneratedFileStream fout(filename);
fout.SetCopyIfDifferent(true);
// IWYU pragma: associated allows include what you use to
// The IWYU "associated" pragma tells include-what-you-use to
// consider the headerFile as part of the entire language
// unit within include-what-you-use and as a result allows
// one to get IWYU advice for headers :)
// one to get IWYU advice for headers.
fout << "#include <" << headerFilename << "> // IWYU pragma: associated\n";
fout.close();

View File

@ -1291,3 +1291,25 @@ private:
};
mutable std::map<std::string, InfoByConfig> Configs;
};
class cmGeneratorTarget::TargetPropertyEntry
{
protected:
static cmLinkImplItem NoLinkImplItem;
public:
TargetPropertyEntry(cmLinkImplItem const& item);
virtual ~TargetPropertyEntry() = default;
virtual const std::string& Evaluate(
cmLocalGenerator* lg, const std::string& config,
cmGeneratorTarget const* headTarget,
cmGeneratorExpressionDAGChecker* dagChecker,
std::string const& language) const = 0;
virtual cmListFileBacktrace GetBacktrace() const = 0;
virtual std::string const& GetInput() const = 0;
virtual bool GetHadContextSensitiveCondition() const;
cmLinkImplItem const& LinkImplItem;
};

View File

@ -1544,8 +1544,9 @@ bool cmGlobalGenerator::Compute()
}
#ifndef CMAKE_BOOTSTRAP
cmQtAutoGenGlobalInitializer qtAutoGen(this->LocalGenerators);
if (!qtAutoGen.InitializeCustomTargets()) {
this->QtAutoGen =
cm::make_unique<cmQtAutoGenGlobalInitializer>(this->LocalGenerators);
if (!this->QtAutoGen->InitializeCustomTargets()) {
return false;
}
#endif
@ -1565,12 +1566,6 @@ bool cmGlobalGenerator::Compute()
}
}
#ifndef CMAKE_BOOTSTRAP
if (!qtAutoGen.SetupCustomTargets()) {
return false;
}
#endif
for (const auto& localGen : this->LocalGenerators) {
cmMakefile* mf = localGen->GetMakefile();
for (const auto& g : mf->GetInstallGenerators()) {
@ -1635,6 +1630,17 @@ void cmGlobalGenerator::Generate()
this->CMakeInstance->UpdateProgress("Generating", 0.1f);
#ifndef CMAKE_BOOTSTRAP
if (!this->QtAutoGen->SetupCustomTargets()) {
if (!cmSystemTools::GetErrorOccurredFlag()) {
this->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
"Problem setting up custom targets for QtAutoGen");
}
return;
}
#endif
// Generate project files
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());

View File

@ -50,6 +50,7 @@ class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
class cmOutputConverter;
class cmQtAutoGenGlobalInitializer;
class cmSourceFile;
class cmState;
class cmStateDirectory;
@ -683,6 +684,11 @@ protected:
cmake* CMakeInstance;
std::vector<std::unique_ptr<cmMakefile>> Makefiles;
LocalGeneratorVector LocalGenerators;
#ifndef CMAKE_BOOTSTRAP
std::unique_ptr<cmQtAutoGenGlobalInitializer> QtAutoGen;
#endif
cmMakefile* CurrentConfigureMakefile;
// map from project name to vector of local generators in that project
std::map<std::string, std::vector<cmLocalGenerator*>> ProjectMap;

View File

@ -28,8 +28,10 @@
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmEvaluatedTargetProperty.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmLinkItem.h"
@ -1691,6 +1693,23 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
info.SetArray("MOC_OPTIONS", this->Moc.Options);
info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
cmGeneratorExpressionDAGChecker dagChecker(
this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr);
EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries;
AddInterfaceEntries(this->GenTarget, this->ConfigDefault,
"INTERFACE_AUTOMOC_MACRO_NAMES", "CXX", &dagChecker,
InterfaceAutoMocMacroNamesEntries,
IncludeRuntimeInterface::Yes);
for (auto const& entry : InterfaceAutoMocMacroNamesEntries.Entries) {
this->Moc.MacroNames.insert(this->Moc.MacroNames.end(),
entry.Values.begin(), entry.Values.end());
}
this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
this->Moc.MacroNames.end());
info.SetArray("MOC_MACRO_NAMES", this->Moc.MacroNames);
info.SetArrayArray(
"MOC_DEPEND_FILTERS", this->Moc.DependFilters,

View File

@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.16)
project(MocInterfaceMacroNames)
include("../AutogenCoreTest.cmake")
set(CMAKE_AUTOMOC ON)
add_executable(dummy dummy.cpp)
target_link_libraries(dummy PRIVATE static_lib interface_lib shared_lib)
add_library(shared_lib SHARED shared_lib.cpp)
set_target_properties(shared_lib PROPERTIES INTERFACE_AUTOMOC_MACRO_NAMES "SHARED_LIB_MACRO")
add_library(interface_lib INTERFACE)
set_target_properties(interface_lib PROPERTIES INTERFACE_AUTOMOC_MACRO_NAMES "INTERFACE_LIB_MACRO")
add_library(static_lib STATIC static_lib.cpp)
set_target_properties(static_lib PROPERTIES INTERFACE_AUTOMOC_MACRO_NAMES "STATIC_LIB_MACRO")
set(AUTOGEN_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/dummy_autogen.dir/AutogenInfo.json")
set(CHECK_AUTOGEN_JSON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CheckAutogenJson.cmake")
message(STATUS "AutogenInfo.json: ${AUTOGEN_INFO_FILE}")
add_custom_command(TARGET dummy POST_BUILD
COMMAND ${CMAKE_COMMAND} -DFILE_PATH=${AUTOGEN_INFO_FILE} -P ${CHECK_AUTOGEN_JSON_PATH}
)
install(TARGETS shared_lib EXPORT shared_lib)
install(TARGETS interface_lib EXPORT interface_lib)
install(TARGETS static_lib EXPORT static_lib)
install(EXPORT shared_lib FILE shared_libTargets.cmake DESTINATION lib/cmake/shared_lib)
install(EXPORT interface_lib FILE interface_libTargets.cmake DESTINATION lib/cmake/interface_lib)
install(EXPORT static_lib FILE static_libTargets.cmake DESTINATION lib/cmake/static_lib)
set(CHECK_EXPORT_TARGETS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CheckExportTargets.cmake")
set(EXPORT_FOLDER_PATH "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Export")
add_custom_command(TARGET dummy POST_BUILD
COMMAND ${CMAKE_COMMAND} -DFOLDER_PATH=${EXPORT_FOLDER_PATH} -P ${CHECK_EXPORT_TARGETS_PATH}
)
# check if INTERFACE_AUTOMOC_MACRO_NAMES were transferred to the *_link libraries correctly
add_executable(dummy_link dummy.cpp)
target_link_libraries(dummy_link PRIVATE static_link_lib interface_link_lib shared_link_lib)
add_library(shared_link_lib SHARED shared_lib.cpp)
target_link_libraries(shared_link_lib PUBLIC shared_lib)
add_library(interface_link_lib INTERFACE)
target_link_libraries(interface_link_lib INTERFACE interface_lib)
add_library(static_link_lib STATIC static_lib.cpp)
target_link_libraries(static_link_lib PUBLIC static_lib)
set(AUTOGEN_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/dummy_link_autogen.dir/AutogenInfo.json")
message(STATUS "AutogenInfo.json: ${AUTOGEN_INFO_FILE}")
add_custom_command(TARGET dummy_link POST_BUILD
COMMAND ${CMAKE_COMMAND} -DFILE_PATH=${AUTOGEN_INFO_FILE} -P ${CHECK_AUTOGEN_JSON_PATH}
)

View File

@ -0,0 +1,27 @@
set(expected_values "SHARED_LIB_MACRO" "INTERFACE_LIB_MACRO" "STATIC_LIB_MACRO")
function(checkAutoMocMacroNames FILE_PATH)
message(STATUS "Checking for auto moc macro names in ${FILE_PATH}")
file(READ ${FILE_PATH} FILE_CONTENT)
string(JSON MOC_MACRO_NAMES_ARR GET ${FILE_CONTENT} MOC_MACRO_NAMES)
# get the length of MOC_MACRO_NAMES in JSON
string(JSON MOC_MACRO_NAMES_LENGTH LENGTH ${MOC_MACRO_NAMES_ARR})
if(${MOC_MACRO_NAMES_LENGTH} EQUAL 0)
message(FATAL_ERROR "MOC_MACRO_NAMES is empty")
endif()
message(STATUS "MOC_MACRO_NAMES: ${MOC_MACRO_NAMES_ARR}")
math(EXPR last_index "${MOC_MACRO_NAMES_LENGTH} - 1")
set(reverse_index ${last_index})
foreach(expected_value IN LISTS expected_values)
string(JSON element GET ${MOC_MACRO_NAMES_ARR} ${reverse_index})
# check if element equals to expected value
if(NOT ${element} STREQUAL ${expected_value})
message(FATAL_ERROR "MOC_MACRO_NAMES is expected to contain ${expected_value} but contains ${element}")
endif()
math(EXPR reverse_index "${reverse_index} - 1")
endforeach()
endfunction()
checkAutoMocMacroNames(${FILE_PATH})

View File

@ -0,0 +1,45 @@
set(TARGET_NAMES "static_lib" "shared_lib" "interface_lib")
set(static_lib_FOUND "0")
set(shared_lib_FOUND "0")
set(interface_lib_FOUND "0")
macro(checkExportTargets FOLDER_PATH)
message("Checking folder: ${FOLDER_PATH}")
file(GLOB sources_list LIST_DIRECTORIES true RELATIVE ${FOLDER_PATH} ${FOLDER_PATH}/*)
message("Found files and folders: ${sources_list}")
foreach(source ${sources_list})
set(SOURCE_ABS "${FOLDER_PATH}/${source}")
if(IS_DIRECTORY ${SOURCE_ABS})
message("Found subfolder: ${source}")
checkExportTargets(${SOURCE_ABS})
else()
message("Found file: ${source}")
foreach(TARGET_NAME ${TARGET_NAMES})
set(TARGETS_FILE "${TARGET_NAME}Targets.cmake")
if(${source} STREQUAL ${TARGETS_FILE})
message("Found ${TARGETS_FILE} in ${FOLDER_PATH}")
string(TOUPPER ${TARGET_NAME} TARGET_NAME_UPPER)
set(expected_macro "${TARGET_NAME_UPPER}_MACRO")
set(expected_string "INTERFACE_AUTOMOC_MACRO_NAMES \"${expected_macro}\"")
file(READ ${FOLDER_PATH}/${source} contents)
if (NOT contents MATCHES ${expected_string})
message(FATAL_ERROR "Expected ${expected_string} in ${FOLDER_PATH}/${source}")
else()
message("Found ${expected_string} in ${FOLDER_PATH}/${source}")
set(${TARGET_NAME}_FOUND "1")
endif()
endif()
endforeach()
endif()
endforeach()
endmacro()
checkExportTargets(${FOLDER_PATH})
foreach(TARGET_NAME ${TARGET_NAMES})
# check if the target found equals the expected value
if(NOT ${TARGET_NAME}_FOUND STREQUAL "1")
message(FATAL_ERROR "Did not find ${TARGET_NAME}Targets.cmake")
endif()
endforeach()

View File

@ -0,0 +1,4 @@
int main()
{
return 0;
}

View File

@ -0,0 +1,6 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
void foo()
{
}

View File

@ -0,0 +1,3 @@
void foo()
{
}

View File

@ -7,6 +7,7 @@ ADD_AUTOGEN_TEST(GlobalAutogenTarget)
ADD_AUTOGEN_TEST(GlobalAutogenExecutable)
ADD_AUTOGEN_TEST(LowMinimumVersion lowMinimumVersion)
ADD_AUTOGEN_TEST(ManySources manySources)
ADD_AUTOGEN_TEST(MocInterfaceMacroNames)
ADD_AUTOGEN_TEST(MocOnly mocOnly)
ADD_AUTOGEN_TEST(MocOptions mocOptions)
ADD_AUTOGEN_TEST(ObjectLibrary someProgram)

View File

@ -99,6 +99,7 @@
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<60, 1> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1000> > >::type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "__gnu_cxx::__enable_if<true, bool>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::remove_reference<Defer &>::type", private, "\"cmConfigure.h\"", public ] },
# Wrappers for 3rd-party libraries
{ include: [ "@<.*curl/curlver.h>", private, "<cm3p/curl/curl.h>", public ] },

View File

@ -338,6 +338,7 @@ CMAKE_CXX_SOURCES="\
cmELF \
cmEnableLanguageCommand \
cmEnableTestingCommand \
cmEvaluatedTargetProperty \
cmExecProgramCommand \
cmExecuteProcessCommand \
cmExpandedCommandArgument \