深度剖析qt cmake 的qt_add_qml_module函数

目录标题

  • 前言
  • 参数
    • 参数的底层调用
  • 模块基本信息
  • QML 文件和资源
    • 解析`QML_FILES` 参数内部机制
    • 解析`SOURCES` 参数内部机制
    • `SOURCES` 和`QML_FILES` 内部实现差异
  • 其他资源文件
  • 输出设置
  • 其他选项

前言

qt_add_qml_module 函数是一个高层次的 CMake 函数,用于创建和管理 QML 模块。它简化了将 QML 代码与 C++ 代码集成以及与其他资源文件集成的过程。这个函数旨在用于 Qt 6 和更高版本的项目。

在调用qt_add_qml_module时,它会执行以下操作:

  1. 创建一个动态链接库——作为QML模块的插件——该库将包含定义自定义QML元素的C++类和其他资源。

2. 源文件列表中指定的源文件将作为静态库编译(),并被链接到QML插件动态库(如果存在)以及其他依赖项之中。您可以通过使用add_library命令来向Qt应用程序/库中添加这些源文件。

  1. 自动创建一个qrc文件,该文件将包含指定源文件中的所有资源,例如图片、样式表和翻译文件。

  2. 生成一个描述该QML模块的JSON文件,其中包含URI、版本号、导出对象名等信息。

  3. 将QML插件动态链接库和描述文件复制到项目二进制目录的特定子目录中。该位置取决于是单个项目还是多个项目,以及是在构建目录还是安装目录中构建应用程序/库。

需要注意的是,qt_add_qml_module是一个高层次的抽象,其内部实现是由诸如qt6_add_qml_module等低层次的CMake宏来完成的。这些底层宏负责执行实际的编译、链接和安装操作,并将相关的属性和配置传递给这些操作。

Qt6QmlMacros.cmake 文件是 Qt 6 框架中的一个 CMake 脚本文件。它包含了 Qt QML 模块的相关 CMake 宏和函数,用于处理 QML 文件和构建 QML 模块。当您在项目中使用 Qt 6 的 QML 功能时,这个文件提供了一些便捷的函数,如 qt_add_qml_moduleqt6_target_qml_sources 等,以简化 QML 项目的构建过程。

简而言之,Qt6QmlMacros.cmake 是 Qt 6 框架提供的一个 CMake 辅助脚本,用于简化 QML 项目的构建和配置。这个文件会在您使用 find_package(Qt6Qml) 或类似命令时被包含在您的 CMake 项目中。

参数

qt_add_qml_module 函数提供了多个参数,以便您在创建 QML 模块时进行配置。以下是按功能分类的参数列表:

  1. 模块基本信息:
    • TARGET:目标名称,用于指定模块关联的可执行文件或库。
    • URI:模块的 URI,用于在 QML 代码中 import。
    • VERSION:模块的版本号。
  2. QML 文件和资源:
    • QML_FILES:QML 文件列表,包括所有要编译到模块中的 QML 文件。
    • SOURCES:源文件列表,包括所有要编译到模块中的源代码文件和资源文件。可以包含 QML 文件。
  3. 其他资源文件:
    • RESOURCE_FILES:要包含在模块中的其他资源文件,例如图片、音频等。
    • STATIC_RESOURCE_FILES:静态资源文件,类似于 RESOURCE_FILES,但会嵌入到二进制文件中。
    • RESOURCE_PREFIX:资源文件的前缀路径。
  4. 输出设置:
    • OUTPUT_DIRECTORY:模块输出的目录。
    • DEBUG_OUTPUT_DIRECTORY:模块在调试模式下的输出目录。
    • RELEASE_OUTPUT_DIRECTORY:模块在发布模式下的输出目录。
  5. 其他选项:
    • INSTALL_QMLDIR:用于指定安装模块时的 QML 目录。
    • NO_PLUGIN_OPTION:禁用生成插件文件的选项。

这些参数可以根据您的需求进行选择和配置,以便为您的项目创建适当的 QML 模块。

参数的底层调用

qt_add_qml_module中,以下是参数及其相关调用:

  1. TARGET:这个参数定义了目标名称,它是CMake中创建的目标的名称。这个参数不会直接调用其他函数或宏。
  2. URI:定义了QML模块的唯一标识符。它用于生成模块的描述文件,例如.qmltypes文件。这个参数不会直接调用其他函数或宏。
  3. VERSION:定义了QML模块的版本号。它用于生成模块的描述文件,例如.qmltypes文件。这个参数不会直接调用其他函数或宏。
  4. QML_FILES:这个参数用于指定QML文件列表。它会传递给qt6_target_qml_sources宏,以便将QML文件添加到目标中并在构建过程中正确处理。
  5. SOURCES:这个参数用于指定源文件列表,通常包括C++源文件。这些源文件会被传递给底层的target_sources函数,以便将这些源文件添加到目标中。
  6. RESOURCES:这个参数用于指定资源文件列表,例如图片、样式表和翻译文件。这些资源文件会传递给qt6_target_qml_resources宏,以便将它们添加到目标中并在构建过程中正确处理。
  7. PLUGIN_TARGET:这个参数定义了插件目标的名称。这个参数不会直接调用其他函数或宏。
  8. OUTPUT_DIRECTORY:这个参数用于指定构建输出目录。这个参数不会直接调用其他函数或宏。
  9. INSTALL_DIRECTORY:这个参数用于指定安装输出目录。这个参数不会直接调用其他函数或宏。

这些参数在qt_add_qml_module内部通过调用底层的CMake函数和Qt宏来处理和实现所需的功能。

模块基本信息

从源码角度出发,我们来看看 qt_add_qml_module 中的以下参数:

  1. TARGET:此参数指定了与 QML 模块关联的可执行文件或库。在 qt_add_qml_module 函数内部,TARGET 会用于设置目标属性,以便将 QML 模块正确链接到目标可执行文件或库。在函数内部,TARGET 参数被用于调用 qt6_add_qml_module 函数,这是一个实际处理 QML 模块编译、链接和资源管理的底层函数。
  2. URI:此参数指定了 QML 模块的 URI,以便在 QML 代码中使用 import 语句导入。URI 参数会传递给 qt6_add_qml_module 函数,该函数会创建一个描述 QML 模块的 JSON 文件。JSON 文件中的 URI 信息在运行时用于解析 QML 模块,确保 QML 模块被正确地导入和实例化。
  3. VERSION:此参数用于指定 QML 模块的版本号。VERSION 参数与 URI 类似,会传递给 qt6_add_qml_module 函数。在 JSON 文件中,版本信息会与模块的 URI 一起存储。在运行时,版本信息用于确保正确的模块版本被加载,从而避免因为使用了错误版本的模块而导致的潜在问题。

这些参数都会传递给 qt6_add_qml_module 函数,该函数负责处理 QML 模块的具体实现,包括编译、链接和资源管理。qt_add_qml_module 本身是一个更高层次的抽象,用于简化 QML 模块的创建和管理。

QML 文件和资源

qt_add_qml_module 函数的 SOURCESQML_FILES 参数都用于指定 QML 模块中的 QML 文件。然而,它们之间有一些区别:

  1. SOURCES 参数:这个参数用于指定 QML 模块的源文件(包括 QML 文件和其他相关资源文件)。当您使用这个参数时,需要提供源文件的相对路径(相对于 CMAKE_CURRENT_SOURCE_DIR)。这些文件会被拷贝到构建目录中的特定位置,并在构建过程中进行处理。
  2. QML_FILES 参数:这个参数仅用于指定 QML 模块的 QML 文件。您可以为这个参数提供相对路径或绝对路径。在构建过程中,这些文件会被拷贝到构建目录的特定位置,并进行处理。但是,与 SOURCES 参数不同,QML_FILES 参数不包括其他资源文件,仅包括 QML 文件。

在大多数情况下,您可能只需要使用 QML_FILES 参数。但是,如果您的项目中包含除 QML 文件之外的其他资源文件,您可能需要使用 SOURCES 参数。不过,请注意,当使用 SOURCES 参数时,需要确保文件路径是相对于 CMAKE_CURRENT_SOURCE_DIR 的相对路径。

解析QML_FILES 参数内部机制

当您调用qt_add_qml_module时,它会在内部调用qt6_target_qml_sources。具体来说,qt_add_qml_module的实现如下:

macro(qt_add_qml_module target)
    set(options)
    set(oneValueArgs URI VERSION)
    set(multiValueArgs QML_FILES PREFER_SHARED)
    cmake_parse_arguments(_args "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    ...

    qt6_target_qml_sources(${target} ${_args_QML_FILES})
    ...
endmacro()

从这段代码可以看出,qt_add_qml_module获取QML_FILES参数(即${QML_RELATIVE_FILES}),并将其传递给qt6_target_qml_sources。所以,您所说的${QML_RELATIVE_FILES}参数作为qt6_target_qml_sources的参数是正确的。

接下来,让我们看一下qt6_target_qml_sources函数的部分实现:

function(qt6_target_qml_sources target)
    set(options)
    set(oneValueArgs)
    set(multiValueArgs FILES)
    cmake_parse_arguments(_args "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    ...

    foreach(_file IN LISTS _args_FILES)
        get_filename_component(_file_abs "${_file}" ABSOLUTE)
        ...
    endforeach()

    ...
endfunction()

qt6_target_qml_sources函数接受一个FILES参数,它是传递给qt_add_qml_moduleQML_FILES参数。在函数内部,它会遍历_args_FILES列表,即我们传递给它的QML文件路径列表。对于每个文件,它会获取绝对路径,然后执行一些操作。

所以,对于qt_add_qml_moduleqt6_target_qml_sources,它们按文件分别处理QML文件列表,而不是将整个列表作为单个参数传递给qt6_target_qml_sources。它们遍历QML文件列表,然后针对每个文件执行操作。

解析SOURCES 参数内部机制

SOURCES参数实际上是直接传递给target_sources函数。qt_add_qml_module中的SOURCES参数用于指定源文件列表,通常包括C++源文件。这些源文件会被传递给底层的target_sources函数,以便将这些源文件添加到目标中。

以下是qt_add_qml_module宏的一部分源代码,用于处理SOURCES参数:

if(SOURCES)
    target_sources(${target} PRIVATE ${SOURCES})
endif()

在这段代码中,您可以看到SOURCES参数直接传递给了target_sources函数,该函数将指定的源文件添加到目标中。

如果SOURCES参数中包含了QML文件,target_sources不会自动调用qt6_target_qml_resourcestarget_sources函数仅用于将源文件添加到目标中,它不会对文件类型进行特殊处理。

如果你需要将QML文件作为资源添加到项目中,你应该使用QML_FILES参数。将QML文件添加到SOURCES参数中可能会导致问题,因为这些文件不会被正确处理为QML资源。

qt_add_qml_module中,QML_FILES参数用于指定QML文件,这些文件将被正确处理并嵌入到生成的二进制文件中。

SOURCESQML_FILES 内部实现差异

qt_add_qml_module 函数中,SOURCES 参数用于指定源代码文件(如C++源代码),而 QML_FILES 参数用于指定QML文件。这两个参数在处理过程中有所不同:

  1. 使用 QML_FILES 参数:

    当您使用 QML_FILES 参数时,qt_add_qml_module 会将其作为一个包含所有 QML 文件路径的列表。函数内部会将这个列表传递给 qt6_target_qml_sources,确保 QML 文件被编译为可执行文件或库的一部分,并在运行时可用。

  2. 使用 SOURCES 参数:

    当您使用 SOURCES 参数时,qt_add_qml_module 会将其作为一个包含所有源代码文件(如C++源代码)的列表。SOURCES 参数不应该包含QML文件,因为它不会将这些文件作为资源处理。在这种情况下,您应该使用 QML_FILES 参数来指定QML文件。

总之,在 qt_add_qml_module 函数中,QML_FILES 参数用于处理QML文件,而 SOURCES 参数用于处理其他类型的源代码文件。为了确保QML文件被正确处理,您应该使用 QML_FILES 参数来指定它们。



其他资源文件

qt_add_qml_module 函数中,不同参数的存在是为了提供更多灵活性和控制。尽管 SOURCES 参数可以用来指定源代码文件,但它并不是专门用于处理资源文件(如图片、音频等)的。使用特定的资源参数可以让您更清晰地组织项目,并明确指定资源文件及其用途。

  • RESOURCE_FILES:此参数允许您将资源文件(如图片、音频等)明确地与源代码文件分开。这有助于组织项目并提高代码可读性。
  • STATIC_RESOURCE_FILES:与 RESOURCE_FILES 类似,此参数用于指定静态资源文件。将资源文件嵌入到二进制文件中可以确保这些资源在部署时始终可用。嵌入资源还可以简化部署过程,因为您不需要担心将外部资源文件与应用程序一起分发。
  • RESOURCE_PREFIX:此参数为资源文件提供了一个前缀路径。使用前缀路径可以帮助您更好地组织资源,并确保在运行时可以正确访问这些资源。

总之,这些参数为项目提供了更多的组织灵活性。虽然您可以使用 SOURCES 参数来指定资源文件,但使用专门的资源参数可以帮助您更清晰地组织项目,并更好地控制资源文件的处理。

输出设置

qt_add_qml_module 函数中,以下参数用于控制模块输出的位置:

  • OUTPUT_DIRECTORY:用于指定模块输出的目录。当您没有为 DEBUG_OUTPUT_DIRECTORYRELEASE_OUTPUT_DIRECTORY 分别指定调试和发布模式下的输出目录时,此参数将作为默认值。
  • DEBUG_OUTPUT_DIRECTORY:用于指定模块在调试模式下的输出目录。如果设置了此参数,它将优先于 OUTPUT_DIRECTORY 参数。
  • RELEASE_OUTPUT_DIRECTORY:用于指定模块在发布模式下的输出目录。如果设置了此参数,它将优先于 OUTPUT_DIRECTORY 参数。

qt_add_qml_module 函数内部,这些参数将传递给底层宏 qt6_target_qml_sources,它会处理模块输出目录的设置。源码中的以下部分演示了这些参数是如何应用的:

set_property(TARGET ${target} PROPERTY
    QT_QML_MODULE_INSTALL_QML_OUTPUT_DIRECTORY "${ARGN_OUTPUT_DIRECTORY}")
set_property(TARGET ${target} PROPERTY
    QT_QML_MODULE_INSTALL_QML_DEBUG_OUTPUT_DIRECTORY "${ARGN_DEBUG_OUTPUT_DIRECTORY}")
set_property(TARGET ${target} PROPERTY
    QT_QML_MODULE_INSTALL_QML_RELEASE_OUTPUT_DIRECTORY "${ARGN_RELEASE_OUTPUT_DIRECTORY}")

这些 set_property 调用用于将模块输出目录的相关参数与目标关联。这些属性随后将在安装步骤(如 install() 命令)中使用,以确保模块在构建过程中输出到正确的位置。

在调试和发布模式下,通过设置 DEBUG_OUTPUT_DIRECTORYRELEASE_OUTPUT_DIRECTORY,您可以更好地控制模块输出目录,从而组织项目和构建过程。

其他选项

从源码角度来看,INSTALL_QMLDIRNO_PLUGIN_OPTION 这两个参数在 qt_add_qml_module 函数中的作用如下:

  1. INSTALL_QMLDIR 参数:

INSTALL_QMLDIR 参数用于指定在安装 QML 模块时使用的 QML 目录。当您使用 qt_add_qml_module 函数创建一个 QML 模块时,通常会将生成的 QML 插件和相关资源文件安装到特定的目录。这个目录通常位于 Qt 安装目录下的 qml 子目录中。

INSTALL_QMLDIR 参数允许您自定义安装目录,而不是使用默认的 QML 目录。这在某些特殊情况下可能非常有用,比如在需要与其他已安装的 QML 模块共享资源或避免目录冲突时。

qt_add_qml_module 函数的内部实现中,INSTALL_QMLDIR 参数会影响到生成的 CMake 安装命令。如果提供了自定义的 INSTALL_QMLDIR,则 CMake 会将 QML 插件和相关资源文件安装到指定的目录,而不是默认的 QML 目录。

  1. NO_PLUGIN_OPTION 参数:

NO_PLUGIN_OPTION 参数用于控制是否生成 QML 插件。当使用 qt_add_qml_module 函数时,默认情况下会为模块生成一个 QML 插件。这个插件是一个动态链接库,包含了自定义 QML 元素的 C++ 类和其他资源。

在某些情况下,您可能不希望生成 QML 插件。例如,当您的项目仅使用纯 QML 代码,而不包含任何 C++ 类时,生成插件可能没有意义。在这种情况下,您可以使用 NO_PLUGIN_OPTION 参数来禁用插件生成。

qt_add_qml_module 函数的内部实现中,NO_PLUGIN_OPTION 参数会影响到插件生成的条件判断。如果设置了 NO_PLUGIN_OPTION,则函数内部的相关逻辑会跳过插件的生成过程,只处理 QML 和资源文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/17464.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes项目部署

目录 ​一、容器交付流程 二、k8s平台部署项目流程 三、在K8s平台部署项目 一、容器交付流程 容器交付流程通常分为四个阶:开发阶段、持续集成阶段、应用部署阶段和运维阶段。 开发阶段:开发应用程序,编写Dockerfile; 持续集成阶段&#…

很佩服的一个Google大佬,离职了。。

这两天,科技圈又有一个突发的爆款新闻相信不少同学都已经看到了。 那就是75岁的计算机科学家Geoffrey Hinton从谷歌离职了,从而引起了科技界的广泛关注和讨论。 而Hinton自己也证实了这一消息。 提到Geoffrey Hinton这个名字,对于一些了解过…

Spring Cloud学习笔记【分布式配置中心-Config】

文章目录 SpringCloud Config概述概述传统方式弊端主要功能与GitHub整合配置 Config服务端配置与测试服务端配置(即Gitee上的配置文件)Config Demo配置Spring Cloud Config访问规则 Config客户端配置与测试bootstrap.yml说明Config客户端 Demo配置 SpringCloud Config概述 概述…

无需公网IP 使用SSH远程连接Linux CentOS服务器【内网穿透】

文章目录 视频教程1. Linux CentOS安装cpolar2. 创建TCP隧道3. 随机地址公网远程连接4. 固定TCP地址5. 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下,SSH远程连接家里/公司的Linux CentOS服务器,无需公网IP,也不需要设置…

深入理解Java虚拟机——垃圾收集器

1.前言 在前面我们已经说过了垃圾收集算法,那么现在我们要讲的垃圾收集器,实际上就是对垃圾收集算法的实践。 首先我们先看一张图,这张图可以帮助我们了解各款经典垃圾收集器之间的关系: 图中的垃圾收集器所在的区域代表了它是属…

【三十天精通Vue 3】第二十六天 Vue3 与 TypeScript 最佳实践

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3 文章目录 引言一、为什么使用TypeScript?二、Vue 3和TypeScript的基础2.1 安装TypeScript2.2 配置TypeScript2.3 Vue 3中使用TypeScript

Java多线程基础概述

简述多线程: 是指从软件或者硬件上实现多个线程并发执行的技术。 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。 正式着手代码前,需要先理清4个概念:并发,并行,进程&#…

TinyJAMBU的制动原理——一种轻量化的认证密码

关于TinyJAMBU的定义和介绍在另一篇博文已经介绍过了,这里只对其动作原理进行描述和说明。 对应的博文链接如下:TinyJAMBU:一种轻量化密码介绍 首先,该密码是一个流密码体系的块密码框架。其加密模式整体上来看是块密码&#xff0…

让语言学习更简单的 WordFlow

作为一个英语并不是那么特别好的计算机专业学生,长期积累英语的学习对个人发展还是有意义的。简单来说,我在语言上最大的两个问题,一个自己「不理解」,另一个是自己「不会表达」。 上述两个问题主要体现在口语层面,而…

实验二 存储器管理

实验二 存储器管理 实验目的: 理解各类置换算法的原理和虚拟存储器管理的方法。 实验内容: 编程实现LRU算法或CLOCK/改进算法等置换算法(二选一),模拟实现虚拟存储器的地址变换过程。 实验步骤: 1…

【Golang项目实战】用Go写一个学生信息管理系统,真的太酷啦| 保姆级详解,附源码——建议收藏

博主简介:努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:数据结构、Go,Java等相关知识。博主主页: 是瑶瑶子啦所属专栏: Go语言核心编程近期目标:写好专栏的每一篇文章 学习了Go的基…

图神经网络:在自定义数据集上动手实现图神经网络

文章说明: 1)参考资料:PYG官方文档。超链。 2)博主水平不高,如有错误还望批评指正。 文章目录 自定义数据集动手实现图神经网络自定义数据集训验测集拆分,创建Data的数据结构,观察Data的基本信息,可视化图网…

震惊,为了学会泛型类竟做这种事?!

上一节,我们基本学会了Java泛型类的用法。 传送门:彻底弄懂Java的泛型 - 泛型类 这一节,我们转变一下风格,具体是什么风格呢,你马上就懂了。 宝子们,欢迎大家来到我们的泛型直播间,这一讲呢&a…

Ansible的脚本-playbook 剧本

目录 1.剧本(playbook) 1.playbook介绍 2. playbooks 的组成 3.案例:编写httpd的playbook 4.定义、引用变量 5.指定远程主机sudo切换用户 6.when条件判断 7.迭代 2.playbook的模块 1.Templates 模块 2.tags 模块 3.Roles 模块 1.…

【Linux从入门到精通】vim的基本使用各种操作详解

文章目录 一、vim编辑器简单介绍 二、vim编辑器的四种模式 2、1 正常/普通/命令模式(Normal mode) 2、2 插入模式(Insert mode) 2、3 末行模式(last line mode) 三、命令模式的相关操作实例 3、1 光标的相关操作 3、2 文本操作 四、插入模式下的相关操作 五、末行模式下的相关操…

Java—JDK8新特性—函数式接口

目录 函数式接口 3.1 什么是函数式接口 3.2 functionalinterface注解 源码分析 3.3 Lambda表达式和函数式接口关系 3.4 使用函数式接口 函数式接口 3.1 什么是函数式接口 如果一个接口中只包含一个抽象方法,这个接口称为函数式接口 如果一个接口包含&#xff0…

K8S管理系统项目实战[API开发]-2

后端: gogin 后端代码地址GitHub - yunixiangfeng/k8s-platform: K8s管理系统后端: gogin 5、存储与配置 5.1 ConfigMap 5.2 Secret 5.3 PersistentVolumeClaims 6、工作流 6.1 流程设计 6.2 数据库操作(GORM) (1)初始化…

交换机-Exchanges

交换机 Exchanges 概念 RabbitMQ 消息传递模型的核心思想是: 生产者生产的消息从不会直接发送到队列。实际上,通常生产者甚至都不知道这些消息传递传递到了哪些队列中。相反,生产者只能将消息发送到交换机(exchange),交换机工作的内容非常简…

正则表达式-基本元字符和语法规则

© Ptw-cwl 文章目录 字符匹配元字符.元字符[]元字符[^]元字符*元字符元字符?元字符{}元字符|元字符()元字符^元字符$元字符\元字符\d元字符\w元字符\s元字符\b元字符\B元字符*?、?、??、{n,m}?元字符(?)、(?!)元字符(?:)元字符\1、\2等元字符^、$元字符&#x…

JavaSE基础(二)—— 类型转换、运算符、键盘录入

目录 一、类型转换 1. 自动类型转换 1.1 自动类型转换的底层原理: ​1.2 自动类型转换的其他形式​编辑 2. 表达式的自动类型转换 3. 强制类型转换 3.1 强制类型转换底层原理​编辑 3.2 注意事项 二、运算符 1. 算数运算符 1.1 案例:数值拆分…