summaryrefslogtreecommitdiffstats
path: root/cmake/QtFlagHandlingHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtFlagHandlingHelpers.cmake')
-rw-r--r--cmake/QtFlagHandlingHelpers.cmake1000
1 files changed, 864 insertions, 136 deletions
diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake
index a71c083717..6a62b85c03 100644
--- a/cmake/QtFlagHandlingHelpers.cmake
+++ b/cmake/QtFlagHandlingHelpers.cmake
@@ -1,56 +1,162 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Sets '${var}' to a genex that extracts the target's property.
+# Sets 'have_${var}' to a genex that checks that the property has a
+# non-empty value.
+macro(qt_internal_genex_get_property var target property)
+ set(${var} "$<TARGET_PROPERTY:${target},${property}>")
+ set(have_${var} "$<BOOL:${${var}}>")
+endmacro()
+
+# Sets '${var}' to a genex that will join the given property values
+# using '${glue}' and will surround the entire output with '${prefix}'
+# and '${suffix}'.
+macro(qt_internal_genex_get_joined_property var target property prefix suffix glue)
+ qt_internal_genex_get_property("${var}" "${target}" "${property}")
+ set(${var}
+ "$<${have_${var}}:${prefix}$<JOIN:${${var}},${glue}>${suffix}>")
+endmacro()
+
+# This function generates LD version script for the target and uses it in the target linker line.
+# Function has two modes dependending on the specified arguments.
+# Arguments:
+# PRIVATE_CONTENT_FILE specifies the pre-cooked content of Qt_<version>_PRIVATE_API section.
+# Requires the content file available at build time.
function(qt_internal_add_linker_version_script target)
- qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN})
+ if(WASM)
+ return()
+ endif()
- if (TEST_ld_version_script)
- if (arg_INTERNAL)
- set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };")
- else()
- set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n")
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ ""
+ "PRIVATE_CONTENT_FILE"
+ "PRIVATE_HEADERS"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(arg_PRIVATE_CONTENT_FILE AND arg_PRIVATE_HEADERS)
+ message(FATAL_ERROR "Both PRIVATE_CONTENT_FILE and PRIVATE_HEADERS are specified.")
+ endif()
+
+ if(TEST_ld_version_script)
+ # Create a list of mangled symbol matches for all "std::" symbols. This
+ # list will catch most symbols, but will miss global-namespace symbols
+ # that only have std parameters.
+ # See https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name for reference
+ set(contents "NonQt {\nlocal:")
+
+ # For types: vtable, VTT, typeinfo, typeinfo name
+ foreach(ptrqualifier "" "P" "PK") # T, T *, const T * (volatile ignored)
+ string(APPEND contents "\n _ZT[VTIS]${ptrqualifier}S*;"
+ "_ZT[VTIS]${ptrqualifier}NS*;")
+ endforeach()
+
+ # For functions and variables
+ foreach(special ""
+ "G[VR]" # guard variables, extended-lifetime references
+ "GTt") # transaction entry points
+ foreach(cvqualifier "" "[VK]" "VK") # plain, const|volatile, const volatile
+ string(APPEND contents "\n ")
+ foreach(refqualifier "" "[RO]") # plain, & or &&
+ # For names in the std:: namespace, compression applies
+ # (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression)
+ string(APPEND contents
+ " _Z${special}${cvqualifier}${refqualifier}S*;" # plain
+ " _Z${special}N${cvqualifier}${refqualifier}S*;" # nested name
+ )
+ endforeach()
+ endforeach()
+ endforeach()
+
+ string(APPEND contents "\n};\nQt_${PROJECT_VERSION_MAJOR}")
+ if(QT_FEATURE_elf_private_full_version)
+ string(APPEND contents ".${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+ endif()
+ string(APPEND contents "_PRIVATE_API { qt_private_api_tag*;\n")
+ if(arg_PRIVATE_HEADERS)
foreach(ph ${arg_PRIVATE_HEADERS})
string(APPEND contents " @FILE:${ph}@\n")
endforeach()
- string(APPEND contents "};\n")
- set(current "Qt_${PROJECT_VERSION_MAJOR}")
- if (QT_NAMESPACE STREQUAL "")
- set(tag_symbol "qt_version_tag")
- else()
- set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
- endif()
- string(APPEND contents "${current} { *; };\n")
+ else()
+ string(APPEND contents "@PRIVATE_CONTENT@")
+ endif()
+ string(APPEND contents "};\n")
+ set(current "Qt_${PROJECT_VERSION_MAJOR}")
+ string(APPEND contents "${current} {\n *;")
- foreach(minor_version RANGE ${PROJECT_VERSION_MINOR})
- set(previous "${current}")
- set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}")
- if (minor_version EQUAL ${PROJECT_VERSION_MINOR})
- string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n")
- else()
- string(APPEND contents "${current} {} ${previous};\n")
- endif()
- endforeach()
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(genex_prefix "\n ")
+ set(genex_glue "$<SEMICOLON>\n ")
+ set(genex_suffix "$<SEMICOLON>")
+ qt_internal_genex_get_joined_property(
+ linker_exports "${target}" _qt_extra_linker_script_exports
+ "${genex_prefix}" "${genex_suffix}" "${genex_glue}"
+ )
+ string(APPEND contents "${linker_exports}")
+ endif()
+ string(APPEND contents "\n};\n")
- set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
- set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set(property_genex "$<TARGET_PROPERTY:${target},_qt_extra_linker_script_content>")
+ set(check_genex "$<BOOL:${property_genex}>")
+ string(APPEND contents
+ "$<${check_genex}:${property_genex}>")
+ endif()
- file(GENERATE OUTPUT "${infile}" CONTENT "${contents}")
+ set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
+ set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
- qt_ensure_perl()
+ file(GENERATE OUTPUT "${infile}" CONTENT "${contents}")
- add_custom_command(TARGET "${target}" PRE_LINK
- COMMAND "${HOST_PERL}" "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}"
- BYPRODUCTS "${outfile}" DEPENDS "${infile}"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT "Generating version linker script"
- )
- target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}")
+ if(NOT arg_PRIVATE_CONTENT_FILE)
+ set(arg_PRIVATE_CONTENT_FILE "")
endif()
+ set(generator_command ${CMAKE_COMMAND}
+ "-DIN_FILE=${infile}"
+ "-DPRIVATE_CONTENT_FILE=${arg_PRIVATE_CONTENT_FILE}"
+ "-DOUT_FILE=${outfile}"
+ -P "${QT_CMAKE_DIR}/QtGenerateVersionScript.cmake"
+ )
+ set(generator_dependencies
+ "${arg_PRIVATE_CONTENT_FILE}"
+ "${QT_CMAKE_DIR}/QtGenerateVersionScript.cmake"
+ )
+
+ add_custom_command(
+ OUTPUT "${outfile}"
+ COMMAND ${generator_command}
+ DEPENDS ${generator_dependencies}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMENT "Generating version linker script for target ${target}"
+ VERBATIM
+ )
+ add_custom_target(${target}_version_script DEPENDS ${outfile})
+ add_dependencies(${target} ${target}_version_script)
+ target_link_options(${target} PRIVATE "-Wl,--version-script,${outfile}")
endif()
endfunction()
function(qt_internal_add_link_flags_no_undefined target)
- if (NOT QT_BUILD_SHARED_LIBS)
+ if (NOT QT_BUILD_SHARED_LIBS OR WASM)
+ return()
+ endif()
+ if (VXWORKS)
+ # VxWorks requires thread_local-related symbols to be found at
+ # runtime, resulting in linker error when no-undefined flag is
+ # set and thread_local is used
return()
endif()
- if (GCC OR CLANG)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ # ld64 defaults to -undefined,error, and in Xcode 15
+ # passing this option is deprecated, causing a warning.
+ return()
+ endif()
+ if ((GCC OR CLANG) AND NOT MSVC)
+ if(CLANG AND QT_FEATURE_sanitizer)
+ return()
+ endif()
set(previous_CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-undefined,error")
@@ -84,12 +190,21 @@ endfunction()
function(qt_internal_apply_gc_binaries target visibility)
set(possible_visibilities PRIVATE INTERFACE PUBLIC)
- list(FIND possible_visibilities "${visibility}" known_visibility)
- if (known_visibility EQUAL "-1")
+ if(NOT visibility IN_LIST possible_visibilities)
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif()
- if ((GCC OR CLANG) AND NOT EMSCRIPTEN AND NOT UIKIT)
+ string(JOIN "" clang_or_gcc_begin
+ "$<$<OR:"
+ "$<CXX_COMPILER_ID:GNU>,"
+ "$<CXX_COMPILER_ID:Clang>,"
+ "$<CXX_COMPILER_ID:AppleClang>,"
+ "$<CXX_COMPILER_ID:IntelLLVM>"
+ ">:"
+ )
+ set(clang_or_gcc_end ">")
+
+ if ((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
if(APPLE)
set(gc_sections_flag "-Wl,-dead_strip")
elseif(SOLARIS)
@@ -97,16 +212,26 @@ function(qt_internal_apply_gc_binaries target visibility)
elseif(LINUX OR BSD OR WIN32 OR ANDROID)
set(gc_sections_flag "-Wl,--gc-sections")
endif()
+
+ # Save the flag value with and without genex wrapping, so we can remove the wrapping
+ # when generating .pc pkgconfig files.
+ set_property(GLOBAL PROPERTY _qt_internal_gc_sections_without_genex "${gc_sections_flag}")
+
+ set(gc_sections_flag
+ "${clang_or_gcc_begin}${gc_sections_flag}${clang_or_gcc_end}")
+
+ set_property(GLOBAL PROPERTY _qt_internal_gc_sections_with_genex "${gc_sections_flag}")
endif()
if(gc_sections_flag)
target_link_options("${target}" ${visibility} "${gc_sections_flag}")
endif()
- if((GCC OR CLANG OR ICC) AND NOT EMSCRIPTEN AND NOT UIKIT)
- set(split_sections_flags "-ffunction-sections" "-fdata-sections")
+ if((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
+ set(split_sections_flags
+ "${clang_or_gcc_begin}-ffunction-sections;-fdata-sections${clang_or_gcc_end}")
endif()
if(split_sections_flags)
- target_compile_options("${target}" ${visibility} ${split_sections_flags})
+ target_compile_options("${target}" ${visibility} "${split_sections_flags}")
endif()
endfunction()
@@ -116,13 +241,17 @@ function(qt_internal_apply_intel_cet target visibility)
endif()
set(possible_visibilities PRIVATE INTERFACE PUBLIC)
- list(FIND possible_visibilities "${visibility}" known_visibility)
- if (known_visibility EQUAL "-1")
+ if(NOT visibility IN_LIST possible_visibilities)
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif()
if(GCC)
- set(flags "-mshstk")
+ string(JOIN "" flags
+ "$<$<OR:"
+ "$<CXX_COMPILER_ID:GNU>,"
+ "$<CXX_COMPILER_ID:Clang>,"
+ "$<CXX_COMPILER_ID:AppleClang>"
+ ">:-mshstk>")
endif()
if(flags)
target_compile_options("${target}" ${visibility} "${flags}")
@@ -130,32 +259,56 @@ function(qt_internal_apply_intel_cet target visibility)
endfunction()
function(qt_internal_library_deprecation_level result)
- if(WIN32)
- # On Windows, due to the way DLLs work, we need to export all functions,
- # including the inlines
- list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x040800")
+ # QT_DISABLE_DEPRECATED_UP_TO controls which version we use as a cut-off
+ # compiling in to the library. E.g. if it is set to QT_VERSION then no
+ # code which was deprecated before QT_VERSION will be compiled in.
+ if (NOT DEFINED QT_DISABLE_DEPRECATED_UP_TO)
+ if(WIN32)
+ # On Windows, due to the way DLLs work, we need to export all functions,
+ # including the inlines
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=0x040800")
+ else()
+ # On other platforms, Qt's own compilation does need to compile the Qt 5.0 API
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=0x050000")
+ endif()
else()
- # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API
- list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000")
+ list(APPEND deprecations "QT_DISABLE_DEPRECATED_UP_TO=${QT_DISABLE_DEPRECATED_UP_TO}")
endif()
- list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000")
- set("${result}" deprecations PARENT_SCOPE)
+ # QT_WARN_DEPRECATED_UP_TO controls the upper-bound of deprecation
+ # warnings that are emitted. E.g. if it is set to 0x060500 then all use of
+ # things deprecated in or before 6.5.0 will be warned against.
+ list(APPEND deprecations "QT_WARN_DEPRECATED_UP_TO=0x070000")
+ set("${result}" "${deprecations}" PARENT_SCOPE)
endfunction()
-# Sets the exceptions flags for the given target
-function(qt_internal_set_no_exceptions_flags target)
- target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS")
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
- target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
- elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
- target_compile_options("${target}" PRIVATE "-fno-exceptions")
+# Sets the exceptions flags for the given target according to exceptions_on
+function(qt_internal_set_exceptions_flags target exceptions_on)
+ set(_defs "")
+ set(_flag "")
+ if(exceptions_on)
+ if(MSVC)
+ set(_flag "/EHsc")
+ if((MSVC_VERSION GREATER_EQUAL 1929) AND NOT CLANG)
+ # Use the undocumented compiler flag to make our binary smaller on x64.
+ # https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/
+ # NOTE: It seems we'll use this new exception handling model unconditionally without
+ # this hack since some unknown MSVC version.
+ set(_flag ${_flag} "/d2FH4")
+ endif()
+ else()
+ set(_flag "-fexceptions")
+ endif()
+ else()
+ set(_defs "QT_NO_EXCEPTIONS")
+ if(MSVC)
+ set(_flag "/EHs-c-" "/wd4530" "/wd4577")
+ else()
+ set(_flag "-fno-exceptions")
+ endif()
endif()
+
+ target_compile_definitions("${target}" PRIVATE ${_defs})
+ target_compile_options("${target}" PRIVATE ${_flag})
endfunction()
function(qt_skip_warnings_are_errors target)
@@ -198,17 +351,17 @@ endfunction()
function(qt_set_language_standards)
## Use the latest standard the compiler supports (same as qt_common.prf)
- if (QT_FEATURE_cxx2a)
+ if (QT_FEATURE_cxx2b)
+ set(CMAKE_CXX_STANDARD 23 PARENT_SCOPE)
+ elseif (QT_FEATURE_cxx20)
set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE)
else()
set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE)
endif()
+ set(CMAKE_CXX_STANDARD_REQUIRED ON PARENT_SCOPE)
- if (c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES)
- set(CMAKE_C_STANDARD 11 PARENT_SCOPE)
- elseif (c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES)
- set(CMAKE_C_STANDARD 99 PARENT_SCOPE)
- endif()
+ set(CMAKE_C_STANDARD 11 PARENT_SCOPE)
+ set(CMAKE_C_STANDARD_REQUIRED ON PARENT_SCOPE)
endfunction()
function(qt_set_language_standards_interface_compile_features target)
@@ -218,30 +371,46 @@ function(qt_set_language_standards_interface_compile_features target)
target_compile_features("${target}" INTERFACE ${cpp_feature})
endfunction()
-function(qt_enable_msvc_cplusplus_define target visibility)
+function(qt_set_msvc_cplusplus_options target visibility)
# For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus.
# Check qt_config_compile_test for more info.
- if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1913)
- target_compile_options("${target}" ${visibility} "-Zc:__cplusplus")
+ if(MSVC AND MSVC_VERSION GREATER_EQUAL 1913)
+ set(flags "-Zc:__cplusplus" "-permissive-")
+ target_compile_options("${target}" ${visibility}
+ "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<COMPILE_LANGUAGE:CXX>>:${flags}>")
endif()
endfunction()
function(qt_enable_utf8_sources target)
set(utf8_flags "")
if(MSVC)
- list(APPEND utf8_flags "-utf-8")
- elseif(WIN32 AND ICC)
- list(APPEND utf8_flags "-Qoption,cpp,--unicode_source_kind,UTF-8")
+ list(APPEND utf8_flags "$<$<CXX_COMPILER_ID:MSVC>:-utf-8>")
endif()
if(utf8_flags)
# Allow opting out by specifying the QT_NO_UTF8_SOURCE target property.
- set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>")
+ set(opt_out_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>")
+ # Only set the compiler option for C and C++.
+ set(language_condition "$<COMPILE_LANGUAGE:C,CXX>")
+ # Compose the full condition.
+ set(genex_condition "$<AND:${opt_out_condition},${language_condition}>")
set(utf8_flags "$<${genex_condition}:${utf8_flags}>")
target_compile_options("${target}" INTERFACE "${utf8_flags}")
endif()
endfunction()
+function(qt_internal_enable_unicode_defines)
+ if(WIN32)
+ set(no_unicode_condition
+ "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UNICODE_DEFINES>>>")
+ target_compile_definitions(Platform
+ INTERFACE "$<${no_unicode_condition}:UNICODE$<SEMICOLON>_UNICODE>")
+ endif()
+endfunction()
+
+# Saves the list of known optimization flags for the current compiler in out_var.
+#
+# Mostly used for removing them before adding new ones.
function(qt_internal_get_all_possible_optimization_flag_values out_var)
set(flag_values "")
set(vars QT_CFLAGS_OPTIMIZE QT_CFLAGS_OPTIMIZE_FULL
@@ -262,7 +431,35 @@ function(qt_internal_get_all_possible_optimization_flag_values out_var)
set("${out_var}" "${flag_values}" PARENT_SCOPE)
endfunction()
-function(qt_internal_print_optimization_flags_values languages configs target_link_types)
+# Return's the current compiler's optimize_full flags if available.
+# Otherwise returns the regular optimization level flag.
+function(qt_internal_get_optimize_full_flags out_var)
+ set(optimize_full_flags "${QT_CFLAGS_OPTIMIZE_FULL}")
+ if(NOT optimize_full_flags)
+ set(optimize_full_flags "${QT_CFLAGS_OPTIMIZE}")
+ endif()
+ set(${out_var} "${optimize_full_flags}" PARENT_SCOPE)
+endfunction()
+
+# Prints the compiler and linker flags for each configuration, language and target type.
+#
+# Usually it would print the cache variables, but one may also override the variables
+# in a specific directory scope, so this is useful for debugging.
+#
+# Basically dumps either scoped or cached
+# CMAKE_<LANG>_FLAGS_CONFIG> and CMAKE_<TYPE>_LINKER_FLAGS_<CONFIG> variables.
+
+function(qt_internal_print_optimization_flags_values)
+ qt_internal_get_enabled_languages_for_flag_manipulation(languages)
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
+
+ qt_internal_print_optimization_flags_values_helper(
+ "${languages}" "${configs}" "${target_link_types}")
+endfunction()
+
+# Helper function for printing the optimization flags.
+function(qt_internal_print_optimization_flags_values_helper languages configs target_link_types)
foreach(lang ${languages})
set(flag_var_name "CMAKE_${lang}_FLAGS")
message(STATUS "${flag_var_name}: ${${flag_var_name}}")
@@ -284,20 +481,29 @@ function(qt_internal_print_optimization_flags_values languages configs target_li
endforeach()
endfunction()
-# This function finds the optimization flags set by the default CMake modules or toolchains, and
-# replaces them with ones that Qt qmake builds expect for all the default CMAKE_BUILD_TYPE
-# configurations.
-# This normalizes things like using -O2 for both Release and RelWithDebInfo, among other flags.
-# See QTBUG-85992 for details.
-function(qt_internal_set_up_config_optimizations_like_in_qmake)
- # Allow opt out.
- if(QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
- return()
+# Saves the list of configs for which flag manipulation will occur.
+function(qt_internal_get_configs_for_flag_manipulation out_var)
+ set(configs RELEASE RELWITHDEBINFO MINSIZEREL DEBUG)
+
+ # Opt into additional non-standard configs for flag removal only.
+ if(QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS)
+ list(APPEND configs ${QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS})
endif()
+ set(${out_var} "${configs}" PARENT_SCOPE)
+endfunction()
+
+# Saves the list of target link types for which flag manipulation will occur.
+function(qt_internal_get_target_link_types_for_flag_manipulation out_var)
+ set(target_link_types EXE SHARED MODULE STATIC)
+ set(${out_var} "${target_link_types}" PARENT_SCOPE)
+endfunction()
+
+# Saves list of enabled languages for which it is safe to manipulate compilation flags.
+function(qt_internal_get_enabled_languages_for_flag_manipulation out_var)
# Limit flag modification to c-like code. We don't want to accidentally add incompatible
# flags to MSVC's RC or Swift.
- set(languages_to_process C CXX OBJC OBJCXX)
+ set(languages_to_process ASM C CXX OBJC OBJCXX)
get_property(globally_enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
set(enabled_languages "")
foreach(lang ${languages_to_process})
@@ -305,70 +511,549 @@ function(qt_internal_set_up_config_optimizations_like_in_qmake)
list(APPEND enabled_languages "${lang}")
endif()
endforeach()
+ set(${out_var} "${enabled_languages}" PARENT_SCOPE)
+endfunction()
- set(configs RELEASE RELWITHDEBINFO MINSIZEREL DEBUG)
- set(target_link_types EXE SHARED MODULE STATIC)
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_replace_flags_impl flag_var_name match_string replace_string IN_CACHE)
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable, but
+ # we need to use the original value on entry to this function.
- # Opt into additional non-standard configs for flag removal only.
- if(QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS)
- list(APPEND configs ${QT_ADDITIONAL_OPTIMIZATION_FLAG_CONFIGS})
+ # Handle an empty input string and an empty match string as a set().
+ if(match_string STREQUAL "" AND "${${flag_var_name}}" STREQUAL "")
+ set(${flag_var_name} "${replace_string}" PARENT_SCOPE)
+ else()
+ string(REPLACE
+ "${match_string}" "${replace_string}"
+ ${flag_var_name} "${${flag_var_name}}")
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
endif()
- # You can set QT_DEBUG_OPTIMIZATION_FLAGS to see the before and after results.
- if(QT_DEBUG_OPTIMIZATION_FLAGS)
- message(STATUS "")
- message(STATUS "DEBUG: Original CMake optimization flags.\n")
- qt_internal_print_optimization_flags_values("${enabled_languages}" "${configs}"
- "${target_link_types}")
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ get_property(help_text CACHE "${flag_var_name}" PROPERTY HELPSTRING)
+
+ # Handle an empty input string and an empty match string as a set().
+ if(match_string STREQUAL "" AND "$CACHE{${flag_var_name}}" STREQUAL "")
+ set(${flag_var_name} "${replace_string}" CACHE STRING "${help_text}" FORCE)
+ else()
+ set(mod_flags "$CACHE{${flag_var_name}}")
+ string(REPLACE
+ "${match_string}" "${replace_string}"
+ mod_flags "${mod_flags}")
+ string(STRIP "${mod_flags}" mod_flags)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+ endif()
+endfunction()
+
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_remove_flags_impl flag_var_name flag_values IN_CACHE)
+ cmake_parse_arguments(arg "REGEX" "" "" ${ARGN})
+ set(replace_type REPLACE)
+ if(arg_REGEX)
+ list(PREPEND replace_type REGEX)
+ endif()
+
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable in this
+ # function scope, but we need to use the original value before that change.
+ foreach(flag_value IN LISTS flag_values)
+ string(${replace_type} "${flag_value}" " " ${flag_var_name} "${${flag_var_name}}")
+ endforeach()
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ set(mod_flags $CACHE{${flag_var_name}})
+ foreach(flag_value IN LISTS flag_values)
+ string(${replace_type} "${flag_value}" " " mod_flags "${mod_flags}")
+ endforeach()
+ string(STRIP "${mod_flags}" mod_flags)
+ get_property(help_text CACHE ${flag_var_name} PROPERTY HELPSTRING)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+endfunction()
+
+# Helper function used to update compiler and linker flags further below
+function(qt_internal_add_flags_impl flag_var_name flags IN_CACHE)
+ # This must come before cache variable modification because setting the
+ # cache variable with FORCE will overwrite the non-cache variable, but
+ # we need to use the original value on entry to this function.
+ set(${flag_var_name} "${${flag_var_name}} ${flags}")
+ string(STRIP "${${flag_var_name}}" ${flag_var_name})
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
+ if(IN_CACHE)
+ # We must not use the non-cache variable's value because toolchain files
+ # might be appending things to the cache variable's value and storing it
+ # in a non-cache variable (e.g. Android NDK toolchain file does this).
+ # Work exclusively on cache variable value only.
+ set(mod_flags "$CACHE{${flag_var_name}} ${flags}")
+ string(STRIP "${mod_flags}" mod_flags)
+ get_property(help_text CACHE ${flag_var_name} PROPERTY HELPSTRING)
+ set(${flag_var_name} "${mod_flags}" CACHE STRING "${help_text}" FORCE)
+ endif()
+endfunction()
+
+
+# Removes all known compiler optimization flags for the given CONFIGS, for all enabled 'safe'
+# languages. The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# IN_CACHE - remove them from the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to remove the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_remove_known_optimization_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to remove the flags.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
endif()
- # Remove known optimization flags.
qt_internal_get_all_possible_optimization_flag_values(flag_values)
+ set(configs ${arg_CONFIGS})
+
foreach(lang ${enabled_languages})
foreach(config ${configs})
set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
- foreach(flag_value ${flag_values})
- # Remove any existing optimization flags, they will be re-added later on.
- string(REPLACE "${flag_value}" "" "${flag_var_name}" "${${flag_var_name}}")
- string(STRIP "${${flag_var_name}}" "${flag_var_name}")
- endforeach()
+ qt_internal_remove_flags_impl(${flag_var_name} "${flag_values}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Removes specified flags from CMAKE_<LANGUAGES>_FLAGS[_CONFIGS] variables
+#
+# Option Arguments:
+# IN_CACHE
+# Enables flags removal from CACHE
+# REGEX
+# Enables the flag processing as a regular expression.
+#
+# Multi-value Arguments:
+# CONFIGS
+# List of configurations that need to clear flags. Clears all configs by default if not
+# specified.
+#
+# LANGUAGES
+# List of LANGUAGES that need clear flags. Clears all languages by default if not
+# specified.
+function(qt_internal_remove_compiler_flags flags)
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "IN_CACHE;REGEX"
+ ""
+ "CONFIGS;LANGUAGES"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if("${flags}" STREQUAL "")
+ message(WARNING "qt_internal_remove_compiler_flags was called without any flags specified.")
+ return()
+ endif()
+
+ if(arg_LANGUAGES)
+ set(languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(languages)
+ endif()
+
+ if(arg_CONFIGS)
+ set(configs "${arg_CONFIGS}")
+ else()
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ endif()
+
+ if(arg_REGEX)
+ list(APPEND extra_options "REGEX")
+ endif()
+
+ foreach(lang ${languages})
+ set(flag_var_name "CMAKE_${lang}_FLAGS")
+ qt_internal_remove_flags_impl(${flag_var_name}
+ "${flags}"
+ "${arg_IN_CACHE}"
+ ${extra_options}
+ )
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_remove_flags_impl(${flag_var_name}
+ "${flags}"
+ "${arg_IN_CACHE}"
+ ${extra_options}
+ )
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Adds compiler flags for the given CONFIGS in the calling scope. Can also update the cache
+# if asked to do so. The flag variables are always updated in the calling scope, even if they
+# did not exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to add the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_add_compiler_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to add the flags.")
+ endif()
+ if(NOT arg_FLAGS)
+ message(FATAL_ERROR "You must specify at least one flag to add.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+
+ set(configs ${arg_CONFIGS})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_add_flags_impl(${flag_var_name} "${arg_FLAGS}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function that adds compiler flags for all release configurations.
+# The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to add the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_add_compiler_flags_for_release_configs)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(args "")
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+
+ set(configs RELEASE RELWITHDEBINFO MINSIZEREL)
+
+ list(APPEND args CONFIGS ${configs})
+
+ if(arg_FLAGS)
+ list(APPEND args FLAGS "${arg_FLAGS}")
+ endif()
+
+ if(arg_IN_CACHE)
+ list(APPEND args IN_CACHE)
+ endif()
+ list(APPEND args LANGUAGES ${enabled_languages})
+
+ qt_internal_add_compiler_flags(${args})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set("${flag_var_name}" "${${flag_var_name}}" PARENT_SCOPE)
endforeach()
endforeach()
+endfunction()
+
+# Convenience function that replaces all optimization flags with the equivalent of '-O3'
+# (optimize_full) flag for all release configs.
+#
+# This is the equivalent of qmake's CONFIG += optimize_full.
+# It is meant to be called in a subdirectory scope to enable full optimizations for a particular
+# Qt module, like Core or Gui.
+function(qt_internal_add_optimize_full_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ ""
+ "")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ # QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS disables forced full optimization.
+ if(QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
+ return()
+ endif()
+
+ # Assume that FEATURE_optimize_full has higher priority. But if FEATURE_optimize_full is OFF,
+ # flags are set by FEATURE_optimize_size should remain unchanged.
+ if(QT_FEATURE_optimize_size AND NOT QT_FEATURE_optimize_full)
+ return()
+ endif()
+
+ set(args "")
+ if(arg_IN_CACHE)
+ list(APPEND args IN_CACHE)
+ endif()
+
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ set(configs RELEASE RELWITHDEBINFO)
+ if(QT_FEATURE_optimize_full) # Assume that FEATURE_optimize_full has higher priority.
+ list(APPEND configs MINSIZEREL)
+ endif()
+
+ qt_internal_remove_known_optimization_flags(${args} CONFIGS ${configs})
+
+ # If the respective compiler doesn't have optimize_full flags, use regular optimization flags.
+ # Mainly MSVC.
+ qt_internal_get_optimize_full_flags(optimize_full_flags)
+ list(APPEND args FLAGS "${optimize_full_flags}")
+
+ qt_internal_add_compiler_flags_for_release_configs(${args})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set("${flag_var_name}" "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to replace a compiler flag with another one, for the given configurations
+# for all enabled 'safe' languages.
+# Essentially a glorified string(REPLACE).
+# Can be used to remove compiler flags.
+# The flag variables are always updated in the calling scope, even if they did not
+# exist beforehand.
+#
+# match_string - string to match
+# replace_string - replacement string
+# IN_CACHE - replace them in the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# LANGUAGES - optional list of languages like 'C', 'CXX', for which to replace the flags
+# if not provided, defaults to the list of enabled C-like languages
+function(qt_internal_replace_compiler_flags match_string replace_string)
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;LANGUAGES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to replace the flags.")
+ endif()
+
+ if(arg_LANGUAGES)
+ set(enabled_languages "${arg_LANGUAGES}")
+ else()
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ endif()
+ set(configs ${arg_CONFIGS})
+
+ foreach(lang ${enabled_languages})
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ qt_internal_replace_flags_impl(${flag_var_name}
+ "${match_string}" "${replace_string}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to add linker flags, for the given configurations and target link types.
+# The flag variables are always updated in the calling scope, even if they did not exist beforehand.
+#
+# FLAGS - should be a single string of flags separated by spaces.
+# IN_CACHE - add them to the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# TYPES - should be a list of target link types as expected by CMake's
+# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
+# e.g EXE, MODULE, SHARED, STATIC.
+function(qt_internal_add_linker_flags)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "IN_CACHE"
+ "FLAGS"
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_TYPES)
+ message(FATAL_ERROR
+ "You must specify at least one linker target type for which to add the flags.")
+ endif()
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to add the flags.")
+ endif()
+ if(NOT arg_FLAGS)
+ message(FATAL_ERROR "You must specify at least one flag to add.")
+ endif()
+
+ set(configs ${arg_CONFIGS})
+ set(target_link_types ${arg_TYPES})
+
+ foreach(config ${configs})
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ qt_internal_add_flags_impl(${flag_var_name} "${arg_FLAGS}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# Convenience function to replace a linker flag with another one, for the given configurations
+# and target link types.
+# Essentially a glorified string(REPLACE).
+# Can be used to remove linker flags.
+# The flag variables are always updated in the calling scope, even if they did not exist beforehand.
+#
+# match_string - string to match
+# replace_string - replacement string
+# IN_CACHE - replace them in the corresponding cache variable too. Note that the cache
+# variable may have a different value to the non-cache variable.
+# CONFIGS - should be a list of upper case configs like DEBUG, RELEASE, RELWITHDEBINFO.
+# TYPES - should be a list of target link types as expected by CMake's
+# CMAKE_<LINKER_TYPE>_LINKER_FLAGS_<CONFIG> cache variable.
+# e.g EXE, MODULE, SHARED, STATIC.
+function(qt_internal_replace_linker_flags match_string replace_string)
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "IN_CACHE"
+ ""
+ "CONFIGS;TYPES")
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ if(NOT arg_TYPES)
+ message(FATAL_ERROR
+ "You must specify at least one linker target type for which to replace the flags.")
+ endif()
+ if(NOT arg_CONFIGS)
+ message(FATAL_ERROR
+ "You must specify at least one configuration for which to replace the flags.")
+ endif()
+
+ set(configs ${arg_CONFIGS})
+ set(target_link_types ${arg_TYPES})
+
+ foreach(config ${configs})
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ qt_internal_replace_flags_impl(${flag_var_name}
+ "${match_string}" "${replace_string}" "${arg_IN_CACHE}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
+endfunction()
+
+# This function finds the optimization flags set by the default CMake platform modules or toolchain
+# files and replaces them with flags that Qt qmake builds expect, for all the usual
+# CMAKE_BUILD_TYPE configurations.
+# This normalizes things like using -O2 for both Release and RelWithDebInfo, among other compilation
+# flags. Also some linker flags specific to MSVC.
+# See QTBUG-85992 for details.
+#
+# Note that both the calling scope and the CMake cache are updated.
+function(qt_internal_set_up_config_optimizations_like_in_qmake)
+ # Allow opt out.
+ if(QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
+ return()
+ endif()
+
+ qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
+
+ # You can set QT_DEBUG_OPTIMIZATION_FLAGS to see the before and after results.
+ if(QT_DEBUG_OPTIMIZATION_FLAGS)
+ message(STATUS "")
+ message(STATUS "DEBUG: Original CMake optimization flags.\n")
+ qt_internal_print_optimization_flags_values_helper("${enabled_languages}" "${configs}"
+ "${target_link_types}")
+ endif()
+
+ # Remove known optimization flags.
+ qt_internal_remove_known_optimization_flags(IN_CACHE CONFIGS ${configs})
# Re-add optimization flags as per qmake mkspecs.
foreach(lang ${enabled_languages})
foreach(config ${configs})
set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set(value_to_append "")
# Release and RelWithDebInfo should get the same base optimization flags.
if(config STREQUAL "RELEASE" AND QT_CFLAGS_OPTIMIZE)
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
elseif(config STREQUAL "RELWITHDEBINFO" AND QT_CFLAGS_OPTIMIZE)
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
# MinSizeRel should get the optimize size flag if available, otherwise the regular
# release flag.
elseif(config STREQUAL "MINSIZEREL")
if(QT_CFLAGS_OPTIMIZE_SIZE)
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE_SIZE}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_SIZE}")
else()
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE}")
endif()
endif()
# Debug should get the OPTIMIZE_DEBUG flag if the respective feature is ON.
if(config STREQUAL "DEBUG" AND QT_FEATURE_optimize_debug)
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE_DEBUG}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_DEBUG}")
endif()
set(configs_for_optimize_size RELEASE RELWITHDEBINFO)
if(QT_FEATURE_optimize_size AND config IN_LIST configs_for_optimize_size)
- string(APPEND "${flag_var_name}" " ${QT_CFLAGS_OPTIMIZE_SIZE}")
+ set(value_to_append "${QT_CFLAGS_OPTIMIZE_SIZE}")
+ endif()
+
+ # Check if the fake 'optimize_full' feature is enabled.
+ # Use the max optimization level flag for all release configs, effectively
+ # overriding any previous setting.
+ set(configs_for_optimize RELEASE RELWITHDEBINFO MINSIZEREL)
+ if(QT_FEATURE_optimize_full AND config IN_LIST configs_for_optimize)
+ qt_internal_get_optimize_full_flags(optimize_full_flags)
+ set(value_to_append "${optimize_full_flags}")
endif()
# Assign value to the cache entry.
- get_property(help_text CACHE "${flag_var_name}" PROPERTY HELPSTRING)
- set("${flag_var_name}" "${${flag_var_name}}" CACHE STRING "${help_text}" FORCE)
+ if(value_to_append)
+ qt_internal_add_flags_impl(${flag_var_name} "${value_to_append}" TRUE)
+ # Delay updating the calling scope's variables to the end of this function
+ endif()
+
endforeach()
endforeach()
@@ -376,36 +1061,79 @@ function(qt_internal_set_up_config_optimizations_like_in_qmake)
# Handle MSVC /INCREMENTAL flag which should not be enabled for Release configurations.
# First remove them from all configs, and re-add INCREMENTAL for Debug only.
set(flag_values "/INCREMENTAL:YES" "/INCREMENTAL:NO" "/INCREMENTAL")
- foreach(config ${configs})
- foreach(t ${target_link_types})
- set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
- foreach(flag_value ${flag_values})
- string(REPLACE "${flag_value}" "" "${flag_var_name}" "${${flag_var_name}}")
- string(STRIP "${${flag_var_name}}" "${flag_var_name}")
- endforeach()
- endforeach()
+ foreach(flag_value ${flag_values})
+ qt_internal_replace_linker_flags(
+ "${flag_value}" ""
+ CONFIGS ${configs}
+ TYPES ${target_link_types}
+ IN_CACHE)
endforeach()
+ set(flag_value "/INCREMENTAL:NO")
+ qt_internal_add_linker_flags(
+ FLAGS "${flag_value}"
+ CONFIGS RELEASE RELWITHDEBINFO MINSIZEREL
+ TYPES EXE SHARED MODULE # when linking static libraries, link.exe can't recognize this parameter, clang-cl will error out.
+ IN_CACHE)
+ qt_internal_remove_compiler_flags("(^| )/EH[scra-]*( |$)" LANGUAGES CXX CONFIGS ${configs} IN_CACHE REGEX)
+ endif()
+
+ # Allow opting into generating debug info in object files with a fake feature.
+ # This would allow us to enable caching with sccache.
+ # See QTQAINFRA-3934 for details.
+ if(MSVC AND QT_FEATURE_msvc_obj_debug_info)
+ qt_internal_replace_compiler_flags(
+ "/Zi" "/Z7"
+ CONFIGS RELWITHDEBINFO DEBUG
+ TYPES ${target_link_types}
+ IN_CACHE)
+ endif()
+
+ # Legacy Android toolchain file adds the `-g` flag to CMAKE_<LANG>_FLAGS, as a
+ # result, our release build ends up containing debug symbols. To avoid that, we
+ # remove the flag from CMAKE_<LANGL>_FLAGS and add
+ # it to CMAKE_<LANG>_FLAGS_DEBUG.
+ #
+ # Note:
+ # The new `android.toolchain.cmake` file does not have this problem, but
+ # it has other issues, eg., https://github.com/android/ndk/issues/1693, so we
+ # cannot force it. While we do load the new toolchain, it automatically falls
+ # back to the legacy toolchain, ie., `android-legacy.toolchain.cmake` which
+ # has the problem described above.
+ #
+ # Todo:
+ # When the new toolchain is fixed, and it doesn't fall back to the legacy
+ # anymore by default, then we should be able to remove this workaround.
+ if(ANDROID AND ANDROID_COMPILER_FLAGS MATCHES "(^| )-g")
+ qt_internal_remove_compiler_flags("-g")
+ qt_internal_add_compiler_flags(FLAGS "-g" CONFIGS DEBUG RELWITHDEBINFO)
+ endif()
+
+ # Update all relevant flags in the calling scope
+ foreach(lang ${enabled_languages})
+ set(flag_var_name "CMAKE_${lang}_FLAGS")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+
foreach(config ${configs})
- foreach(t ${target_link_types})
- set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
+ endforeach()
+ endforeach()
- if(config STREQUAL "RELEASE" OR config STREQUAL "RELWITHDEBINFO"
- OR config STREQUAL "MINSIZEREL")
- string(APPEND "${flag_var_name}" " /INCREMENTAL:NO")
- endif()
+ foreach(t ${target_link_types})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
- # Assign value to the cache entry.
- get_property(help_text CACHE "${flag_var_name}" PROPERTY HELPSTRING)
- set("${flag_var_name}" "${${flag_var_name}}" CACHE STRING "${help_text}" FORCE)
- endforeach()
+ foreach(config ${configs})
+ set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
+ set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
endforeach()
- endif()
+ endforeach()
if(QT_DEBUG_OPTIMIZATION_FLAGS)
message(STATUS "")
message(STATUS "DEBUG: Modified optimization flags to mirror qmake mkspecs.\n")
- qt_internal_print_optimization_flags_values("${enabled_languages}" "${configs}"
- "${target_link_types}")
+ qt_internal_print_optimization_flags_values_helper("${enabled_languages}" "${configs}"
+ "${target_link_types}")
endif()
endfunction()