# # All things resource related # function(__qt_get_relative_resource_path_for_file output_alias file) get_property(alias SOURCE ${file} PROPERTY QT_RESOURCE_ALIAS) if (NOT alias) set(alias "${file}") endif() set(${output_alias} ${alias} PARENT_SCOPE) endfunction() function(__qt_propagate_generated_resource target resource_name generated_source_code output_generated_target) get_target_property(type ${target} TYPE) if(type STREQUAL STATIC_LIBRARY) set(resource_target "${target}_resources_${resourceName}") add_library("${resource_target}" OBJECT "${generated_source_code}") # Use TARGET_NAME genex to map to the correct prefixed target name when it is exported # via qt_install(EXPORT), so that the consumers of the target can find the object library # as well. target_link_libraries(${target} INTERFACE "$>") set(${output_generated_target} "${resource_target}" PARENT_SCOPE) else() set(${output_generated_target} "" PARENT_SCOPE) target_sources(${target} PRIVATE ${generated_source_code}) endif() endfunction() # Inspect all files passed to a call to add_qt_resource. If there are any # files present, invoke the quick compiler and return the remaining resource # files that have not been processed in OUTPUT_REMAINING_RESOURCES as well as the new # name for the resource in OUTPUT_RESOURCE_NAME. function(__qt_quick_compiler_process_resources target resource_name) cmake_parse_arguments(arg "" "PREFIX;OUTPUT_REMAINING_RESOURCES;OUTPUT_RESOURCE_NAME;OUTPUT_GENERATED_TARGET" "FILES" ${ARGN} ) set(qml_files) set(resource_files) set(retained_files) # scan for qml files foreach(file IN LISTS arg_FILES) # check whether this resource should not be processed by the qt quick # compiler get_source_file_property(skip_compiler_check ${file} QT_SKIP_QUICKCOMPILER) get_source_file_property(retain_compiler_check ${file} QT_RETAIN_QUICKCOMPILER) if (skip_compiler_check) list(APPEND resource_files ${file}) continue() endif() if (${file} MATCHES "\.js$" OR ${file} MATCHES "\.mjs$" OR ${file} MATCHES "\.qml$") list(APPEND qml_files ${file}) if (retain_compiler_check) list(APPEND retained_files ${file}) list(APPEND resource_files ${file}) endif() else() list(APPEND resource_files ${file}) endif() endforeach() if (NOT TARGET @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen AND qml_files) message(WARNING "QT@PROJECT_VERSION_MAJOR@_PROCESS_RESOURCE: Qml files were detected but the qmlcachgen target is not defined. Consider adding QmlTools to your find_package command.") endif() set(retained_resource_paths) if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen AND qml_files) # Enable qt quick compiler support set(qml_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${resource_name}.qrc") if (resource_files) set(chained_resource_name "${resource_name}_qmlcache") endif() foreach(file IN LISTS qml_files) get_filename_component(file_absolute ${file} ABSOLUTE) file(RELATIVE_PATH file_relative ${CMAKE_CURRENT_SOURCE_DIR} ${file_absolute}) __qt_get_relative_resource_path_for_file(file_resource_path ${file}) if (arg_PREFIX STREQUAL "/") # TO_CMAKE_PATH does not clean up cases such as //Foo set(file_resource_path "/${file_resource_path}") else() set(file_resource_path "${arg_PREFIX}/${file_resource_path}") endif() if (file IN_LIST retained_files) list(APPEND retained_resource_paths ${file_resource_path}) endif() file(TO_CMAKE_PATH ${file_resource_path} file_resource_path) list(APPEND file_resource_paths ${file_resource_path}) string(REGEX REPLACE "\.js$" "_js" compiled_file ${file_relative}) string(REGEX REPLACE "\.mjs$" "_mjs" compiled_file ${compiled_file}) string(REGEX REPLACE "\.qml$" "_qml" compiled_file ${compiled_file}) string(REGEX REPLACE "[\$#\?]+" "_" compiled_file ${compiled_file}) set(compiled_file "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${resource_name}/${compiled_file}.cpp") add_custom_command( OUTPUT ${compiled_file} DEPENDS ${file_absolute} COMMAND @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen --resource-path ${file_resource_path} -o ${compiled_file} ${file_absolute} ) target_sources(${target} PRIVATE ${compiled_file}) endforeach() set(qmlcache_loader_list "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${resource_name}/qml_loader_file_list.rsp") file(GENERATE OUTPUT ${qmlcache_loader_list} CONTENT "$" ) set(qmlcache_loader_file "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${resource_name}/qmlcache_loader.cpp") set(resource_name_arg "${resource_name}.qrc") if (chained_resource_name) set(resource_name_arg "${resource_name_arg}=${chained_resource_name}") endif() if (retained_resource_paths) set(retained_loader_list "${CMAKE_CURRENT_BINARY_DIR}/qmlcache/${resource_name}/retained_file_list.rsp") file(GENERATE OUTPUT ${retained_loader_list} CONTENT "$" ) set(retained_args "--retain" "@${retained_loader_list}") endif() add_custom_command( OUTPUT ${qmlcache_loader_file} DEPENDS ${qmlcache_loader_list} COMMAND @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen ${retained_args} --resource-name "${resource_name_arg}" -o ${qmlcache_loader_file} "@${qmlcache_loader_list}" ) __qt_propagate_generated_resource(${target} ${resource_name} ${qmlcache_loader_file} output_target) set(${arg_OUTPUT_GENERATED_TARGET} "${output_target}" PARENT_SCOPE) if (resource_files) set(resource_name ${chained_resource_name}) endif() # The generated qmlcache_loader source file uses private headers of Qml, so make sure # if the object library was created, it depends on the Qml target. If there's no target, # that means the target is a shared library and the sources are directly added to the target # via target_sources, so add dependency in that case as well. set(chosen_target "target") # shared library case if(output_target) set(chosen_target "output_target") # static library case. endif() target_link_libraries(${${chosen_target}} PRIVATE @QT_CMAKE_EXPORT_NAMESPACE@::Qml) else() set(resource_files ${arg_FILES}) endif() set(${arg_OUTPUT_REMAINING_RESOURCES} ${resource_files} PARENT_SCOPE) set(${arg_OUTPUT_RESOURCE_NAME} ${resource_name} PARENT_SCOPE) endfunction() # # Process resources via file path instead of QRC files. Behind the # scnenes, it will generate a qrc file and apply post processing steps # when applicable. (e.g.: QtQuickCompiler) # # The QRC Prefix is set via the PREFIX parameter. # # Alias settings for files need to be set via the QT_RESOURCE_ALIAS property # via the set_soure_files_properties() command. # # When using this command with static libraries, a special target will be # generated. Should you wish to perform additional processing on said target # pass a value to the OUTPUT_TARGET parameter. # function(QT@PROJECT_VERSION_MAJOR@_PROCESS_RESOURCE target resourceName) cmake_parse_arguments(rcc "" "PREFIX;LANG;BASE;OUTPUT_TARGET" "FILES" ${ARGN}) string(REPLACE "/" "_" resourceName ${resourceName}) string(REPLACE "." "_" resourceName ${resourceName}) # Apply base to all files if (rcc_BASE) foreach(file IN LISTS rcc_FILES) set(resource_file "${rcc_BASE}/${file}") __qt_get_relative_resource_path_for_file(alias ${resource_file}) # Handle case where resources were generated from a directory # different than the one where the main .pro file resides. # Unless otherwise specified, we should use the original file path # as alias. if (alias STREQUAL resource_file) set_source_files_properties(${resource_file} PROPERTIES QT_RESOURCE_ALIAS ${file}) endif() file(TO_CMAKE_PATH ${resource_file} resource_file) list(APPEND resource_files ${resource_file}) endforeach() else() set(resource_files ${rcc_FILES}) endif() if(NOT rcc_PREFIX) get_target_property(rcc_PREFIX ${target} QT_RESOURCE_PREFIX) if (NOT rcc_PREFIX) message(FATAL_ERROR "QT@PROJECT_VERSION_MAJOR@_PROCESS_RESOURCE() was called without a PREFIX and the target does not provide QT_RESOURCE_PREFIX. Please either add a PREFIX or make the target ${target} provide a default.") endif() endif() # Apply quick compiler pass __qt_quick_compiler_process_resources(${target} ${resourceName} FILES ${resource_files} PREFIX ${rcc_PREFIX} OUTPUT_REMAINING_RESOURCES resources OUTPUT_RESOURCE_NAME newResourceName OUTPUT_GENERATED_TARGET output_target ) if (NOT resources) if (rcc_OUTPUT_TARGET) set(${rcc_OUTPUT_TARGET} "${output_target}" PARENT_SCOPE) endif() return() endif() set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/generated_${newResourceName}.qrc") set(generatedSourceCode "${CMAKE_CURRENT_BINARY_DIR}/qrc_${newResourceName}.cpp") # Generate .qrc file: # set(qrcContents "\n \n") foreach(file IN LISTS resources) __qt_get_relative_resource_path_for_file(file_resource_path ${file}) if (NOT IS_ABSOLUTE ${file}) set(file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") endif() ### FIXME: escape file paths to be XML conform # ... string(APPEND qrcContents " ") string(APPEND qrcContents "${file}\n") list(APPEND files "${file}") endforeach() # string(APPEND qrcContents " \n\n") file(GENERATE OUTPUT "${generatedResourceFile}" CONTENT "${qrcContents}") # Process .qrc file: add_custom_command(OUTPUT "${generatedSourceCode}" COMMAND "@QT_CMAKE_EXPORT_NAMESPACE@::rcc" ARGS --name "${newResourceName}" --output "${generatedSourceCode}" "${generatedResourceFile}" DEPENDS ${resources} ${generatedResourceFile} COMMENT "RCC ${newResourceName}" VERBATIM) get_target_property(type "${target}" TYPE) # Only do this if newResourceName is the same as resourceName, since # the resource will be chainloaded by the qt quickcompiler # qml cache loader if(newResourceName STREQUAL resourceName) __qt_propagate_generated_resource(${target} ${resourceName} "${generatedSourceCode}" output_target) else() target_sources(${target} PRIVATE "${generatedSourceCode}") endif() if (rcc_OUTPUT_TARGET) set(${rcc_OUTPUT_TARGET} "${output_target}" PARENT_SCOPE) endif() endfunction()