CMake: Fix libraries in qt_lib_XXX_private.pri files for NMC

qmake_use.prf understands the _DEBUG and _RELEASE suffixes for
QMAKE_LIBS_XXX entries. The CMake configuration "Debug" is considered
for the _DEBUG entries, "Release" and "RelWithDebInfo" for _RELEASE.

The qt_lib_XXX_private.pri files are now generated in multiple steps:
1. The QT_LIBS_XXX information is generated per $<CONFIG> and written to
   .cmake files.
2. A preliminary qt_lib_XXX_private.pri file is generated, containing
   only configuration-independent data.
3. A custom command runs the QtGenerateLibPri.cmake script that combines
   the files from step 1 and 2 into the final qt_lib_XXX_private.pri
   file.

The same is done for mkspecs/qmodule.pri.

To be able to trigger custom commands from header modules, which are
interface libraries, we introduce one XXX_timestamp ALL target per
header module that creates a timestamp file. To that XXX_timestamp
target we add the pri file generation target as dependency.

Fixes: QTBUG-84348
Change-Id: I610f279e37feeb7eceb9ef20b3ddfecff8cfbf81
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Joerg Bornemann 2020-06-05 10:10:50 +02:00
parent d2833a3ce5
commit 2a767ab4bb
4 changed files with 168 additions and 31 deletions

View File

@ -311,6 +311,7 @@ qt_copy_or_install(FILES
cmake/QtFindWrapConfigExtra.cmake.in
cmake/QtFileConfigure.txt.in
cmake/QtGenerateExtPri.cmake
cmake/QtGenerateLibPri.cmake
cmake/QtPlatformSupport.cmake
cmake/QtPlatformAndroid.cmake
cmake/QtPostProcess.cmake

View File

@ -611,12 +611,13 @@ function(qt_re_escape out_var str)
set(${out_var} ${regex} PARENT_SCOPE)
endfunction()
# Extracts the 3rdparty libraries for the module ${module_name} in module .pri file format
# and stores the content in ${out_var}.
# Extracts the 3rdparty libraries for the module ${module_name}
# and stores the information in cmake language in
# ${output_root_dir}/$<CONFIG>/${output_file_name}.
#
# This function "follows" INTERFACE_LIBRARY targets to "real" targets
# and collects defines, include dirs and lib dirs on the way.
function(qt_get_qmake_libraries_pri_content out_var module_name)
function(qt_generate_qmake_libraries_pri_content module_name output_root_dir output_file_name)
set(content "")
# Set up a regular expression that matches all implicit include dirs
@ -665,25 +666,24 @@ function(qt_get_qmake_libraries_pri_content out_var module_name)
string(PREPEND lib_incdir "$<FILTER:")
string(APPEND lib_incdir ",EXCLUDE,${implicit_include_dirs_regex}>")
# Wrap in $<JOIN:..., > to create qmake-style lists.
foreach(sfx libs libdir incdir defines)
string(PREPEND lib_${sfx} "$<JOIN:")
string(APPEND lib_${sfx} ", >")
endforeach()
string(APPEND content "QMAKE_LIBS_${uclib} = ${lib_libs}
QMAKE_LIBDIR_${uclib} = ${lib_libdir}
QMAKE_INCDIR_${uclib} = ${lib_incdir}
QMAKE_DEFINES_${uclib} = ${lib_defines}
set(uccfg $<UPPER_CASE:$<CONFIG>>)
string(APPEND content "list(APPEND known_libs ${uclib})
set(QMAKE_LIBS_${uclib}_${uccfg} \"${lib_libs}\")
set(QMAKE_LIBDIR_${uclib}_${uccfg} \"${lib_libdir}\")
set(QMAKE_INCDIR_${uclib}_${uccfg} \"${lib_incdir}\")
set(QMAKE_DEFINES_${uclib}_${uccfg} \"${lib_defines}\")
")
if(QT_QMAKE_LIB_DEPS_${lib})
list(JOIN QT_QMAKE_LIB_DEPS_${lib} " " deps)
string(APPEND content "QMAKE_DEPENDS_${uclib}_CC = ${deps}
QMAKE_DEPENDS_${uclib}_LD = ${deps}
string(APPEND content "set(QMAKE_DEPENDS_${uclib}_CC, ${deps})
set(QMAKE_DEPENDS_${uclib}_LD, ${deps})
")
endif()
endforeach()
set(${out_var} "${content}" PARENT_SCOPE)
file(GENERATE
OUTPUT "${output_root_dir}/$<CONFIG>/${output_file_name}"
CONTENT "${content}"
)
endfunction()
# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module.
@ -849,15 +849,11 @@ QT_MODULES += ${config_module_name}
)
endif()
qt_path_join(private_pri_file "${target_path}" "qt_lib_${config_module_name}_private.pri")
list(APPEND pri_files "${private_pri_file}")
set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake")
qt_generate_qmake_libraries_pri_content(${config_module_name} "${CMAKE_CURRENT_BINARY_DIR}"
${pri_data_cmake_file})
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
### FIXME QTBUG-84348
set(libraries_content "")
else()
qt_get_qmake_libraries_pri_content(libraries_content ${config_module_name})
endif()
set(private_pri_file_name "qt_lib_${config_module_name}_private.pri")
set(private_module_dependencies "")
if(NOT arg_HEADER_MODULE)
@ -865,8 +861,9 @@ QT_MODULES += ${config_module_name}
endif()
list(JOIN private_module_dependencies " " private_module_dependencies)
# Generate a preliminary qt_lib_XXX_private.pri file
file(GENERATE
OUTPUT "${private_pri_file}"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}"
CONTENT
"QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION}
QT.${config_module_name}_private.name = ${module}
@ -878,10 +875,34 @@ QT.${config_module_name}_private.depends = ${private_module_dependencies}
QT.${config_module_name}_private.uses =
QT.${config_module_name}_private.module_config = ${joined_module_internal_config}
QT.${config_module_name}_private.enabled_features = ${enabled_private_features}
QT.${config_module_name}_private.disabled_features = ${disabled_private_features}
${libraries_content}"
QT.${config_module_name}_private.disabled_features = ${disabled_private_features}"
)
if(QT_GENERATOR_IS_MULTI_CONFIG)
set(configs ${CMAKE_CONFIGURATION_TYPES})
else()
set(configs ${CMAKE_BUILD_TYPE})
endif()
set(inputs "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}")
foreach(cfg ${configs})
list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/${pri_data_cmake_file}")
endforeach()
qt_path_join(private_pri_file_path "${target_path}" "${private_pri_file_name}")
list(APPEND pri_files "${private_pri_file_path}")
add_custom_command(
OUTPUT "${private_pri_file_path}"
DEPENDS ${inputs}
COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${private_pri_file_path}"
"-DCONFIGS=${configs}"
-P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
VERBATIM)
add_custom_target(${target}_lib_pri DEPENDS "${private_pri_file_path}")
if(arg_HEADER_MODULE)
add_dependencies(${target}_timestamp ${target}_lib_pri)
else()
add_dependencies(${target} ${target}_lib_pri)
endif()
qt_install(FILES "${pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules)
endfunction()
@ -1145,13 +1166,35 @@ CONFIG += ${private_config_joined}
string(REPLACE ";" " " build_parts "${build_parts}")
string(APPEND content "QT_BUILD_PARTS = ${build_parts}\n")
qt_get_qmake_libraries_pri_content(libraries_content global)
string(APPEND content "${libraries_content}")
set(preliminary_pri_root "${CMAKE_CURRENT_BINARY_DIR}/mkspecs/preliminary")
set(pri_data_cmake_file "qmodule.cmake")
qt_generate_qmake_libraries_pri_content(global ${preliminary_pri_root} ${pri_data_cmake_file})
# Generate a preliminary qmodule.pri file
set(preliminary_pri_file_path "${preliminary_pri_root}/qmodule.pri")
file(GENERATE
OUTPUT "${qmodule_pri_target_path}"
OUTPUT ${preliminary_pri_file_path}
CONTENT "${content}"
)
if(QT_GENERATOR_IS_MULTI_CONFIG)
set(configs ${CMAKE_CONFIGURATION_TYPES})
else()
set(configs ${CMAKE_BUILD_TYPE})
endif()
set(inputs ${preliminary_pri_file_path})
foreach(cfg ${configs})
list(APPEND inputs "${preliminary_pri_root}/${cfg}/${pri_data_cmake_file}")
endforeach()
add_custom_command(
OUTPUT "${qmodule_pri_target_path}"
DEPENDS ${inputs}
COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${qmodule_pri_target_path}"
"-DCONFIGS=${configs}"
-P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake"
VERBATIM)
add_custom_target(qmodule_pri DEPENDS "${qmodule_pri_target_path}")
qt_install(FILES "${qmodule_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR})
endfunction()
@ -2468,6 +2511,14 @@ function(qt_add_module target)
set(header_module)
if(arg_HEADER_MODULE)
set(header_module "HEADER_MODULE")
# Provide a *_timestamp target that can be used to trigger the build of custom_commands.
set(timestamp_file "${CMAKE_CURRENT_BINARY_DIR}/timestamp")
add_custom_command(OUTPUT "${timestamp_file}"
COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}"
DEPENDS ${module_headers_public}
VERBATIM)
add_custom_target(${target}_timestamp ALL DEPENDS "${timestamp_file}")
endif()
qt_extend_target("${target}"

View File

@ -0,0 +1,84 @@
# Generate a qt_lib_XXX.pri file.
#
# This file is to be used in CMake script mode with the following variables set:
# IN_FILES: path to the qt_lib_XXX.cmake files
# OUT_FILE: path to the generated qt_lib_XXX.pri file
# CONFIGS: the configurations Qt is being built with
#
# QMAKE_LIBS_XXX values are split into QMAKE_LIBS_XXX_DEBUG and QMAKE_LIBS_XXX_RELEASE if
# debug_and_release was detected. The CMake configuration "Debug" is considered for the _DEBUG
# values. The first config that is not "Debug" is treated as _RELEASE.
cmake_policy(SET CMP0057 NEW)
# Create a qmake-style list from the passed arguments and store it in ${out_var}.
function(qmake_list out_var)
set(result "")
# Surround values that contain spaces with double quotes.
foreach(v ${ARGN})
if(v MATCHES " ")
set(v "\"${v}\"")
endif()
list(APPEND result ${v})
endforeach()
list(JOIN result " " result)
set(${out_var} ${result} PARENT_SCOPE)
endfunction()
list(POP_FRONT IN_FILES in_pri_file)
file(READ ${in_pri_file} content)
string(APPEND content "\n")
foreach(in_file ${IN_FILES})
include(${in_file})
endforeach()
list(REMOVE_DUPLICATES known_libs)
set(is_debug_and_release FALSE)
if("Debug" IN_LIST CONFIGS AND ("Release" IN_LIST CONFIGS OR "RelWithDebInfo" IN_LIST CONFIGS))
set(is_debug_and_release TRUE)
set(release_configs ${CONFIGS})
list(REMOVE_ITEM release_configs "Debug")
list(GET release_configs 0 release_cfg)
string(TOUPPER "${release_cfg}" release_cfg)
endif()
foreach(lib ${known_libs})
set(configuration_independent_infixes LIBDIR INCDIR DEFINES)
if(is_debug_and_release)
set(value_debug ${QMAKE_LIBS_${lib}_DEBUG})
set(value_release ${QMAKE_LIBS_${lib}_${release_cfg}})
if(value_debug STREQUAL value_release)
if(value_debug)
qmake_list(value_debug ${value_debug})
string(APPEND content "QMAKE_LIBS_${lib} = ${value_debug}\n")
endif()
else()
if(value_debug)
qmake_list(value_debug ${value_debug})
string(APPEND content "QMAKE_LIBS_${lib}_DEBUG = ${value_debug}\n")
endif()
if(value_release)
qmake_list(value_release ${value_release})
string(APPEND content "QMAKE_LIBS_${lib}_RELEASE = ${value_release}\n")
endif()
endif()
else()
list(APPEND configuration_independent_infixes LIBS)
endif()
# The remaining values are considered equal for all configurations.
# Pick the first configuration and use its values.
list(GET CONFIGS 0 cfg)
string(TOUPPER ${cfg} cfg)
foreach(infix ${configuration_independent_infixes})
set(value ${QMAKE_${infix}_${lib}_${cfg}})
if(value)
qmake_list(value ${value})
string(APPEND content "QMAKE_${infix}_${lib} = ${value}\n")
endif()
endforeach()
endforeach()
file(WRITE "${OUT_FILE}" "${content}")

View File

@ -259,6 +259,7 @@ qt_add_module(Core
)
# special case begin
add_dependencies(Core qmodule_pri)
add_dependencies(Core ${QT_CMAKE_EXPORT_NAMESPACE}::moc)
add_dependencies(Core ${QT_CMAKE_EXPORT_NAMESPACE}::rcc)
add_dependencies(CorePrivate ${QT_CMAKE_EXPORT_NAMESPACE}::moc)