From 26f8dff7daeb6538b9308d2bef77ecea8bd2a80e Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Wed, 30 Jul 2025 16:38:47 +0200 Subject: [PATCH] CMake: Add warnings as errors support for example builds We want to ensure we don't introduce new build warnings in examples. We have a mechanism to enable warnings as errors for qt targets like modules or plugins, but not for targets in example projects. To enable this, we introduce a new internal target PlatformExampleInternal, which is linked to all targets created by qt_add_executable and qt_add_library-like functions in projects in the /examples subdirectory. The detection of targets in example projects is done by checking the QT_INTERNAL_IS_EXAMPLE_EP_BUILD variable or the QT_INTERNAL_IS_EXAMPLE_IN_TREE_BUILD variable. These are set either by ExternalProject_Add in the case of external example projects, or by qt_examples_build_begin in the case of in-tree example projects. The PlatformExampleInternal target gets the same warnings as errors flags as the other Platform*Internal targets. To enable gradual adoption, the new feature is opt-in rather than opt-out, on a per-repo basis. The QT_REPO_EXAMPLES_WARNINGS_CLEAN variable can be set to TRUE in a repo's '.cmake.conf' file. The warnings as errors behavior is controlled as usual by configuring qt with -DWARNINGS_ARE_ERRORS=ON. Pick-to: 6.8 6.9 6.10 Task-number: QTBUG-108448 Change-Id: If62b47b205c111f2a1fec791e5bb6502f5b64f9c Reviewed-by: Alexey Edelev --- cmake/QtBaseGlobalTargets.cmake | 5 ++++- cmake/QtBuildRepoExamplesHelpers.cmake | 6 ++++++ cmake/QtFindPackageHelpers.cmake | 1 + cmake/QtFlagHandlingHelpers.cmake | 6 +----- cmake/QtInternalTargets.cmake | 4 ++++ cmake/QtPublicTargetHelpers.cmake | 9 ++++++++ src/corelib/Qt6CoreMacros.cmake | 29 ++++++++++++++++++++++++++ 7 files changed, 54 insertions(+), 6 deletions(-) diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index 601592277fe..08044843a18 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -161,6 +161,7 @@ target_include_directories(GlobalConfigPrivate INTERFACE qt_internal_setup_public_platform_target() # defines PlatformCommonInternal PlatformModuleInternal PlatformPluginInternal PlatformToolInternal +# PlatformExampleInternal include(QtInternalTargets) qt_internal_run_common_config_tests() @@ -175,7 +176,9 @@ set(__export_targets Platform PlatformModuleInternal PlatformPluginInternal PlatformAppInternal - PlatformToolInternal) + PlatformToolInternal + PlatformExampleInternal + ) set(__export_name "${INSTALL_CMAKE_NAMESPACE}Targets") qt_install(TARGETS ${__export_targets} EXPORT "${__export_name}") qt_install(EXPORT ${__export_name} diff --git a/cmake/QtBuildRepoExamplesHelpers.cmake b/cmake/QtBuildRepoExamplesHelpers.cmake index d9e219ae80b..a6d7c2b144b 100644 --- a/cmake/QtBuildRepoExamplesHelpers.cmake +++ b/cmake/QtBuildRepoExamplesHelpers.cmake @@ -89,6 +89,9 @@ macro(qt_examples_build_begin) if(active_linker_flags) add_link_options(${active_linker_flags}) endif() + + # Marker for warnings_as_errors. + set(QT_INTERNAL_IS_EXAMPLE_IN_TREE_BUILD ON) endif() # TODO: Change this to TRUE when all examples in all repos are ported to use @@ -467,6 +470,8 @@ function(qt_internal_add_example_external_project subdir) QT_ADDITIONAL_PACKAGES_PREFIX_PATH:STRING QT_ADDITIONAL_QML_PLUGIN_GLOB_PREFIXES:STRING QT_INTERNAL_SKIP_DEPLOYMENT:BOOL + QT_REPO_EXAMPLES_WARNINGS_CLEAN:BOOL + WARNINGS_ARE_ERRORS:BOOL CMAKE_FIND_ROOT_PATH:STRING CMAKE_MODULE_PATH:STRING BUILD_SHARED_LIBS:BOOL @@ -608,6 +613,7 @@ function(qt_internal_add_example_external_project subdir) TEST_COMMAND "" DEPENDS ${deps} CMAKE_CACHE_ARGS ${var_defs} + -DQT_INTERNAL_IS_EXAMPLE_EP_BUILD:BOOL=TRUE -DCMAKE_INSTALL_PREFIX:STRING= -DQT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT:BOOL=TRUE ${terminal_args} diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake index 614fe8a9dfd..aadf0bf1f7f 100644 --- a/cmake/QtFindPackageHelpers.cmake +++ b/cmake/QtFindPackageHelpers.cmake @@ -466,6 +466,7 @@ function(qt_internal_is_lib_part_of_qt6_package lib out_var) OR lib STREQUAL "PlatformPluginInternal" OR lib STREQUAL "PlatformToolInternal" OR lib STREQUAL "PlatformCommonInternal" + OR lib STREQUAL "PlatformExampleInternal" ) set(${out_var} "TRUE" PARENT_SCOPE) else() diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake index 46793eb6c8d..8f50e0e686b 100644 --- a/cmake/QtFlagHandlingHelpers.cmake +++ b/cmake/QtFlagHandlingHelpers.cmake @@ -315,11 +315,7 @@ endfunction() # Controls the QT_SKIP_WARNINGS_ARE_ERRORS property for the given target. function(qt_internal_set_skip_warnings_are_errors target value) - get_target_property(target_type "${target}" TYPE) - if(target_type STREQUAL "INTERFACE_LIBRARY") - return() - endif() - set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ${value}) + _qt_internal_set_skip_warnings_are_errors("${target}" "${value}") endfunction() # Sets the default warnings behavior according to the WARNINGS_ARE_ERRORS and diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake index c041f9d3ac5..0ef27717502 100644 --- a/cmake/QtInternalTargets.cmake +++ b/cmake/QtInternalTargets.cmake @@ -162,6 +162,7 @@ function(qt_internal_add_global_definition definition) set(scope_PLUGIN PlatformPluginInternal) set(scope_TOOL PlatformToolInternal) set(scope_APP PlatformAppInternal) + set(scope_EXAMPLE PlatformExampleInternal) set(undef_property_name "QT_INTERNAL_UNDEF_${definition}") @@ -199,6 +200,8 @@ target_link_libraries(PlatformAppInternal INTERFACE PlatformCommonInternal) qt_internal_add_platform_internal_target(PlatformToolInternal) target_link_libraries(PlatformToolInternal INTERFACE PlatformAppInternal) +qt_internal_add_platform_internal_target(PlatformExampleInternal) + qt_internal_add_global_definition(QT_NO_JAVA_STYLE_ITERATORS) qt_internal_add_global_definition(QT_NO_QASCONST) qt_internal_add_global_definition(QT_NO_QEXCHANGE) @@ -212,6 +215,7 @@ qt_internal_add_global_definition(QT_NO_STD_FORMAT_SUPPORT SCOPE PLUGIN TOOL MOD qt_internal_set_warnings_are_errors_flags(PlatformModuleInternal INTERFACE) qt_internal_set_warnings_are_errors_flags(PlatformPluginInternal INTERFACE) qt_internal_set_warnings_are_errors_flags(PlatformAppInternal INTERFACE) +qt_internal_set_warnings_are_errors_flags(PlatformExampleInternal INTERFACE) if(WIN32) # Needed for M_PI define. Same as mkspecs/features/qt_module.prf. diff --git a/cmake/QtPublicTargetHelpers.cmake b/cmake/QtPublicTargetHelpers.cmake index 27f7c3acf79..5bec6011e9f 100644 --- a/cmake/QtPublicTargetHelpers.cmake +++ b/cmake/QtPublicTargetHelpers.cmake @@ -480,6 +480,15 @@ function(_qt_internal_set_up_static_runtime_library target) endif() endfunction() +# Controls the QT_SKIP_WARNINGS_ARE_ERRORS property for the given target. +function(_qt_internal_set_skip_warnings_are_errors target value) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ${value}) +endfunction() + function(_qt_internal_warn_about_example_add_subdirectory) # This is set by qt_build_repo_impl_examples() in QtBuildRepoHelpers.cmake, only for developer # builds, to catch examples that are added via add_subdirectory instead of via diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 46283381a42..dd6108066b6 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -695,6 +695,31 @@ function(_qt_internal_disable_autorcc_zstd_when_not_supported target) endif() endfunction() +# Link given target to PlatformExampleInternal when the target is part of an example build. +function(_qt_internal_link_to_platform_example_internal target) + # The first variable is set when examples are built using ExternalProject_Add. + # The second is set when examples are built in-tree, the scope is in the /examples subdir. + if(QT_INTERNAL_IS_EXAMPLE_EP_BUILD + OR QT_INTERNAL_IS_EXAMPLE_IN_TREE_BUILD) + target_link_libraries("${target}" PRIVATE + ${QT_CMAKE_EXPORT_NAMESPACE}::PlatformExampleInternal) + endif() +endfunction() + +# Set up warnings as errors for targets built in example projects. +function(_qt_internal_setup_warnings_are_errors_for_example_target target) + # Only enable warnings as errors when the global variable is enabled and the repo is known + # to have clean examples. + if(QT_INTERNAL_IS_EXAMPLE_EP_BUILD + OR QT_INTERNAL_IS_EXAMPLE_IN_TREE_BUILD) + if(WARNINGS_ARE_ERRORS AND QT_REPO_EXAMPLES_WARNINGS_CLEAN) + _qt_internal_set_skip_warnings_are_errors("${target}" FALSE) + else() + _qt_internal_set_skip_warnings_are_errors("${target}" TRUE) + endif() + endif() +endfunction() + function(_qt_internal_create_executable target) if(ANDROID) list(REMOVE_ITEM ARGN "WIN32" "MACOSX_BUNDLE") @@ -727,6 +752,8 @@ function(_qt_internal_create_executable target) endif() _qt_internal_disable_autorcc_zstd_when_not_supported("${target}") + _qt_internal_link_to_platform_example_internal("${target}") + _qt_internal_setup_warnings_are_errors_for_example_target("${target}") _qt_internal_set_up_static_runtime_library("${target}") endfunction() @@ -2834,6 +2861,8 @@ function(_qt_internal_add_library target) cmake_policy(POP) _qt_internal_disable_autorcc_zstd_when_not_supported("${target}") + _qt_internal_link_to_platform_example_internal("${target}") + _qt_internal_setup_warnings_are_errors_for_example_target("${target}") _qt_internal_set_up_static_runtime_library(${target}) if(NOT type_to_create STREQUAL "INTERFACE" AND NOT type_to_create STREQUAL "OBJECT")