You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨CMake子项目使用Q_GADGET导致Qt QML应用崩溃求助

跨CMake子项目Q_GADGET类型QML访问崩溃问题解决

问题背景

两个CMake子项目foo与bar:

  • bar子项目定义带Q_GADGET的结构体Bar,包含x属性
  • foo子项目的FooObjectWithBarProperty类添加Bar类型的属性
  • QML中绑定obj.foo.x正常,但绑定obj.bar.x时应用崩溃,栈追踪提示Bar元类型未正确注册
  • 已尝试qRegisterMetaType、Q_DECLARE_METATYPE、QML_FOREIGN均未解决

核心原因

  1. 跨库符号与元对象链接问题:Bar作为bar子项目的库类型,其moc生成的元对象代码未被foo项目正确链接,导致Qt元类型系统无法识别完整的类型信息。
  2. QML层面类型注册缺失:仅注册C++元类型不足以让QML引擎解析嵌套属性访问(如obj.bar.x),需要将Bar类型注册到QML引擎中。

可行修改方案

1. 修正bar子项目的Bar定义与CMake配置

bar/bar.h

#ifndef BAR_H
#define BAR_H

#include <QObject>

// 跨库符号导出/导入声明
#ifdef BAR_LIBRARY
#define BAR_EXPORT Q_DECL_EXPORT
#else
#define BAR_EXPORT Q_DECL_IMPORT
#endif

struct BAR_EXPORT Bar
{
    Q_GADGET
    Q_PROPERTY(int x MEMBER x)
public:
    int x = 0;
};

// 声明C++元类型
Q_DECLARE_METATYPE(Bar)

#endif // BAR_H

bar/CMakeLists.txt

add_library(bar SHARED
    bar.h
    bar.cpp
)

target_link_libraries(bar PRIVATE Qt${QT_VERSION_MAJOR}::Core)

set_target_properties(bar PROPERTIES
    AUTOMOC ON  # 自动生成moc代码
    PUBLIC_HEADER bar.h
    BAR_LIBRARY ON  # 定义BAR_LIBRARY宏,启用符号导出
)

target_include_directories(bar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

2. 修正foo子项目的类型注册与CMake配置

foo/main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "fooobjectwithbarproperty.h"
#include "bar.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    // 将Bar注册到QML引擎,标记为不可创建(Q_GADGET类型无法在QML实例化)
    qmlRegisterUncreatableType<Bar>("com.example", 1, 0, "Bar", "Bar是Gadget类型,无法在QML中创建");
    // 注册foo的QObject类型
    qmlRegisterType<FooObjectWithBarProperty>("com.example", 1, 0, "FooObjectWithBarProperty");

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/foo/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

foo/CMakeLists.txt

add_executable(foo
    main.cpp
    fooobjectwithbarproperty.h
    fooobjectwithbarproperty.cpp
    qml.qrc
)

target_link_libraries(foo PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick bar)

set_target_properties(foo PROPERTIES
    AUTOMOC ON
    AUTORCC ON
)

target_include_directories(foo PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

3. 验证QML代码(确保导入正确模块)

import QtQuick 2.15
import QtQuick.Window 2.15
import com.example 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    FooObjectWithBarProperty {
        id: obj
        bar: Bar { x: 100 }
        foo: 200
    }

    Text {
        text: obj.bar.x // 现在可正常访问,不会崩溃
        anchors.centerIn: parent
    }
}

方案说明

  • 跨库符号导出:通过BAR_EXPORT宏确保Bar的元对象信息能被foo项目正确链接,避免元类型系统无法找到类型的元数据。
  • QML类型注册:qmlRegisterUncreatableType让QML引擎识别Bar类型,同时明确禁止在QML中实例化(符合Q_GADGET的特性),这样QML才能解析嵌套属性obj.bar.x。
  • AUTOMOC启用:确保CMake自动生成Bar的moc代码,这是Q_GADGET类型元信息的来源。

内容的提问来源于stack exchange,提问作者MarcinJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:08:32