Files
RedBear-OS/local/recipes/kde/kf6-extra-cmake-modules/source/modules/ECMQmlModule5.cmake
T
2026-04-14 10:51:06 +01:00

340 lines
14 KiB
CMake

#
# SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause
# Qt 5 implementation of ECMQmlModule
set(_ECM_QMLMODULE_STATIC_QMLONLY_H "${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule.h.in")
set(_ECM_QMLMODULE_STATIC_QMLONLY_CPP "${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule.cpp.in")
set(_ECM_QMLMODULE_PROPERTY_URI "_ecm_qml_uri")
set(_ECM_QMLMODULE_PROPERTY_QMLDIR "_ecm_qmldir_file")
set(_ECM_QMLMODULE_PROPERTY_FILES "_ecm_qml_files")
set(_ECM_QMLMODULE_PROPERTY_QMLONLY "_ecm_qml_only")
set(_ECM_QMLMODULE_PROPERTY_VERSION "_ecm_qml_version")
set(_ECM_QMLMODULE_PROPERTY_PRIVATE "_ecm_qml_private")
set(_ECM_QMLMODULE_PROPERTY_PATH "_ecm_qml_path")
set(_ECM_QMLMODULE_PROPERTY_CLASSNAME "_ecm_qml_classname")
set(_ECM_QMLMODULE_PROPERTY_DEPENDS "_ecm_qml_depends")
macro(_ecm_qmlmodule_verify_qml_target ARG_TARGET)
if (NOT TARGET ${ARG_TARGET})
message(FATAL_ERROR "Target ${ARG_TARGET} does not exist")
endif()
get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
if ("${_qml_uri}" STREQUAL "" OR "${_qml_uri}" STREQUAL "${_ECM_QMLMODULE_PROPERTY_URI}-NOTFOUND")
message(FATAL_ERROR "Target ${ARG_TARGET} is not a QML plugin target")
endif()
endmacro()
function(_ecm_qmlmodule_generate_qmldir ARG_TARGET)
get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
get_target_property(_qml_only ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLONLY})
get_target_property(_qml_classname ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_CLASSNAME})
set(_qmldir_template "# This file was automatically generated by ECMQmlModule and should not be modified")
string(APPEND _qmldir_template "\nmodule ${_qml_uri}")
if (NOT ${_qml_only})
string(APPEND _qmldir_template "\nplugin ${ARG_TARGET}")
if ("${_qml_classname}" STREQUAL "")
string(APPEND _qmldir_template "\nclassname ${ARG_TARGET}")
else()
string(APPEND _qmldir_template "\nclassname ${_qml_classname}")
endif()
endif()
get_target_property(_qml_depends ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_DEPENDS})
if (NOT "${_qml_depends}" STREQUAL "")
foreach(_depends ${_qml_depends})
string(APPEND _qmldir_template "\ndepends ${_depends}")
endforeach()
endif()
foreach(_file ${_qml_files})
get_filename_component(_filename ${_file} NAME)
get_filename_component(_classname ${_file} NAME_WE)
get_property(_version SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_VERSION})
get_property(_private SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PRIVATE})
get_property(_singleton SOURCE ${_file} PROPERTY "QT_QML_SINGLETON_TYPE")
get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})
cmake_path(SET _actual_path "${_path}")
cmake_path(APPEND _actual_path "${_filename}")
if (_singleton)
string(APPEND _qmldir_template "\nsingleton ${_classname} ${_version} ${_actual_path}")
else()
if (NOT _private)
string(APPEND _qmldir_template "\n${_classname} ${_version} ${_actual_path}")
else()
string(APPEND _qmldir_template "\ninternal ${_classname} ${_actual_path}")
endif()
endif()
endforeach()
get_target_property(_qml_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})
string(APPEND _qmldir_template "\n# KDE-qmldir-Version: ${_qml_version}")
string(APPEND _qmldir_template "\n")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}_qmldir" "${_qmldir_template}")
set_target_properties(${ARG_TARGET} PROPERTIES _ecm_qmldir_file "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}_qmldir")
endfunction()
function(_ecm_qmlmodule_generate_qrc ARG_TARGET)
get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
get_target_property(_qmldir_file ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLDIR})
get_target_property(_qml_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})
_ecm_qmlmodule_uri_to_path(_qml_prefix "${_qml_uri}" "${_qml_version}")
set(_qrc_template "<!-- This file was automatically generated by ECMQmlModule and should not be modified -->")
string(APPEND _qrc_template "\n<RCC>\n<qresource prefix=\"/qt-project.org/imports/${_qml_prefix}\">")
string(APPEND _qrc_template "\n<file alias=\"qmldir\">${_qmldir_file}</file>")
foreach(_file ${_qml_files})
get_filename_component(_filename ${_file} NAME)
get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})
set(_file_path "${_filename}")
if (NOT "${_path}" STREQUAL "")
set(_file_path "${_path}/${_filename}")
endif()
string(APPEND _qrc_template "\n<file alias=\"${_file_path}\">${_file}</file>")
endforeach()
string(APPEND _qrc_template "\n</qresource>\n</RCC>\n")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}.qrc" "${_qrc_template}")
qt_add_resources(_qrc_output "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}.qrc")
target_sources(${ARG_TARGET} PRIVATE ${_qrc_output})
endfunction()
function(ecm_add_qml_module ARG_TARGET)
cmake_parse_arguments(PARSE_ARGV 1 ARG "NO_PLUGIN" "URI;VERSION;CLASSNAME" "")
if ("${ARG_TARGET}" STREQUAL "")
message(FATAL_ERROR "ecm_add_qml_module called without a valid target name.")
endif()
if ("${ARG_URI}" STREQUAL "")
message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
endif()
string(FIND "${ARG_URI}" " " "_space")
if (${_space} GREATER_EQUAL 0)
message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
endif()
if (${BUILD_SHARED_LIBS} AND ${ARG_NO_PLUGIN})
# CMake doesn't like library targets without sources, so if we have no
# C++ sources, use a plain target that we can add all the install stuff
# to.
add_custom_target(${ARG_TARGET} ALL)
else()
add_library(${ARG_TARGET})
endif()
if (NOT ARG_VERSION)
set(ARG_VERSION "1.0")
endif()
set_target_properties(${ARG_TARGET} PROPERTIES
${_ECM_QMLMODULE_PROPERTY_URI} "${ARG_URI}"
${_ECM_QMLMODULE_PROPERTY_FILES} ""
${_ECM_QMLMODULE_PROPERTY_QMLONLY} "${ARG_NO_PLUGIN}"
${_ECM_QMLMODULE_PROPERTY_VERSION} "${ARG_VERSION}"
${_ECM_QMLMODULE_PROPERTY_CLASSNAME} "${ARG_CLASSNAME}"
${_ECM_QMLMODULE_PROPERTY_DEPENDS} ""
)
# QQmlImportDatabase::resolvePlugin doesn't accept lib prefixes under
# Windows, causing to fail to import when using as a dynamic plugin.
if (MINGW)
set_target_properties(${ARG_TARGET} PROPERTIES PREFIX "")
endif()
# -Muri is required for static QML plugins to work properly, see
# https://bugreports.qt.io/browse/QTBUG-82598
set_target_properties(${ARG_TARGET} PROPERTIES AUTOMOC_MOC_OPTIONS -Muri=${ARG_URI})
endfunction()
function(ecm_add_qml_module_dependencies ARG_TARGET)
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "" "DEPENDS")
_ecm_qmlmodule_verify_qml_target(${ARG_TARGET})
if ("${ARG_DEPENDS}" STREQUAL "")
message(FATAL_ERROR "ecm_add_qml_module_dependencies called without required argument DEPENDS")
endif()
set_target_properties(${ARG_TARGET} PROPERTIES ${_ECM_QMLMODULE_PROPERTY_DEPENDS} "${ARG_DEPENDS}")
endfunction()
function(ecm_target_qml_sources ARG_TARGET)
cmake_parse_arguments(PARSE_ARGV 1 ARG "PRIVATE" "VERSION;PATH" "SOURCES")
_ecm_qmlmodule_verify_qml_target(${ARG_TARGET})
if ("${ARG_SOURCES}" STREQUAL "")
message(FATAL_ERROR "ecm_target_qml_sources called without required argument SOURCES")
endif()
if ("${ARG_VERSION}" STREQUAL "")
get_target_property(ARG_VERSION ${ARG_TARGET} "_ecm_qml_version")
endif()
# In case we have not specified a version in add_qml_module, we use 1.0 as a default for the individual QML files
if (NOT ARG_VERSION)
set(ARG_VERSION "1.0")
endif()
foreach(_file ${ARG_SOURCES})
# Check if a given file exists, but only for files that are not
# automatically generated.
set(_path "${_file}")
get_source_file_property(_generated ${_file} GENERATED)
if (NOT _generated)
if (IS_ABSOLUTE ${_path})
# Assume absolute paths are generated, which may not always be
# true but is fairly likely.
set(_generated TRUE)
else()
string(FIND ${_file} ${CMAKE_BINARY_DIR} _in_binary_dir)
if (${_in_binary_dir} GREATER_EQUAL 0)
# Assume anything in binary dir is generated.
set(_generated TRUE)
else()
set(_path "${CMAKE_CURRENT_SOURCE_DIR}/${_file}")
endif()
endif()
endif()
if (NOT ${_generated} AND NOT EXISTS ${_path})
message(FATAL_ERROR "ecm_target_qml_sources called with nonexistent file ${_file}")
endif()
set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_VERSION} "${ARG_VERSION}")
if (ARG_PRIVATE)
set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PRIVATE} TRUE)
endif()
set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH} "${ARG_PATH}")
set_property(TARGET ${ARG_TARGET}
APPEND PROPERTY ${_ECM_QMLMODULE_PROPERTY_FILES} ${_path}
)
endforeach()
endfunction()
function(ecm_finalize_qml_module ARG_TARGET)
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "DESTINATION" "")
_ecm_qmlmodule_verify_qml_target(${ARG_TARGET})
if (NOT ARG_DESTINATION)
set(ARG_DESTINATION "${KDE_INSTALL_QMLDIR}")
endif()
if ("${ARG_DESTINATION}" STREQUAL "")
message(FATAL_ERROR "ecm_finalize_qml_module called without argument DESTINATION and KDE_INSTALL_QMLDIR is not set")
endif()
get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
get_target_property(_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})
_ecm_qmlmodule_generate_qmldir(${ARG_TARGET})
_ecm_qmlmodule_uri_to_path(_plugin_path "${_qml_uri}" "${_version}")
get_target_property(_qml_only ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLONLY})
if (NOT BUILD_SHARED_LIBS)
_ecm_qmlmodule_generate_qrc(${ARG_TARGET})
set(CPP_RESOURCE_INIT "#include <qglobal.h> \n#include <QDebug> \n void initQmlResource${ARG_TARGET}() {Q_INIT_RESOURCE(${ARG_TARGET}); qWarning()<<Q_FUNC_INFO;};")
file(WRITE ${ARG_TARGET}_init.cpp "${CPP_RESOURCE_INIT}")
target_sources(${ARG_TARGET} PRIVATE ${ARG_TARGET}_init.cpp)
target_compile_definitions(${ARG_TARGET} PRIVATE -DQT_PLUGIN_RESOURCE_INIT_FUNCTION=initQmlResource${ARG_TARGET} -DQT_STATICPLUGIN=1)
if (${_qml_only})
# If we do not have any C++ sources for the target, we need a way to
# compile the generated QRC file. So generate a very plain C++ QML
# plugin that we include in the target.
configure_file(${_ECM_QMLMODULE_STATIC_QMLONLY_H} ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.h @ONLY)
configure_file(${_ECM_QMLMODULE_STATIC_QMLONLY_CPP} ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.cpp @ONLY)
target_sources(${ARG_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.cpp)
if (TARGET Qt::Qml)
target_link_libraries(${ARG_TARGET} PRIVATE Qt::Qml)
else()
target_link_libraries(${ARG_TARGET} PRIVATE Qt5::Qml)
endif()
endif()
install(TARGETS ${ARG_TARGET} DESTINATION ${ARG_DESTINATION}/${_plugin_path})
return()
endif()
get_target_property(_runtime_output_dir ${ARG_TARGET} RUNTIME_OUTPUT_DIRECTORY)
if (NOT ${_runtime_output_dir})
if ("${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" STREQUAL "")
set(_runtime_output_dir ${CMAKE_CURRENT_BINARY_DIR})
else()
set(_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
endif()
endif()
add_custom_command(
TARGET ${ARG_TARGET}
POST_BUILD
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${_runtime_output_dir}/${_plugin_path}
BYPRODUCTS ${_runtime_output_dir}/${_plugin_path}
)
get_target_property(_qmldir_file ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLDIR})
install(FILES ${_qmldir_file} DESTINATION ${ARG_DESTINATION}/${_plugin_path} RENAME "qmldir")
add_custom_command(
TARGET ${ARG_TARGET}
POST_BUILD
WORKING_DIRECTORY ${_runtime_output_dir}
COMMAND ${CMAKE_COMMAND} -E copy ${_qmldir_file} ${_plugin_path}/qmldir
)
if (NOT ${_qml_only})
install(TARGETS ${ARG_TARGET} DESTINATION ${ARG_DESTINATION}/${_plugin_path})
add_custom_command(
TARGET ${ARG_TARGET}
POST_BUILD
WORKING_DIRECTORY ${_runtime_output_dir}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${ARG_TARGET}> ${_plugin_path}
)
endif()
get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
foreach(_file ${_qml_files})
get_filename_component(_filename ${_file} NAME)
get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})
set(_file_path "${_plugin_path}/")
if (NOT "${_path}" STREQUAL "")
set(_file_path "${_plugin_path}/${_path}/")
endif()
install(FILES ${_file} DESTINATION ${ARG_DESTINATION}/${_file_path})
add_custom_command(
TARGET ${ARG_TARGET}
POST_BUILD
WORKING_DIRECTORY ${_runtime_output_dir}
COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_path}
COMMAND ${CMAKE_COMMAND} -E copy ${_file} ${_file_path}
BYPRODUCTS ${_file_path}/${_filename}
)
endforeach()
endfunction()