diff options
Diffstat (limited to 'cmake/Functions.cmake')
-rw-r--r-- | cmake/Functions.cmake | 1407 |
1 files changed, 1407 insertions, 0 deletions
diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake new file mode 100644 index 000000000..6cc8a401e --- /dev/null +++ b/cmake/Functions.cmake @@ -0,0 +1,1407 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +function(assertTargets) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "" "MODULES;TARGETS" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + foreach(module ${arg_MODULES}) + if(NOT DEFINED ${module}_SUPPORT) + set(${module}_SUPPORT ON PARENT_SCOPE) + set(${module}_SUPPORT ON) + endif() + if(${module}_SUPPORT) + foreach(qtTarget ${arg_TARGETS}) + if(NOT TARGET Qt::${qtTarget}) + set(${module}_ERROR "Missing required Qt::${qtTarget}." PARENT_SCOPE) + set(${module}_SUPPORT OFF PARENT_SCOPE) + break() + endif() + endforeach() + endif() + endforeach() +endfunction() + +# TODO: this should be idealy in qtbase +function(add_check_for_support) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "" "MODULES;MESSAGE;CONDITION" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + foreach(module ${arg_MODULES}) + if(NOT DEFINED ${module}_SUPPORT) + set(${module}_SUPPORT ON PARENT_SCOPE) + set(${module}_SUPPORT ON) + endif() + if(${module}_SUPPORT) + if("x${arg_CONDITION}" STREQUAL "x") + set(arg_CONDITION ON) + endif() + qt_evaluate_config_expression(result ${arg_CONDITION}) + if(NOT ${result}) + set(${module}_SUPPORT OFF PARENT_SCOPE) + set(${module}_ERROR ${arg_MESSAGE} PARENT_SCOPE) + qt_configure_add_report_entry(TYPE WARNING + MESSAGE "${module} won't be built. ${arg_MESSAGE}" + CONDITION ON + ) + endif() + endif() + endforeach() +endfunction() + +function(create_cxx_config cmakeTarget arch configFileName) + if(NOT QT_SUPERBUILD AND QT_WILL_INSTALL) + get_target_property(mocFilePath Qt6::moc IMPORTED_LOCATION) + else() + if(CMAKE_CROSSCOMPILING) + set(mocFilePath "${QT_HOST_PATH}/${INSTALL_LIBEXECDIR}/moc${CMAKE_EXECUTABLE_SUFFIX}") + else() + set(mocFilePath "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/moc${CMAKE_EXECUTABLE_SUFFIX}") + endif() + endif() + file(GENERATE + OUTPUT $<CONFIG>/${arch}/${configFileName} + CONTENT "\ + set(GN_INCLUDES \"$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>\")\n\ + set(GN_DEFINES \"$<TARGET_PROPERTY:COMPILE_DEFINITIONS>\")\n\ + set(GN_LINK_OPTIONS \"$<TARGET_PROPERTY:LINK_OPTIONS>\")\n\ + set(GN_CXX_COMPILE_OPTIONS \"$<TARGET_PROPERTY:COMPILE_OPTIONS>\")\n\ + set(GN_MOC_PATH \"${mocFilePath}\")" +# set(GN_LIBS $<TARGET_PROPERTY:LINK_LIBRARIES>) + CONDITION $<COMPILE_LANGUAGE:CXX> + TARGET ${cmakeTarget} + ) +endfunction() + +function(create_static_config cmakeTarget arch configFileName) + list(APPEND libs Png Jpeg Harfbuzz Freetype Zlib) + foreach(lib IN LISTS libs) + string(TOUPPER ${lib} out) + set(lib Qt::${lib}Private) + list(APPEND contents "set(GN_${out}_INCLUDES \"$<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${lib}>,${lib}>:$<TARGET_PROPERTY:${lib},INTERFACE_INCLUDE_DIRECTORIES>>\")") + endforeach() + list(JOIN contents "\n" contents) + file(GENERATE + OUTPUT $<CONFIG>/${arch}/${configFileName} + CONTENT "${contents}" + ) +endfunction() + +function(create_c_config cmakeTarget arch configFileName) + file(GENERATE + OUTPUT $<CONFIG>/${arch}/${configFileName} + CONTENT "set(GN_C_COMPILE_OPTIONS $<TARGET_PROPERTY:COMPILE_OPTIONS>)" + CONDITION $<COMPILE_LANGUAGE:C> + TARGET ${cmakeTarget}) +endfunction() + +function(create_gn_target_config target configFile) + get_target_property(elementList ${target} ELEMENTS) + get_target_property(prefix ${target} PREFIX) + file(WRITE ${configFile} + "set(PREFIX ${prefix})\nset(ELEMENTS ${elementList})\n" + ) + foreach(element IN LISTS elementList) + get_target_property(prop ${target} ${prefix}_${element}) + if(prop) + file(APPEND ${configFile} "set(${prefix}_${element} ${prop})\n") + endif() + endforeach() +endfunction() + +function(add_gn_target target config arch) + add_custom_target(${target}) + list(REMOVE_ITEM ARGN ${target}) + list(REMOVE_ITEM ARGN ${config}) + list(REMOVE_ITEM ARGN ${arch}) + set_target_properties(${target} PROPERTIES + ELEMENTS "${ARGN}" + PREFIX "GN" + CONFIG ${config} + ARCH ${arch} + ) +endfunction() + +function(init_gn_config filePath) + include(${filePath}) + set_directory_properties(PROPERTIES + ELEMENTS "${ELEMENTS}" + PREFIX "${PREFIX}" + ) + applyToGnTarget(DIRECTORY) +endfunction() + +function(read_gn_config filePath) + include(${filePath}) + applyToGnTarget(DIRECTORY) +endfunction() + +# this runs also in script mode, so we use than DIRECTORY +macro(applyToGnTarget) + set(type ${ARGV0}) + set(target ${ARGV1}) + get_property(elementList ${type} ${target} PROPERTY ELEMENTS) + get_property(prefix ${type} ${target} PROPERTY PREFIX) + foreach(element IN LISTS elementList) + if(${prefix}_${element}) + message(DEBUG "${prefix}_${element} = ${${prefix}_${element}}") + set_property(${type} ${target} APPEND PROPERTY ${prefix}_${element} ${${prefix}_${element}}) + endif() + endforeach() +endmacro() + +function(extend_gn_target target) + get_target_property(elements ${target} ELEMENTS) + cmake_parse_arguments(PARSE_ARGV 1 GN "" "" "CONDITION;${elements}") + _qt_internal_validate_all_args_are_parsed(GN) + + if("x${GN_CONDITION}" STREQUAL "x") + set(GN_CONDITION ON) + endif() + qt_evaluate_config_expression(result ${GN_CONDITION}) + if(${result}) + message(DEBUG "extend_gn_target(${target} CONDITION ${GN_CONDITION} ...): Evaluated") + applyToGnTarget(TARGET ${target}) + endif() +endfunction() + +function(extend_gn_list outList) + cmake_parse_arguments(PARSE_ARGV 1 GN "" "" "ARGS;CONDITION") + _qt_internal_validate_all_args_are_parsed(GN) + + if("x${GN_CONDITION}" STREQUAL "x") + set(GN_CONDITION ON) + endif() + qt_evaluate_config_expression(result ${GN_CONDITION}) + if(${result}) + set(value "true") + else() + set(value "false") + endif() + message(DEBUG "extend_gn_list(${outList} ${GN_ARGS} CONDITION ${GN_CONDITION} ...): Evaluated to ${value}") + foreach(gnArg ${GN_ARGS}) + set(${outList} "${${outList}}" "${gnArg}=${value}") + endforeach() + set(${outList} "${${outList}}" PARENT_SCOPE) +endfunction() + +function(configure_gn_target sourceDir inFilePath outFilePath) + # FIXME: GN_CONFIG + set(GN_CONFIG NOTUSED) + + set(path_mode REALPATH) + if(APPLE AND QT_ALLOW_SYMLINK_IN_PATHS) + set(path_mode ABSOLUTE) + endif() + + # GN_SOURCES GN_HEADERS + get_property(gnSources DIRECTORY PROPERTY GN_SOURCES) + foreach(gnSourceFile ${gnSources}) + get_filename_component(gnSourcePath ${sourceDir}/${gnSourceFile} ${path_mode}) + list(APPEND sourceList \"${gnSourcePath}\") + endforeach() + set(GN_HEADERS ${sourceList}) + set(GN_SOURCES ${sourceList}) + list(FILTER GN_HEADERS INCLUDE REGEX "^.+\\.h\"$") + list(FILTER GN_SOURCES EXCLUDE REGEX "^.+\\.h\"$") + + # GN_DEFINES + get_property(gnDefines DIRECTORY PROPERTY GN_DEFINES) + list(REMOVE_DUPLICATES gnDefines) + foreach(gnDefine ${gnDefines}) + list(APPEND GN_ARGS_DEFINES \"-D${gnDefine}\") + list(APPEND GN_DEFINES \"${gnDefine}\") + endforeach() + + # GN_INCLUDES + get_property(gnIncludes DIRECTORY PROPERTY GN_INCLUDES) + list(REMOVE_DUPLICATES gnIncludes) + foreach(gnInclude ${gnIncludes}) + get_filename_component(gnInclude ${gnInclude} ${path_mode}) + list(APPEND GN_ARGS_INCLUDES \"-I${gnInclude}\") + list(APPEND GN_INCLUDE_DIRS \"${gnInclude}\") + endforeach() + + # MOC + get_property(mocFilePath DIRECTORY PROPERTY GN_MOC_PATH) + set(GN_ARGS_MOC_BIN \"${mocFilePath}\") + + # GN_CFLAGS_CC + get_property(gnCxxCompileOptions DIRECTORY PROPERTY GN_CXX_COMPILE_OPTIONS) + foreach(gnCxxCompileOption ${gnCxxCompileOptions}) + list(APPEND GN_CFLAGS_CC \"${gnCxxCompileOption}\") + endforeach() + list(REMOVE_DUPLICATES GN_CFLAGS_CC) + + # GN_CFLAGS_C + get_property(gnCCompileOptions DIRECTORY PROPERTY GN_C_COMPILE_OPTIONS) + foreach(gnCCompileOption ${gnCCompileOptions}) + list(APPEND GN_CFLAGS_C \"${gnCCompileOption}\") + endforeach() + list(REMOVE_DUPLICATES GN_CFLAGS_C) + + # GN_SOURCE_ROOT + get_filename_component(GN_SOURCE_ROOT "${sourceDir}" ${path_mode}) + + if(APPLE) # this runs in scrpit mode without qt-cmake so on MACOS here + recoverFrameworkBuild(GN_INCLUDE_DIRS GN_CFLAGS_C) + endif() + + # Static setup + set(libs PNG JPEG FREETYPE HARFBUZZ ZLIB) + foreach(lib ${libs}) + get_property(staticIncludes DIRECTORY PROPERTY GN_${lib}_INCLUDES) + foreach(is ${staticIncludes}) + list(APPEND GN_${lib}_INCLUDES \"${is}\") + endforeach() + endforeach() + foreach(item GN_HEADERS GN_SOURCES GN_ARGS_DEFINES GN_DEFINES GN_ARGS_INCLUDES + GN_INCLUDE_DIRS GN_CFLAGS_CC GN_CFLAGS_C GN_PNG_INCLUDES GN_JPEG_INCLUDES + GN_FREETYPE_INCLUDES GN_HARFBUZZ_INCLUDES GN_ZLIB_INCLUDES) + string(REPLACE ";" ",\n " ${item} "${${item}}") + endforeach() + configure_file(${inFilePath} ${outFilePath} @ONLY) +endfunction() + +# we had no qtsync on headers during configure, so take current interface from expression +# generator from our WebEngieCore target so we can apply it for our buildGn target +function(resolve_target_includes resultVar target) + get_target_property(includeDirs ${target} INCLUDE_DIRECTORIES) + foreach(includeDir ${includeDirs}) + if(includeDir MATCHES "\\$<BUILD_INTERFACE:([^,>]+)>") + list(APPEND includeDirList ${CMAKE_MATCH_1}) + endif() + endforeach() + set(${resultVar} ${includeDirList} PARENT_SCOPE) +endfunction() + +function(get_install_config result) + if(DEFINED CMAKE_BUILD_TYPE) + set(${result} ${CMAKE_BUILD_TYPE} PARENT_SCOPE) + elseif(DEFINED CMAKE_CONFIGURATION_TYPES) + if("Release" IN_LIST CMAKE_CONFIGURATION_TYPES) + set(${result} "Release" PARENT_SCOPE) + elseif("RelWithDebInfo" IN_LIST CMAKE_CONFIGURATION_TYPES) + set(${result} "RelWithDebInfo" PARENT_SCOPE) + elseif("Debug" IN_LIST CMAKE_CONFIGURATION_TYPES) + set(${result} "Debug" PARENT_SCOPE) + else() + # assume MinSizeRel ? + set(${result} "${CMAKE_CONFIGURATION_TYPES}" PARENT_SCOPE) + endif() + endif() +endfunction() + +# we need to pass -F or -iframework in case of frameworks builds, which gn treats as +# compiler flag and cmake as include dir, so swap it. +function(recoverFrameworkBuild includeDirs compilerFlags) + foreach(includeDir ${${includeDirs}}) + if(includeDir MATCHES "^\"(.*/([^/]+)\\.framework)\"$") + list(APPEND frameworkDirs \"-iframework${CMAKE_MATCH_1}/..\") + else() + list(APPEND newIncludeDirs ${includeDir}) + endif() + endforeach() + set(${includeDirs} ${newIncludeDirs} PARENT_SCOPE) + set(${compilerFlags} ${${compilerFlags}} ${frameworkDirs} PARENT_SCOPE) +endfunction() + +# we need to fix namespace ambiguity issues between Qt and Chromium like +# forward declarations of NSString. +function(get_forward_declaration_macro result) + if(MACOS) + set(${result} " \"Q_FORWARD_DECLARE_OBJC_CLASS(name)=class name;\" " PARENT_SCOPE) + else() + set(${result} "Q_FORWARD_DECLARE_OBJC_CLASS=QT_FORWARD_DECLARE_CLASS" PARENT_SCOPE) + endif() +endfunction() + +function(get_darwin_sdk_version result) + if(APPLE) + if(IOS) + set(sdk_name "iphoneos") + elseif(TVOS) + set(sdk_name "appletvos") + elseif(WATCHOS) + set(sdk_name "watchos") + else() + # Default to macOS + set(sdk_name "macosx") + endif() + set(xcrun_version_arg "--show-sdk-version") + execute_process(COMMAND /usr/bin/xcrun --sdk ${sdk_name} ${xcrun_version_arg} + OUTPUT_VARIABLE sdk_version + ERROR_VARIABLE xcrun_error) + if(NOT sdk_version) + message(FATAL_ERROR + "Can't determine darwin ${sdk_name} SDK version. Error: ${xcrun_error}") + endif() + string(STRIP "${sdk_version}" sdk_version) + set(${result} "${sdk_version}" PARENT_SCOPE) + endif() +endfunction() + +function(get_ios_target_triple_and_sysroot result arch) + get_ios_sysroot(sysroot ${arch}) + set(${result} + -target ${arch}-apple-ios${CMAKE_OSX_DEPLOYMENT_TARGET} + -isysroot ${sysroot} PARENT_SCOPE + ) +endfunction() + +function(add_ninja_target) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "TARGET;CMAKE_TARGET;NINJA_TARGET;BUILDDIR;NINJA_STAMP;NINJA_DATA_STAMP;CONFIG;ARCH" "" + ) + _qt_internal_validate_all_args_are_parsed(arg) + set(stamps ${arg_NINJA_STAMP} ${arg_NINJA_DATA_STAMP}) + list(TRANSFORM stamps PREPEND "${arg_BUILDDIR}/${arg_CONFIG}/${arg_ARCH}/") + add_custom_target(${arg_TARGET} DEPENDS ${stamps}) + set_target_properties(${arg_TARGET} PROPERTIES + CONFIG ${arg_CONFIG} + ARCH ${arg_ARCH} + CMAKE_TARGET ${arg_CMAKE_TARGET} + NINJA_TARGET ${arg_NINJA_TARGET} + NINJA_STAMP ${arg_NINJA_STAMP} + ) +endfunction() + +function(get_copy_of_response_file result target rsp) + get_target_property(config ${target} CONFIG) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + set(rsp_dst "CMakeFiles_${ninjaTarget}_${config}_${rsp}.rsp") + set(rsp_src "${${result}}") + if(NOT QT_SUPERBUILD) + set(rsp_output ${PROJECT_BINARY_DIR}/${rsp_dst}) + else() + set(rsp_output ${PROJECT_BINARY_DIR}/../${rsp_dst}) + endif() + add_custom_command( + OUTPUT ${rsp_output} + COMMAND ${CMAKE_COMMAND} -E copy ${rsp_src} ${rsp_output} + DEPENDS ${rsp_src} + USES_TERMINAL + ) + set(${result} ${rsp_dst} PARENT_SCOPE) + add_custom_target(${cmakeTarget}_${rsp}_copy_${config} + DEPENDS ${rsp_output} + ) + add_dependencies(${cmakeTarget} ${cmakeTarget}_${rsp}_copy_${config}) +endfunction() + +function(add_archiver_options target buildDir completeStatic) + get_target_property(config ${target} CONFIG) + string(TOUPPER ${config} cfg) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + set(objects_out "${buildDir}/${cmakeTarget}_objects.o") + add_library(GnObject_${cmakeTarget}_${config} OBJECT IMPORTED GLOBAL) + target_link_libraries(${cmakeTarget} PRIVATE $<$<CONFIG:${config}>:GnObject_${cmakeTarget}_${config}>) + set_property(TARGET GnObject_${cmakeTarget}_${config} PROPERTY IMPORTED_OBJECTS_${cfg} ${objects_out}) +endfunction() + +function(add_linker_options target buildDir completeStatic) + get_target_property(config ${target} CONFIG) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + string(TOUPPER ${cmakeTarget} tg) + string(TOUPPER ${config} cfg) + set(objects_rsp "${buildDir}/${ninjaTarget}_objects.rsp") + set(archives_rsp "${buildDir}/${ninjaTarget}_archives.rsp") + set(libs_rsp "${buildDir}/${ninjaTarget}_libs.rsp") + set(ldir_rsp "${buildDir}/${ninjaTarget}_ldir.rsp") + set_target_properties(${cmakeTarget} PROPERTIES STATIC_LIBRARY_OPTIONS "@${objects_rsp}") + if(LINUX OR ANDROID) + get_gn_arch(cpu ${TEST_architecture_arch}) + if(CMAKE_CROSSCOMPILING AND cpu STREQUAL "arm" AND ${config} STREQUAL "Debug") + target_link_options(${cmakeTarget} PRIVATE "LINKER:--long-plt") + endif() + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") + # Chromium is meant for linking with gc-sections, which seems to not always get applied otherwise + target_link_options(${cmakeTarget} PRIVATE "-Wl,--gc-sections") + if(NOT completeStatic) + target_link_libraries(${cmakeTarget} PRIVATE + "$<1:-Wl,--start-group $<$<CONFIG:${config}>:@${archives_rsp}> -Wl,--end-group>" + ) + endif() + + # linker here options are just to prevent processing it by cmake + target_link_libraries(${cmakeTarget} PRIVATE + "$<1:-Wl,--no-fatal-warnings $<$<CONFIG:${config}>:@${ldir_rsp}> $<$<CONFIG:${config}>:@${libs_rsp}> -Wl,--no-fatal-warnings>" + ) + unset(cpu) + endif() + if(MACOS) + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") + if(NOT completeStatic) + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${archives_rsp}>") + endif() + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${ldir_rsp}>" "$<$<CONFIG:${config}>:@${libs_rsp}>") + endif() + if(WIN32) + get_copy_of_response_file(objects_rsp ${target} objects) + if(NOT MINGW) + target_link_options(${cmakeTarget} + PRIVATE /DELAYLOAD:mf.dll /DELAYLOAD:mfplat.dll /DELAYLOAD:mfreadwrite.dll /DELAYLOAD:winmm.dll + ) + # enable larger PDBs if webenginecore debug build + if(cmakeTarget STREQUAL "WebEngineCore") + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:Debug>:/pdbpagesize:8192>") + endif() + endif() + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") + if(NOT completeStatic) + get_copy_of_response_file(archives_rsp ${target} archives) + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${archives_rsp}>") + endif() + get_copy_of_response_file(libs_rsp ${target} libs) + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${libs_rsp}>") + # we need libs rsp also when linking process with sandbox lib + set_property(TARGET ${cmakeTarget} PROPERTY LIBS_RSP ${libs_rsp}) + endif() +endfunction() + +function(add_intermediate_archive target buildDir completeStatic) + get_target_property(config ${target} CONFIG) + get_target_property(arch ${target} ARCH) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + get_target_property(ninjaStamp ${target} NINJA_STAMP) + string(TOUPPER ${config} cfg) + set(objects_rsp "${buildDir}/${ninjaTarget}_objects.rsp") + set(objects_out "${buildDir}/${cmakeTarget}_objects.o") + if(NOT completeStatic) + set(archives_rsp "${buildDir}/${ninjaTarget}_archives.rsp") + set(archives_out "${buildDir}/${cmakeTarget}_archives.o") + set(archives_command + COMMAND clang++ -r -nostdlib -arch ${arch} + -o ${archives_out} + -Wl,-keep_private_externs + -Wl,-all_load + @${archives_rsp} + ) + endif() + add_custom_command( + OUTPUT ${buildDir}/${cmakeTarget}.a + BYPRODUCTS ${objects_out} ${archives_out} + COMMAND clang++ -r -nostdlib -arch ${arch} + -o ${objects_out} + -Wl,-keep_private_externs + @${objects_rsp} + ${archives_command} + COMMAND ar -crs + ${buildDir}/${cmakeTarget}.a + ${objects_out} + ${archives_out} + DEPENDS + ${buildDir}/${ninjaStamp} + WORKING_DIRECTORY "${buildDir}/../../.." + COMMENT "Creating intermediate archives for ${cmakeTarget}/${config}/${arch}" + USES_TERMINAL + VERBATIM + COMMAND_EXPAND_LISTS + ) +endfunction() + +function(add_intermediate_object target buildDir completeStatic) + get_target_property(config ${target} CONFIG) + get_target_property(arch ${target} ARCH) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + get_target_property(ninjaStamp ${target} NINJA_STAMP) + string(TOUPPER ${config} cfg) + if(IOS) + get_ios_target_triple_and_sysroot(args ${arch}) + endif() + set(objects_rsp "${buildDir}/${ninjaTarget}_objects.rsp") + set(objects_out "${buildDir}/${cmakeTarget}_objects.o") + add_custom_command( + OUTPUT ${objects_out} + COMMAND clang++ -r -nostdlib + ${args} + -o ${objects_out} + -Wl,-keep_private_externs + @${objects_rsp} + DEPENDS + ${buildDir}/${ninjaStamp} + WORKING_DIRECTORY "${buildDir}/../../.." + COMMENT "Creating intermediate object files for ${cmakeTarget}/${config}/${arch}" + USES_TERMINAL + VERBATIM + COMMAND_EXPAND_LISTS + ) +endfunction() + +# Lipo the object files together to a single fat archive +function(create_lipo_command target buildDir fileName) + get_target_property(config ${target} CONFIG) + get_architectures(archs) + foreach(arch ${archs}) + list(APPEND lipo_objects ${buildDir}/${arch}/${fileName}) + endforeach() + add_custom_command( + OUTPUT ${buildDir}/${fileName} + COMMAND lipo -create + -output ${buildDir}/${fileName} + ARGS ${lipo_objects} + DEPENDS ${lipo_objects} + USES_TERMINAL + COMMENT "Running lipo for ${target}/${config}/${arch}" + VERBATIM + ) +endfunction() + +# this function only deals with objects as it is only +# used by qtpdf and we do not need anything more +function(add_ios_lipo_command target buildDir) + get_target_property(config ${target} CONFIG) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + set(fileName ${cmakeTarget}_objects.o) + create_lipo_command(${target} ${buildDir} ${fileName}) + add_custom_target(lipo_${cmakeTarget}_${config} DEPENDS + ${buildDir}/${fileName} + ) + add_dependencies(${cmakeTarget} lipo_${cmakeTarget}_${config}) + qt_internal_get_target_property(options ${cmakeTarget} STATIC_LIBRARY_OPTIONS) + set_target_properties(${cmakeTarget} PROPERTIES STATIC_LIBRARY_OPTIONS + "${options}$<$<CONFIG:${config}>:${buildDir}/${fileName}>" + ) +endfunction() + +function(add_lipo_command target buildDir) + get_target_property(config ${target} CONFIG) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + set(fileName ${cmakeTarget}.a) + create_lipo_command(${target} ${buildDir} ${fileName}) + add_library(${cmakeTarget}_${config} STATIC IMPORTED GLOBAL) + set_property(TARGET ${cmakeTarget}_${config} + PROPERTY IMPORTED_LOCATION ${buildDir}/${fileName} + ) + add_custom_target(lipo_${cmakeTarget}_${config} DEPENDS + ${buildDir}/${fileName} + ) + add_dependencies(${cmakeTarget}_${config} lipo_${cmakeTarget}_${config}) + target_link_libraries(${cmakeTarget} PRIVATE ${cmakeTarget}_${config}) + + # Just link with dynamic libs once + # TODO: this is evil hack, since cmake has no idea about libs + set(libs_rsp "${buildDir}/x86_64/${ninjaTarget}_libs.rsp") + target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${libs_rsp}>") +endfunction() + +function(qt_internal_add_external_project_dependency_to_root_project name) + set(independent_args) + cmake_policy(PUSH) + if(POLICY CMP0114) + set(independent_args INDEPENDENT TRUE) + cmake_policy(SET CMP0114 NEW) + endif() + + # Force configure step to re-run after we configure the root project + set(reconfigure_check_file ${CMAKE_CURRENT_BINARY_DIR}/reconfigure_${name}.stamp) + file(TOUCH ${reconfigure_check_file}) + ExternalProject_Add_Step(${name} reconfigure-check + DEPENDERS configure + DEPENDS ${reconfigure_check_file} + ${independent_args} + ) + + cmake_policy(POP) +endfunction() + +# Function maps TEST_architecture_arch or CMAKE_SYSTEM_PROCESSOR into gn architecture +function(get_gn_arch result arch) + set(armList arm armv7-a) + set(mips64List mips64 mipsel64) + set(x86List i386 i686) + set(x64List x86_64 AMD64 x86_64h aarch64) + if(arch IN_LIST x86List) + set(${result} "x86" PARENT_SCOPE) + elseif(arch IN_LIST x64List) + set(${result} "x64" PARENT_SCOPE) + elseif(arch IN_LIST armList) + set(${result} "arm" PARENT_SCOPE) + elseif(arch STREQUAL "arm64") + set(${result} "arm64" PARENT_SCOPE) + elseif(arch STREQUAL "mipsel") + set(${result} "mipsel" PARENT_SCOPE) + elseif(arch IN_LIST mipsList) + set(${result} "mips64el" PARENT_SCOPE) + elseif(arch STREQUAL "riscv64") + set(${result} "riscv64" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unknown architecture: ${arch}") + endif() +endfunction() + +# Function maps gn architecture for v8 +function(get_v8_arch result targetArch hostArch) + set(list32 x86 arm mipsel riscv32) + if(hostArch STREQUAL targetArch) + set(${result} "${targetArch}" PARENT_SCOPE) + elseif(targetArch IN_LIST list32) + # 32bit target which needs a 32bit compatible host + if(hostArch STREQUAL "x64") + set(${result} "x86" PARENT_SCOPE) + elseif(hostArch STREQUAL "arm64") + set(${result} "arm" PARENT_SCOPE) + elseif(hostArch STREQUAL "mips64el") + set(${result} "mipsel" PARENT_SCOPE) + elseif(hostArch STREQUAL "riscv64") + set(${result} "riscv32" PARENT_SCOPE) + elseif(hostArch IN_LIST list32) + set(${result} "${hostArch}" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unknown architecture: ${hostArch}") + endif() + else() + # assume 64bit target which matches 64bit host + set(${result} "${hostArch}" PARENT_SCOPE) + endif() +endfunction() + +function(get_gn_os result) + if(WIN32) + set(${result} "win" PARENT_SCOPE) + elseif(LINUX) + set(${result} "linux" PARENT_SCOPE) + elseif(MACOS) + set(${result} "mac" PARENT_SCOPE) + elseif(IOS) + set(${result} "ios" PARENT_SCOPE) + else() + message(DEBUG "Unrecognized OS") + endif() +endfunction() + +function(get_gn_is_clang result) + if(CLANG) + set(${result} "true" PARENT_SCOPE) + else() + set(${result} "false" PARENT_SCOPE) + endif() +endfunction() + + +function(get_gn_is_mingw result) + if(MINGW) + set(${result} "true" PARENT_SCOPE) + else() + set(${result} "false" PARENT_SCOPE) + endif() +endfunction() + +function(get_ios_sysroot result arch) + if(NOT CMAKE_APPLE_ARCH_SYSROOTS) + message(FATAL_ERROR "CMAKE_APPLE_ARCH_SYSROOTS not set.") + endif() + get_architectures(archs) + list(FIND archs ${arch} known_arch) + if (known_arch EQUAL "-1") + message(FATAL_ERROR "Unknown iOS architecture ${arch}.") + endif() + list(GET CMAKE_APPLE_ARCH_SYSROOTS ${known_arch} sysroot) + set(${result} ${sysroot} PARENT_SCOPE) +endfunction() + +function(configure_gn_toolchain name cpu v8Cpu toolchainIn toolchainOut) + set(GN_TOOLCHAIN ${name}) + get_gn_os(GN_OS) + get_gn_is_clang(GN_IS_CLANG) + get_gn_is_mingw(GN_IS_MINGW) + set(GN_CPU ${cpu}) + set(GN_V8_CPU ${v8Cpu}) + configure_file(${toolchainIn} ${toolchainOut}/BUILD.gn @ONLY) +endfunction() + +function(create_pkg_config_wrapper wrapperName wrapperCmd) + file(WRITE ${wrapperName} + "#!/bin/sh\n" + "unset PKG_CONFIG_LIBDIR\n" + "unset PKG_CONFIG_PATH\n" + "unset PKG_CONFIG_SYSROOT_DIR\n" + "exec ${wrapperCmd} \"$@\"" + ) + file(CHMOD ${wrapperName} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) +endfunction() + +function(extract_cflag result cflag) + set(i 1) + while(NOT "x${CMAKE_CXX_COMPILER_ARG${i}}" STREQUAL "x") + list(APPEND cflags ${CMAKE_CXX_COMPILER_ARG${i}}) + math(EXPR i "${i} + 1") + endwhile() + list(APPEND cflags ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}) + string(REPLACE ";" " " cflags "${cflags}") + message(DEBUG "Found cflags: ${cflags}") + if(cflags MATCHES "-${cflag}=([^ ]+)") + set(${result} ${CMAKE_MATCH_1} PARENT_SCOPE) + return() + endif() + if(cflags MATCHES "-${cflag}") + set(${result} ON PARENT_SCOPE) + else() + set(${result} OFF PARENT_SCOPE) + endif() +endfunction() + +function(extend_gn_list_cflag outList) + cmake_parse_arguments(PARSE_ARGV 1 GN "" "" "ARG;CFLAG") + _qt_internal_validate_all_args_are_parsed(GN) + + extract_cflag(cflag "${GN_CFLAG}") + if(cflag) + set(${outList} "${${outList}}" "${GN_ARG}=\"${cflag}\"" PARENT_SCOPE) + endif() +endfunction() + +function(get_arm_version result cflag) + if(cflag MATCHES "^armv([0-9])") + set(${result} ${CMAKE_MATCH_1} PARENT_SCOPE) + endif() +endfunction() + +function(check_thumb result) + extract_cflag(thumb "mthumb") + if(thumb) + set(${result} TRUE PARENT_SCOPE) + return() + else() + extract_cflag(marm "marm") + if(marm) + set(${result} FALSE PARENT_SCOPE) + return() + else() + extract_cflag(march "march") + get_arm_version(arm_version ${march}) + if(arm_version GREATER_EQUAL 7) + set(${result} TRUE PARENT_SCOPE) + return() + endif() + endif() + endif() + set(${result} FALSE PARENT_SCOPE) +endfunction() + +macro(create_pkg_config_host_wrapper buildDir) + find_package(PkgConfigHost) + if(CMAKE_CROSSCOMPILING) + create_pkg_config_wrapper("${buildDir}/pkg-config-host_wrapper.sh" "${PKG_CONFIG_HOST_EXECUTABLE}") + set(PKG_CONFIG_HOST_EXECUTABLE "${buildDir}/pkg-config-host_wrapper.sh") + endif() +endmacro() + +macro(setup_toolchains) + get_gn_arch(gn_arch ${TEST_architecture_arch}) + if(NOT CMAKE_CROSSCOMPILING) # delivered by hostBuild project + configure_gn_toolchain(host ${gn_arch} ${gn_arch} + ${WEBENGINE_ROOT_SOURCE_DIR}/src/host/BUILD.toolchain.gn.in + ${buildDir}/host_toolchain) + configure_gn_toolchain(v8 ${gn_arch} ${gn_arch} + ${WEBENGINE_ROOT_SOURCE_DIR}/src/host/BUILD.toolchain.gn.in + ${buildDir}/v8_toolchain) + endif() + configure_gn_toolchain(target ${gn_arch} ${gn_arch} + ${WEBENGINE_ROOT_SOURCE_DIR}/src/host/BUILD.toolchain.gn.in + ${buildDir}/target_toolchain) + unset(gn_arch) +endmacro() + +macro(append_build_type_setup) + list(APPEND gnArgArg + is_qtwebengine=true + init_stack_vars=false + is_component_build=false + is_shared=true + use_sysroot=false + forbid_non_component_debug_builds=false + treat_warnings_as_errors=false + use_allocator_shim=false + use_partition_alloc=true + use_partition_alloc_as_malloc=false + use_custom_libcxx=false + enable_rust=false # We do not yet support rust + ) + if(${config} STREQUAL "Debug") + list(APPEND gnArgArg is_debug=true symbol_level=2) + if(WIN32) + list(APPEND gnArgArg enable_iterator_debugging=true) + endif() + elseif(${config} STREQUAL "Release") + list(APPEND gnArgArg is_debug=false symbol_level=0) + elseif(${config} STREQUAL "RelWithDebInfo") + list(APPEND gnArgArg is_debug=false) + if(WIN32 AND NOT CLANG) + list(APPEND gnArgArg symbol_level=2) + else() + list(APPEND gnArgArg symbol_level=1) + endif() + elseif(${config} STREQUAL "MinSizeRel") + list(APPEND gnArgArg is_debug=false symbol_level=0 optimize_for_size=true) + endif() + if(FEATURE_developer_build OR (${config} STREQUAL "Debug") OR QT_FEATURE_webengine_sanitizer) + list(APPEND gnArgArg + is_official_build=false + use_viz_debugger=false + ) + else() + list(APPEND gnArgArg is_official_build=true) + if(NOT CLANG OR NOT QT_FEATURE_use_lld_linker) + list(APPEND gnArgArg + use_thin_lto=false + ) + endif() + endif() + extend_gn_list(gnArgArg + ARGS is_unsafe_developer_build + CONDITION FEATURE_developer_build + ) + + #TODO: refactor to not check for IOS here + if(NOT QT_FEATURE_webengine_full_debug_info AND NOT IOS) + list(APPEND gnArgArg blink_symbol_level=0 v8_symbol_level=0) + endif() + + extend_gn_list(gnArgArg ARGS use_jumbo_build CONDITION QT_FEATURE_webengine_jumbo_build) + if(QT_FEATURE_webengine_jumbo_build) + list(APPEND gnArgArg jumbo_file_merge_limit=${QT_FEATURE_webengine_jumbo_file_merge_limit}) + if(QT_FEATURE_webengine_jumbo_file_merge_limit LESS_EQUAL 8) + list(APPEND gnArgArg jumbo_build_excluded=[\"browser\"]) + endif() + endif() + + extend_gn_list(gnArgArg + ARGS enable_precompiled_headers + CONDITION BUILD_WITH_PCH AND NOT LINUX + ) + extend_gn_list(gnArgArg + ARGS dcheck_always_on + CONDITION QT_FEATURE_force_asserts + ) +endmacro() + +macro(append_compiler_linker_sdk_setup) + if(CMAKE_CXX_COMPILER_LAUNCHER) + list(APPEND gnArgArg cc_wrapper="${CMAKE_CXX_COMPILER_LAUNCHER}") + endif() + + extend_gn_list(gnArgArg ARGS is_clang CONDITION CLANG) + extend_gn_list(gnArgArg ARGS is_mingw CONDITION MINGW) + extend_gn_list(gnArgArg ARGS is_msvc CONDITION MSVC) + extend_gn_list(gnArgArg ARGS is_gcc CONDITION LINUX AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + + if(CLANG) + if(MACOS) + get_darwin_sdk_version(macSdkVersion) + # macOS needs to use the objcxx compiler as the cxx compiler is just a link + get_filename_component(clangBasePath ${CMAKE_OBJCXX_COMPILER} DIRECTORY) + get_filename_component(clangBasePath ${clangBasePath} DIRECTORY) + else() + get_filename_component(clangBasePath ${CMAKE_CXX_COMPILER} DIRECTORY) + get_filename_component(clangBasePath ${clangBasePath} DIRECTORY) + endif() + + string(REGEX MATCH "[0-9]+" clangVersion ${CMAKE_CXX_COMPILER_VERSION}) + list(APPEND gnArgArg + clang_base_path="${clangBasePath}" + clang_use_chrome_plugins=false + clang_version=${clangVersion} + fatal_linker_warnings=false + ) + + if(MACOS) + list(APPEND gnArgArg + use_system_xcode=true + mac_deployment_target="${CMAKE_OSX_DEPLOYMENT_TARGET}" + mac_sdk_min="${macSdkVersion}" + use_libcxx=true + ) + endif() + if(IOS) + list(APPEND gnArgArg + use_system_xcode=true + enable_ios_bitcode=true + ios_deployment_target="${CMAKE_OSX_DEPLOYMENT_TARGET}" + ios_enable_code_signing=false + use_libcxx=true + ) + endif() + if(DEFINED QT_FEATURE_stdlib_libcpp AND LINUX) + extend_gn_list(gnArgArg ARGS use_libcxx + CONDITION QT_FEATURE_stdlib_libcpp + ) + endif() + if(ANDROID) + list(APPEND gnArgArg + android_ndk_root="${CMAKE_ANDROID_NDK}" + android_ndk_version="${CMAKE_ANDROID_NDK_VERSION}" + clang_use_default_sample_profile=false + #android_ndk_major_version=22 + ) + endif() + else() + if(QT_FEATURE_use_lld_linker) + get_filename_component(clangBasePath ${CMAKE_LINKER} DIRECTORY) + get_filename_component(clangBasePath ${clangBasePath} DIRECTORY) + list(APPEND gnArgArg + clang_base_path="${clangBasePath}" + fatal_linker_warnings=false + ) + endif() + endif() + + if(MSVC) + get_filename_component(windowsSdkPath $ENV{WINDOWSSDKDIR} ABSOLUTE) + get_filename_component(visualStudioPath $ENV{VSINSTALLDIR} ABSOLUTE) + set(windowSdkVersion $ENV{WindowsSDKVersion}) + list(APPEND gnArgArg + win_linker_timing=true + use_incremental_linking=false + visual_studio_version=2022 + visual_studio_path=\"${visualStudioPath}\" + windows_sdk_version=\"${windowsSdkVersion}\" + windows_sdk_path=\"${windowsSdkPath}\" + ) + endif() + get_gn_arch(cpu ${TEST_architecture_arch}) + if(LINUX AND CMAKE_CROSSCOMPILING AND cpu STREQUAL "arm") + + extend_gn_list_cflag(gnArgArg + ARG arm_tune + CFLAG mtune + ) + extend_gn_list_cflag(gnArgArg + ARG arm_float_abi + CFLAG mfloat-abi + ) + extend_gn_list_cflag(gnArgArg + ARG arm_arch + CFLAG march + ) + extend_gn_list_cflag(gnArgArg + ARG arm_cpu + CFLAG mcpu + ) + extract_cflag(cflag "mfpu") + get_arm_version(arm_version "${cflag}") + extend_gn_list(gnArgArg + ARGS arm_use_neon + CONDITION (arm_version GREATER_EQUAL 8) OR ("${cflag}" MATCHES ".*neon.*") + ) + if(arm_version EQUAL 7 AND NOT "${cflag}" MATCHES ".*neon.*") + # If the toolchain does not explicitly specify to use NEON instructions + # we use arm_neon_optional for ARMv7 + list(APPEND gnArgArg arm_optionally_use_neon=true) + endif() + extract_cflag(march "march") + get_arm_version(arm_version ${march}) + if(arm_version EQUAL 7) + list(APPEND gnArgArg use_arm_crc32=false) + endif() + check_thumb(armThumb) + extend_gn_list(gnArgArg + ARGS arm_use_thumb + CONDITION armThumb + ) + endif() + extend_gn_list(gnArgArg + ARGS use_gold + CONDITION QT_FEATURE_use_gold_linker + ) + extend_gn_list(gnArgArg + ARGS use_lld + CONDITION QT_FEATURE_use_lld_linker + ) + unset(cpu) +endmacro() + +macro(append_sanitizer_setup) + if(QT_FEATURE_webengine_sanitizer) + extend_gn_list(gnArgArg + ARGS is_asan + CONDITION address IN_LIST ECM_ENABLE_SANITIZERS + ) + extend_gn_list(gnArgArg + ARGS is_tsan + CONDITION thread IN_LIST ECM_ENABLE_SANITIZERS + ) + extend_gn_list(gnArgArg + ARGS is_msan + CONDITION memory IN_LIST ECM_ENABLE_SANITIZERS + ) + extend_gn_list(gnArgArg + ARGS is_ubsan is_ubsan_vptr + CONDITION undefined IN_LIST ECM_ENABLE_SANITIZERS + ) + if(APPLE) + list(APPEND gnArgArg + clang_version=\"${QT_COMPILER_VERSION_MAJOR}.${QT_COMPILER_VERSION_MINOR}.${QT_COMPILER_VERSION_PATCH}\" + ) + endif() + endif() +endmacro() + +macro(append_toolchain_setup) + if(WIN32) + get_gn_arch(cpu ${arch}) + list(APPEND gnArgArg target_cpu="${cpu}") + if(MINGW) + get_gn_arch(cpu ${TEST_architecture_arch}) + list(APPEND gnArgArg + # note '/' prefix + custom_toolchain="/${buildDir}/target_toolchain:target" + host_toolchain="/${buildDir}/host_toolchain:host" + host_cpu="${cpu}" + ) + endif() + elseif(LINUX) + get_gn_arch(cpu ${TEST_architecture_arch}) + list(APPEND gnArgArg + custom_toolchain="${buildDir}/target_toolchain:target" + host_toolchain="${buildDir}/host_toolchain:host" + ) + if(CMAKE_CROSSCOMPILING) + list(APPEND gnArgArg + v8_snapshot_toolchain="${buildDir}/v8_toolchain:v8" + target_cpu="${cpu}" + ) + else() + list(APPEND gnArgArg host_cpu="${cpu}") + endif() + if(CMAKE_SYSROOT) + list(APPEND gnArgArg target_sysroot="${CMAKE_SYSROOT}") + endif() + elseif(MACOS) + get_gn_arch(cpu ${arch}) + list(APPEND gnArgArg target_cpu="${cpu}") + elseif(IOS) + get_gn_arch(cpu ${arch}) + get_ios_sysroot(sysroot ${arch}) + list(APPEND gnArgArg target_cpu="${cpu}" target_sysroot="${sysroot}" target_os="ios") + elseif(ANDROID) + get_gn_arch(cpu ${TEST_architecture_arch}) + list(APPEND gnArgArg target_os="android" target_cpu="${cpu}") + if(CMAKE_HOST_WIN32) + list(APPEND gnArgArg + host_toolchain="/${buildDir}/host_toolchain:host" + host_cpu="x64" + v8_snapshot_toolchain="/${buildDir}/v8_toolchain:v8" + ) + endif() + endif() + unset(cpu) +endmacro() + + +macro(append_pkg_config_setup) + if(PkgConfig_FOUND) + list(APPEND gnArgArg + pkg_config="${PKG_CONFIG_EXECUTABLE}" + host_pkg_config="${PKG_CONFIG_HOST_EXECUTABLE}" + ) + if(NOT "$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") + list(APPEND gnArgArg + system_libdir="$ENV{PKG_CONFIG_LIBDIR}" + ) + endif() + endif() +endmacro() + +function(add_ninja_command) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "TARGET;BUILDDIR;MODULE" "OUTPUT;BYPRODUCTS" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + string(REPLACE " " ";" NINJAFLAGS "$ENV{NINJAFLAGS}") + list(TRANSFORM arg_OUTPUT PREPEND "${arg_BUILDDIR}/") + list(TRANSFORM arg_BYPRODUCTS PREPEND "${arg_BUILDDIR}/") + add_custom_command( + OUTPUT + ${arg_OUTPUT} + ${arg_BUILDDIR}/${arg_TARGET} # use generator expression in CMAKE 3.20 + BYPRODUCTS ${arg_BYPRODUCTS} + COMMENT "Running ninja for ${arg_TARGET} in ${arg_BUILDDIR}" + COMMAND Ninja::ninja + ${NINJAFLAGS} + -C ${arg_BUILDDIR} + ${arg_TARGET} + USES_TERMINAL + VERBATIM + COMMAND_EXPAND_LISTS + DEPENDS run_${arg_MODULE}_NinjaReady + ) +endfunction() + +function(get_configs result) + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(${result} ${CMAKE_CONFIGURATION_TYPES}) + else() + set(${result} ${CMAKE_BUILD_TYPE}) + endif() + if(NOT ${result}) + message(FATAL_ERROR "No valid configurations found !") + endif() + set(${result} ${${result}} PARENT_SCOPE) +endfunction() + +function(get_architectures result) + if(CMAKE_OSX_ARCHITECTURES) + set(${result} ${CMAKE_OSX_ARCHITECTURES}) + else() + set(${result} ${CMAKE_SYSTEM_PROCESSOR}) + endif() + if(NOT ${result}) + message(FATAL_ERROR "No valid architectures found. In case of cross-compiling make sure you have CMAKE_SYSTEM_PROCESSOR in your toolchain file.") + endif() + set(${result} ${${result}} PARENT_SCOPE) +endfunction() + +function(add_gn_build_artifacts_to_target) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "CMAKE_TARGET;NINJA_TARGET;BUILDDIR;MODULE;COMPLETE_STATIC;NINJA_STAMP;NINJA_DATA_STAMP" "" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + # config loop is a workaround to be able to add_custom_command per config + # note this is fixed in CMAKE.3.20 and should be cleaned up when 3.20 is + # the minimum cmake we support + get_configs(configs) + get_architectures(archs) + foreach(config ${configs}) + foreach(arch ${archs}) + set(target ${arg_NINJA_TARGET}_${config}_${arch}) + set(stamps ${arg_NINJA_STAMP} ${arg_NINJA_DATA_STAMP}) + add_ninja_target( + TARGET ${target} + NINJA_TARGET ${arg_NINJA_TARGET} + CMAKE_TARGET ${arg_CMAKE_TARGET} + NINJA_STAMP ${arg_NINJA_STAMP} + NINJA_DATA_STAMP ${arg_NINJA_DATA_STAMP} + CONFIG ${config} + ARCH ${arch} + BUILDDIR ${arg_BUILDDIR} + ) + add_ninja_command( + TARGET ${arg_NINJA_TARGET} + OUTPUT ${stamps} + BUILDDIR ${arg_BUILDDIR}/${config}/${arch} + MODULE ${arg_MODULE} + ) + add_dependencies(run_${arg_MODULE}_NinjaDone ${target}) + set_target_properties(${arg_CMAKE_TARGET} PROPERTIES + LINK_DEPENDS ${arg_BUILDDIR}/${config}/${arch}/${arg_NINJA_STAMP} + ) + if(QT_IS_MACOS_UNIVERSAL) + add_intermediate_archive(${target} ${arg_BUILDDIR}/${config}/${arch} ${arg_COMPLETE_STATIC}) + elseif(IOS) + add_intermediate_object(${target} ${arg_BUILDDIR}/${config}/${arch} ${arg_COMPLETE_STATIC}) + else() + if(MACOS AND QT_FEATURE_static) + # mac archiver does not support @file notation, do intermediate object istead + add_intermediate_object(${target} ${arg_BUILDDIR}/${config}/${arch} ${arg_COMPLETE_STATIC}) + add_archiver_options(${target} ${arg_BUILDDIR}/${config}/${arch} ${arg_COMPLETE_STATIC}) + else() + add_linker_options(${target} ${arg_BUILDDIR}/${config}/${arch} ${arg_COMPLETE_STATIC}) + endif() + endif() + unset(target) + endforeach() + list(GET archs 0 arch) + set(target ${arg_NINJA_TARGET}_${config}_${arch}) + # Work around for broken builds with new Apple linker ld_prime. Force + # use of the classic linker until this has been fixed. + # TODO: remove once this has been fixed by Apple. See issue FB13667242 + # or QTBUG-122655 for details. + if(APPLECLANG) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0") + target_link_options(${arg_CMAKE_TARGET} PRIVATE -ld_classic) + set_target_properties(${arg_CMAKE_TARGET} PROPERTIES + QT_NO_DISABLE_WARN_DUPLICATE_LIBRARIES TRUE) + endif() + endif() + if(QT_IS_MACOS_UNIVERSAL) + add_lipo_command(${target} ${arg_BUILDDIR}/${config}) + endif() + if(IOS) + add_ios_lipo_command(${target} ${arg_BUILDDIR}/${config}) + endif() + endforeach() +endfunction() + +function(get_config_filenames c_config cxx_config static_config target_config) + set(${target_config} gn_config_target.cmake PARENT_SCOPE) + set(${cxx_config} gn_config_cxx.cmake PARENT_SCOPE) + set(${c_config} gn_config_c.cmake PARENT_SCOPE) + set(${static_config} gn_static.cmake PARENT_SCOPE) +endfunction() + +function(add_gn_command) + cmake_parse_arguments(PARSE_ARGV 0 arg + "" "CMAKE_TARGET;GN_TARGET;MODULE;BUILDDIR" "NINJA_TARGETS;GN_ARGS" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + get_config_filenames(cConfigFileName cxxConfigFileName staticConfigFileName targetConfigFileName) + set(gnArgArgFile ${arg_BUILDDIR}/args.gn) + + list(JOIN arg_GN_ARGS "\n" arg_GN_ARGS) + file(WRITE ${gnArgArgFile} ${arg_GN_ARGS}) + + foreach(ninjaTarget ${arg_NINJA_TARGETS}) + list(APPEND output ${ninjaTarget}_objects.rsp ${ninjaTarget}_archives.rsp ${ninjaTarget}_libs.rsp ${ninjaTarget}_ldir.rsp) + endforeach() + list(TRANSFORM output PREPEND "${arg_BUILDDIR}/") + + add_custom_command( + OUTPUT ${output} + COMMAND ${CMAKE_COMMAND} + -DBUILD_DIR=${arg_BUILDDIR} + -DSOURCE_DIR=${CMAKE_CURRENT_LIST_DIR} + -DMODULE=${arg_MODULE} + -DQT_HOST_PATH=${QT_HOST_PATH} + -DINSTALL_LIBEXECDIR=${INSTALL_LIBEXECDIR} + -DINSTALL_BINDIR=${INSTALL_BINDIR} + -DPython3_EXECUTABLE=${Python3_EXECUTABLE} + -DGN_THREADS=$ENV{QTWEBENGINE_GN_THREADS} + -DQT_ALLOW_SYMLINK_IN_PATHS=${QT_ALLOW_SYMLINK_IN_PATHS} + -P ${WEBENGINE_ROOT_SOURCE_DIR}/cmake/Gn.cmake + WORKING_DIRECTORY ${WEBENGINE_ROOT_BUILD_DIR} + COMMENT "Run gn for target ${arg_CMAKE_TARGET} in ${arg_BUILDDIR}" + DEPENDS + ${gnArgArgFile} + run_${arg_MODULE}_GnReady + "${WEBENGINE_ROOT_SOURCE_DIR}/src/${arg_MODULE}/configure/BUILD.root.gn.in" + "${WEBENGINE_ROOT_SOURCE_DIR}/cmake/Gn.cmake" + ) + add_custom_target(runGn_${arg_GN_TARGET} + DEPENDS #TODO this is fixed in cmake 3.20 so we could simply use GN_TARGET and not create new one + ${output} + ${arg_BUILDDIR}/${cxxConfigFileName} + ${arg_BUILDDIR}/${cConfigFileName} + ${arg_BUILDDIR}/${targetConfigFileName} + ) + add_dependencies(run_${arg_MODULE}_GnDone runGn_${arg_GN_TARGET}) + if(TARGET thirdparty_sync_headers) + add_dependencies(runGn_${arg_GN_TARGET} thirdparty_sync_headers) + endif() + create_gn_target_config(${arg_GN_TARGET} ${arg_BUILDDIR}/${targetConfigFileName}) +endfunction() + +function(create_cxx_configs cmakeTarget arch) + get_config_filenames(cConfigFileName cxxConfigFileName staticConfigFileName targetConfigFileName) + create_c_config(${cmakeTarget} ${arch} ${cConfigFileName}) + create_cxx_config(${cmakeTarget} ${arch} ${cxxConfigFileName}) + create_static_config(${cmakeTarget} ${arch} ${staticConfigFileName}) +endfunction() + +# targets to gather per config / architecture targets +function(addSyncTargets module) + add_custom_target(run_${module}_GnReady) + add_custom_target(run_${module}_GnDone) + add_custom_target(run_${module}_NinjaReady) + add_custom_target(run_${module}_NinjaDone) + # make nicer log so all gn has to finish before any ninja build starts + add_dependencies(run_${module}_NinjaReady run_${module}_GnDone) +endfunction() + +function(addCopyCommand target src dst) + add_custom_command( + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${dst} + COMMAND ${CMAKE_COMMAND} -E copy ${src} ${dst} + TARGET ${target} + DEPENDS ${src} + USES_TERMINAL + ) +endfunction() + +function(check_for_ulimit) + message("-- Checking 'ulimit -n'") + execute_process(COMMAND bash -c "ulimit -n" + OUTPUT_VARIABLE ulimitOutput + ) + string(REGEX MATCHALL "[0-9]+" limit "${ulimitOutput}") + message(" -- Open files limit ${limit}") + if(NOT (QT_FEATURE_use_gold_linker OR QT_FEATURE_use_lld_linker) AND ulimitOutput LESS 4096) + if(NOT ${CMAKE_VERSION} VERSION_LESS "3.21.0") + message(" -- Creating linker launcher") + file(GENERATE OUTPUT ${PROJECT_BINARY_DIR}/linker_ulimit.sh + CONTENT "#!/bin/bash\nulimit -n 4096\nexec \"$@\"" + FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + ) + set(COIN_BUG_699 ON PARENT_SCOPE) + else() + set(PRINT_BFD_LINKER_WARNING ON PARENT_SCOPE) + endif() + endif() +endfunction() + +function(add_build feature value) + list(APPEND cmakeArgs + "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" + "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" + "-DMATRIX_SUBBUILD=ON" + "-DFEATURE_${feature}=${value}" + ) + if(CMAKE_C_COMPILER_LAUNCHER) + list(APPEND cmakeArgs "-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}") + endif() + if(CMAKE_CXX_COMPILER_LAUNCHER) + list(APPEND cmakeArgs "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}") + endif() + + externalproject_add(${feature} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${feature}-${value} + PREFIX ${feature}-${value} + CMAKE_ARGS ${cmakeArgs} + USES_TERMINAL_BUILD ON + USES_TERMINAL_CONFIGURE ON + BUILD_ALWAYS TRUE + INSTALL_COMMAND "" + ) + get_property(depTracker GLOBAL PROPERTY MATRIX_DEPENDENCY_TRACKER) + foreach(dep ${depTracker}) + add_dependencies(${feature} ${dep}) + endforeach() + set(depTracker "${depTracker}" ${feature}) + set_property(GLOBAL PROPERTY MATRIX_DEPENDENCY_TRACKER "${depTracker}") +endfunction() + +function(add_code_attributions_target) + cmake_parse_arguments(PARSE_ARGV 0 arg "" + "TARGET;OUTPUT;GN_TARGET;FILE_TEMPLATE;ENTRY_TEMPLATE;BUILDDIR" + "EXTRA_THIRD_PARTY_DIRS" + ) + _qt_internal_validate_all_args_are_parsed(arg) + get_filename_component(fileTemplate ${arg_FILE_TEMPLATE} ABSOLUTE) + get_filename_component(entryTemplate ${arg_ENTRY_TEMPLATE} ABSOLUTE) + add_custom_command( + OUTPUT ${arg_OUTPUT} + COMMAND ${CMAKE_COMMAND} + -DLICENSE_SCRIPT=${WEBENGINE_ROOT_SOURCE_DIR}/src/3rdparty/chromium/tools/licenses/licenses.py + -DFILE_TEMPLATE=${fileTemplate} + -DENTRY_TEMPLATE=${entryTemplate} + -DGN_TARGET=${arg_GN_TARGET} + -DEXTRA_THIRD_PARTY_DIRS="${arg_EXTRA_THIRD_PARTY_DIRS}" + -DBUILDDIR=${arg_BUILDDIR} + -DOUTPUT=${arg_OUTPUT} + -DPython3_EXECUTABLE=${Python3_EXECUTABLE} + -P ${WEBENGINE_ROOT_SOURCE_DIR}/cmake/License.cmake + WORKING_DIRECTORY ${WEBENGINE_ROOT_BUILD_DIR} + DEPENDS + ${WEBENGINE_ROOT_SOURCE_DIR}/src/3rdparty/chromium/tools/licenses/licenses.py + ${arg_FILE_TEMPLATE} + ${arg_ENTRY_TEMPLATE} + ${WEBENGINE_ROOT_SOURCE_DIR}/cmake/License.cmake + USES_TERMINAL + ) + add_custom_target(${arg_TARGET} DEPENDS ${arg_OUTPUT}) +endfunction() |