From db21bad936a761f475145886f1e06dfcfa11eb80 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 19 Aug 2020 14:05:29 +0200 Subject: Port headersclean check to CMake Configure Qt with -DQT_FEATURE_headersclean=ON to enable the check. There will be separate target for each module include (e.g. QtCore_header_check), but the check will also be done when the module is built for the first time. There are notable differences to the qmake version: - the build does not pick up anymore default defines or flags from the module, or Qt. Instead options like -fPIC they have to be listed explicitly. Also for this reason, we have to skip the vulkan-related headers from the check, since vulkan/vulkan.h is not necessarily in the compiler's default search path. - some checks for nowadays unsupported compiler versions are removed. - -Wdouble-promotion -Wshorten-64-to-32 is not added for clang builds; the qmake code path did never enforce that on CI machines (it was non-Apple clang only), and the check currently fails on these configurations. Fixes: QTBUG-82615 Change-Id: I1cd303677b1472116910b6c27748f96436feb35e Reviewed-by: Alexandru Croitor --- cmake/QtBuild.cmake | 1 + cmake/QtHeadersClean.cmake | 139 +++++++++++++++++++++++++++++++++++++++ cmake/QtModuleHelpers.cmake | 7 ++ src/gui/vulkan/qvulkaninstance.h | 1 + src/gui/vulkan/qvulkanwindow.h | 1 + 5 files changed, 149 insertions(+) create mode 100644 cmake/QtHeadersClean.cmake diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index c1a14230d6..27fe8d4226 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -467,6 +467,7 @@ include(QtSyncQtHelpers) include(QtTargetHelpers) include(QtTestHelpers) include(QtToolHelpers) +include(QtHeadersClean) # This sets up the scope finalizer mechanism. variable_watch(CMAKE_CURRENT_LIST_DIR qt_watch_current_list_dir) diff --git a/cmake/QtHeadersClean.cmake b/cmake/QtHeadersClean.cmake new file mode 100644 index 0000000000..9719cdbaa5 --- /dev/null +++ b/cmake/QtHeadersClean.cmake @@ -0,0 +1,139 @@ +# Add a custom ${module_include_name}_header_check target that builds each header in +# ${module_headers} with a custom set of defines. This makes sure our public headers +# are self-contained, and also compile with more strict compiler options. +function(qt_internal_add_headers_clean_target + module_target + module_include_name + module_headers) + # module_headers is a list of strings of the form + # [:feature] + set(hclean_headers "") + foreach(entry ${module_headers}) + string(REPLACE ":" ";" entry_list ${entry}) + list(LENGTH entry_list entry_list_length) + list(GET entry_list 0 entry_path) + + if (${entry_list_length} EQUAL 2) + list(GET entry_list 1 entry_feature) + if (NOT QT_FEATURE_${entry_feature}) + message(STATUS "headersclean: Ignoring header ${entry_path} because of missing feature ${entry_feature}") + continue() + endif() + endif() + list(APPEND hclean_headers ${entry_path}) + endforeach() + + # Make sure that the header compiles with our strict options + set(hcleanDEFS -DQT_NO_CAST_TO_ASCII + -DQT_NO_CAST_FROM_ASCII + -DQT_NO_URL_CAST_FROM_STRING + -DQT_NO_CAST_FROM_BYTEARRAY + -DQT_NO_KEYWORDS + -DQT_USE_QSTRINGBUILDER + -DQT_USE_FAST_OPERATOR_PLUS) + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" + OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" + OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + # Turn on some extra warnings not found in -Wall -Wextra. + + set(hcleanFLAGS -Wall -Wextra -Werror -Woverloaded-virtual -Wshadow -Wundef -Wfloat-equal + -Wnon-virtual-dtor -Wpointer-arith -Wformat-security -Wno-long-long -Wno-variadic-macros + -pedantic-errors) + + if(QT_FEATURE_reduce_relocations AND UNIX) + list(APPEND hcleanFLAGS -fPIC) + endif() + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + # these warnings are disabled because explicit constructors with zero or + # multiple arguments are permitted in C++11: + # 2304: non-explicit constructor with single argument may cause implicit type + # conversion + # 2305: declaration of 'explicit' constructor without a single argument is + # redundant + # + # ICC 14+ has a bug with -Wshadow, emitting it for cases where there's no + # shadowing (issue ID 0000698329, task DPD200245740) + list(APPEND hcleanFLAGS -wd2304,2305 -Wshadow) + else() + # options accepted by GCC and Clang + list(APPEND hcleanFLAGS -Wchar-subscripts -Wold-style-cast) + + if (NOT ((TEST_architecture_arch STREQUAL arm) + OR (TEST_architecture_arch STREQUAL mips))) + list(APPEND hcleanFLAGS -Wcast-align) + endif() + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + list(APPEND hcleanFLAGS -Wzero-as-null-pointer-constant) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.5) + list(APPEND hcleanFLAGS -Wdouble-promotion) + endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.9) + list(APPEND hcleanFLAGS -Wfloat-conversion) + + # GCC 9 has a lot of false positives relating to these + list(APPEND hcleanFlags -Wno-deprecated-copy -Wno-redundant-move + -Wno-format-overflow -Wno-init-list-lifetime) + endif() + endif() + endif() + + # Use strict mode C++17, with no GNU extensions (see -pedantic-errors above). + list(APPEND hcleanFLAGS -std=c++17) + + foreach(header ${hclean_headers}) + get_filename_component(input_path "${header}" ABSOLUTE) + set(artifact_path "header_${header}.o") + + add_custom_command( + OUTPUT "${artifact_path}" + COMMENT "headersclean: Checking header ${header}" + COMMAND "${CMAKE_CXX_COMPILER}" -c ${CMAKE_CXX_FLAGS} ${hcleanFLAGS} + -I "${QT_BUILD_DIR}/include" ${hcleanDEFS} -xc++ "${input_path}" + -o${artifact_path} + IMPLICIT_DEPENDS CXX + VERBATIM) + list(APPEND hclean_artifacts "${artifact_path}") + endforeach() + + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # 4180: qualifier applied to function type has no meaning; ignored + # 4458: declaration of 'identifier' hides class member + # 4577: 'noexcept' used with no exception handling mode specified; termination on + # exception is not guaranteed. Specify /EHsc + # + # -Za would enable strict standards behavior, but we can't add it because + # and violate the standards. + set(hcleanFLAGS -std:c++17 -WX -W3 -wd4180 -wd4458 -wd4577) + + # cl.exe needs a source path + get_filename_component(source_path "${QT_MKSPECS_DIR}/features/data/dummy.cpp" REALPATH) + + foreach(header ${hclean_headers}) + # We need realpath here to make sure path starts with drive letter + get_filename_component(input_path "${header}" REALPATH) + set(artifact_path "header_${header}.o") + + add_custom_command( + OUTPUT "${artifact_path}" + COMMENT "headersclean: Checking header ${header}" + COMMAND "${CMAKE_CXX_COMPILER}" -nologo -c ${CMAKE_CXX_FLAGS} ${hcleanFLAGS} + -I "${QT_BUILD_DIR}/include" ${hcleanDEFS} -FI "${input_path}" + -Fo${artifact_path} "${source_path}" + IMPLICIT_DEPENDS CXX + VERBATIM) + list(APPEND hclean_artifacts "${artifact_path}") + endforeach() + else() + message(ERROR "CMAKE_CXX_COMPILER_ID \"${CMAKE_CXX_COMPILER_ID}\" is not supported for the headersclean check.") + endif() + + add_custom_target(${module_include_name}_header_check + COMMENT "headersclean: Checking headers in ${module_include_name}" + DEPENDS ${hclean_artifacts} + VERBATIM) + + add_dependencies(${module_target} ${module_include_name}_header_check) +endfunction() diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake index 6a4f49dc76..b60c8a04ea 100644 --- a/cmake/QtModuleHelpers.cmake +++ b/cmake/QtModuleHelpers.cmake @@ -559,6 +559,13 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") endif() endif() + if(QT_FEATURE_headersclean AND NOT arg_NO_MODULE_HEADERS) + qt_internal_add_headers_clean_target( + ${target} + "${module_include_name}" + "${module_headers_clean}") + endif() + if(NOT ${arg_NO_PRIVATE_MODULE}) target_include_directories("${target_private}" INTERFACE ${interface_includes}) target_link_libraries("${target_private}" INTERFACE "${target}") diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h index ed3a4a002e..698285d12e 100644 --- a/src/gui/vulkan/qvulkaninstance.h +++ b/src/gui/vulkan/qvulkaninstance.h @@ -44,6 +44,7 @@ #if 0 #pragma qt_no_master_include +#pragma qt_sync_skip_header_check #endif #if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC) diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 8ce968d8af..4325b6317d 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -44,6 +44,7 @@ #if 0 #pragma qt_no_master_include +#pragma qt_sync_skip_header_check #endif #if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC) -- cgit v1.2.3