qtutilities/cmake/modules/QtLinkage.cmake

212 lines
8.6 KiB
CMake

cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR)
# defines helper to link against Qt dynamically or statically
# prevent multiple inclusion
if (DEFINED QT_LINKAGE_DETERMINED)
return()
endif ()
set(QT_LINKAGE_DETERMINED ON)
# include validate_visibility from c++utilities' 3rdParty module
include(3rdParty)
# determine the minimum Qt version
if (NOT META_QT_VERSION)
if (META_QT5_VERSION)
# use deprecated META_QT5_VERSION variable (for compatibility)
set(META_QT_VERSION "${META_QT5_VERSION}")
else ()
# require Qt 5.6 or higher by default
set(META_QT_VERSION 5.6)
endif ()
endif ()
# avoid "add_custom_target cannot create target "apk" because another target…" errors produced by Qt's Android support module
# (which can not cope with Qt CMake modules already pulled in by a dependency)
if (ANDROID AND NOT ${PROJECT_NAME}-MultiAbiBuild)
set(${PROJECT_NAME}-MultiAbiBuild ON)
endif ()
# define function for using Qt and KDE Frameworks modules and static plugins
macro (use_qt_module)
# parse arguments
set(OPTIONAL_ARGS ONLY_PLUGINS)
set(ONE_VALUE_ARGS PREFIX MODULE VISIBILITY LIBRARIES_VARIABLE)
set(MULTI_VALUE_ARGS TARGETS PLUGINS)
cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
# validate values
if (NOT ARGS_PREFIX)
message(FATAL_ERROR "use_qt_module called without PREFIX.")
endif ()
if (NOT ARGS_MODULE)
message(FATAL_ERROR "use_qt_module called without MODULE.")
endif ()
if (ARGS_VISIBILITY)
validate_visibility(${ARGS_VISIBILITY})
else ()
set(ARGS_VISIBILITY PRIVATE)
endif ()
if (NOT ARGS_LIBRARIES_VARIABLE)
set(ARGS_LIBRARIES_VARIABLE "${ARGS_VISIBILITY}_LIBRARIES")
endif ()
if (NOT ARGS_TARGETS)
if (${MODULE}_MODULE_TARGETS)
set(ARGS_TARGETS "${${MODULE}_MODULE_TARGETS}")
else ()
set(ARGS_TARGETS "${ARGS_PREFIX}::${ARGS_MODULE}")
endif ()
endif ()
if (ARGS_ONLY_PLUGINS AND NOT ARGS_PLUGINS)
message(FATAL_ERROR "ONLY_PLUGINS specified but no plugins.")
endif ()
# find and use module
if (NOT ONLY_PLUGINS)
find_package("${ARGS_PREFIX}${ARGS_MODULE}" "${META_QT_VERSION}" REQUIRED)
foreach (TARGET ${ARGS_TARGETS})
if (NOT TARGET "${TARGET}")
message(FATAL_ERROR "The ${ARGS_PREFIX}${ARGS_MODULE} does not provide the target ${TARGET}.")
endif ()
if ("${TARGET}" IN_LIST "${ARGS_LIBRARIES_VARIABLE}")
continue()
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${TARGET}")
set("PKG_CONFIG_${ARGS_PREFIX}_${ARGS_MODULE}" "${ARGS_PREFIX}${ARGS_MODULE}")
message(STATUS "Linking ${META_TARGET_NAME} against Qt module ${TARGET}.")
# hack for "StaticQt5": re-assign INTERFACE_LINK_LIBRARIES_RELEASE to INTERFACE_LINK_LIBRARIES
get_target_property("${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE" "${TARGET}"
INTERFACE_LINK_LIBRARIES_RELEASE)
if ("${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE")
set_target_properties("${TARGET}" PROPERTIES INTERFACE_LINK_LIBRARIES
"${${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE}")
endif ()
endforeach ()
endif ()
# find and use plugins
foreach (PLUGIN ${ARGS_PLUGINS})
set(PLUGIN_TARGET "${ARGS_PREFIX}::Q${PLUGIN}Plugin")
if (NOT TARGET "${PLUGIN_TARGET}")
find_package("${ARGS_PREFIX}${ARGS_MODULE}" "${META_QT_VERSION}" REQUIRED)
endif ()
if (NOT TARGET "${PLUGIN_TARGET}"
AND PLUGIN MATCHES "Svg.*"
AND ARGS_MODULE STREQUAL "Svg")
# look for Svg plugins within the Gui module's directory as well
find_package("${ARGS_PREFIX}Gui" "${META_QT_VERSION}" REQUIRED)
set(PLUGIN_CONFIG "${${ARGS_PREFIX}Gui_DIR}/${ARGS_PREFIX}Q${PLUGIN}PluginConfig.cmake")
if (EXISTS "${PLUGIN_CONFIG}")
include("${PLUGIN_CONFIG}")
endif ()
endif ()
if (NOT TARGET "${PLUGIN_TARGET}")
message(
FATAL_ERROR
"The ${ARGS_PREFIX}${ARGS_MODULE} package does not provide the target ${ARGS_PREFIX}::Q${PLUGIN}Plugin.")
endif ()
if ("${PLUGIN_TARGET}" IN_LIST "${ARGS_LIBRARIES_VARIABLE}")
continue()
endif ()
set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_PREFIX}::Q${PLUGIN}Plugin")
message(STATUS "Linking ${META_TARGET_NAME} against Qt plugin ${ARGS_PREFIX}::Q${PLUGIN}Plugin.")
endforeach ()
# unset variables (can not simply use a function because Qt's variables need to be exported)
foreach (ARGUMENT ${OPTIONAL_ARGS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
unset(ARGS_${ARGUMENT})
endforeach ()
endmacro ()
# define function to make Qt variable available; queries qmake or uses variables provided by Qt 6
function (query_qmake_variable QMAKE_VARIABLE)
# prevent queries for variables already known
if (NOT "${${QMAKE_VARIABLE}}" STREQUAL "")
return()
endif ()
# check configuration variables provided by Qt 6
if (QMAKE_VARIABLE MATCHES "QT_(.*)")
set(VARIABLE_NAME "${CMAKE_MATCH_1}")
if (QT6_${VARIABLE_NAME})
set(VARIABLE_NAME QT6_${VARIABLE_NAME})
endif ()
if (NOT "${${VARIABLE_NAME}}" STREQUAL "")
set("${QMAKE_VARIABLE}"
"${${VARIABLE_NAME}}"
PARENT_SCOPE)
message(STATUS "Qt variable ${QMAKE_VARIABLE} taken from ${VARIABLE_NAME}: ${${VARIABLE_NAME}}")
return()
endif ()
endif ()
# execute qmake
get_target_property(QMAKE_BIN "${QT_QMAKE_TARGET}" IMPORTED_LOCATION)
execute_process(
COMMAND "${QMAKE_BIN}" -query "${QMAKE_VARIABLE}"
RESULT_VARIABLE "${QMAKE_VARIABLE}_RESULT"
OUTPUT_VARIABLE "${QMAKE_VARIABLE}")
if (NOT "${${QMAKE_VARIABLE}_RESULT}" STREQUAL 0 OR "${${QMAKE_VARIABLE}}" STREQUAL "")
message(
FATAL_ERROR
"Unable to read qmake variable ${QMAKE_VARIABLE} via \"${QMAKE_BIN} -query ${QMAKE_VARIABLE}\"; output was \"${${QMAKE_VARIABLE}}\"."
)
endif ()
# remove new-line character at the end
string(REGEX REPLACE "\n$" "" "${QMAKE_VARIABLE}" "${${QMAKE_VARIABLE}}")
# export variable to parent scope
set("${QMAKE_VARIABLE}"
"${${QMAKE_VARIABLE}}"
PARENT_SCOPE)
message(STATUS "Qt variable ${QMAKE_VARIABLE} queried from qmake: ${${QMAKE_VARIABLE}}")
endfunction ()
# define function to make Qt variable available, resolving relative paths via CMAKE_FIND_ROOT_PATH
function (query_qmake_variable_path QMAKE_VARIABLE)
# query the variable itself
query_qmake_variable("${QMAKE_VARIABLE}")
set(VARIABLE_VALUE "${${QMAKE_VARIABLE}}")
if (NOT VARIABLE_VALUE)
message(WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE}: it is empty")
return()
endif ()
# pass the variable as-is if it points to an existing dir/file
if (EXISTS "${VARIABLE_VALUE}")
get_filename_component(VARIABLE_VALUE "${VARIABLE_VALUE}" REALPATH)
message(STATUS "Qt variable ${QMAKE_VARIABLE} resolved to path: ${VARIABLE_VALUE}")
set("${QMAKE_VARIABLE}"
"${VARIABLE_VALUE}"
PARENT_SCOPE)
return()
endif ()
# assume VARIABLE_VALUE is relative within CMAKE_FIND_ROOT_PATH, e.g. QT_INSTALL_TRANSLATIONS might be set to
# "share/qt6/translations"
if ("${CMAKE_VERSION}" VERSION_LESS "3.12.0")
message(
WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE} to an existing path, try using CMake 3.12 or newer")
return() # skip if CMake version too old like on Leap 15.1
endif ()
foreach (ROOT_PATH ${CMAKE_FIND_ROOT_PATH} "")
foreach (PREFIX_PATH ${CMAKE_PREFIX_PATH} "")
string(JOIN "/" FULL_PATH ${ROOT_PATH} ${PREFIX_PATH} ${VARIABLE_VALUE})
if (EXISTS "${FULL_PATH}")
set("${QMAKE_VARIABLE}"
"${FULL_PATH}"
PARENT_SCOPE)
message(STATUS "Qt variable ${QMAKE_VARIABLE} resolved to path: ${FULL_PATH}")
return()
else ()
list(APPEND CHECKED_PATHS "${FULL_PATH}")
endif ()
endforeach ()
endforeach ()
message(
WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE} to an existing path, was checking for: ${CHECKED_PATHS}")
endfunction ()