# # SPDX-FileCopyrightText: 2021 Arjen Hiemstra # # 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 "") string(APPEND _qrc_template "\n\n") string(APPEND _qrc_template "\n${_qmldir_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}") endforeach() string(APPEND _qrc_template "\n\n\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 \n#include \n void initQmlResource${ARG_TARGET}() {Q_INIT_RESOURCE(${ARG_TARGET}); qWarning()< ${_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()