mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 10:50:16 -06:00
Autogen: Add INTERFACE_AUTOMOC_MACRO_NAMES target property
Add this target property to specify macro names that propagate to dependents as `AUTOMOC_MACRO_NAMES`. The dependents will automatically generate MOC files for source files that contain the inherited macro names. Co-Authored-By: Craig Scott <craig.scott@crascit.com> Fixes: #19679
This commit is contained in:
committed by
Craig Scott
parent
69cf9700e6
commit
c5c3aff1f5
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
89
Help/prop_tgt/INTERFACE_AUTOMOC_MACRO_NAMES.rst
Normal file
89
Help/prop_tgt/INTERFACE_AUTOMOC_MACRO_NAMES.rst
Normal 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``.
|
||||
5
Help/release/dev/automoc-macro-names.rst
Normal file
5
Help/release/dev/automoc-macro-names.rst
Normal 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.
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
61
Tests/QtAutogen/MocInterfaceMacroNames/CMakeLists.txt
Normal file
61
Tests/QtAutogen/MocInterfaceMacroNames/CMakeLists.txt
Normal 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}
|
||||
)
|
||||
@@ -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})
|
||||
@@ -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()
|
||||
4
Tests/QtAutogen/MocInterfaceMacroNames/dummy.cpp
Normal file
4
Tests/QtAutogen/MocInterfaceMacroNames/dummy.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
6
Tests/QtAutogen/MocInterfaceMacroNames/shared_lib.cpp
Normal file
6
Tests/QtAutogen/MocInterfaceMacroNames/shared_lib.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void foo()
|
||||
{
|
||||
}
|
||||
3
Tests/QtAutogen/MocInterfaceMacroNames/static_lib.cpp
Normal file
3
Tests/QtAutogen/MocInterfaceMacroNames/static_lib.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
void foo()
|
||||
{
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user