Custom C++ type from a QML module is not defined when used inside QML file
-
In my project I'm trying to expose a singleton type to QML from C++. Initially I registered it with qmlRegisterSingletonInstance and it worked fine. But when I tried to replace this way with QML_ELEMENT and QML_SINGLETON macros it compiles fine but when QML tries to use the class it complains that the type is not defined.
My project has two modules, one consists solely of qml files and the second - of C++ files, where I try to expose the class from and use it in the first module. The structure is a bit complicated so I reproduced the issue with a simpler test project. I noticed that QML cannot recognize neither the singleton type nor a non-singleton type.
The project has a following structure:
│ CMakeLists.txt │ main.cpp │ └───logicmodule CMakeLists.txt Main.qml Message.h MySingleton.h
The code:
// logicmodule/MySingleton.h #pragma once #include <QObject> #include <QQmlEngine> #include <QString> class MySingleton : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON public: MySingleton(QObject *parent = nullptr) : QObject{parent} {} public slots: QString exec(const QString &str) { return "somestring"; } };
// logicmodule/Message.h #pragma once #include <QObject> #include <QQmlEngine> #include <QString> class Message : public QObject { Q_OBJECT QML_ELEMENT Q_PROPERTY(QString author MEMBER m_author NOTIFY authorChanged) public: Message() {} signals: void authorChanged(); private: QString m_author; };
// logicmodule/Main.qml import QtQuick import QtQuick.Controls Window { width: 640 height: 480 visible: true title: qsTr("Hello World") // property Message msg: Message {} Button { id: button anchors.centerIn: parent text: "Click me" onClicked: { label.text = MySingleton.exec(label.text) } } Label { id: label anchors.top: button.bottom } }
// logicmodule/CMakeLists.txt project(logicmodule VERSION 0.1 LANGUAGES CXX) qt_add_library(${PROJECT_NAME} STATIC) qt6_add_qml_module(${PROJECT_NAME} URI Main VERSION 1.0 NO_PLUGIN RESOURCE_PREFIX "/qt/qml" QML_FILES Main.qml SOURCES MySingleton.h Message.h ) target_link_libraries(${PROJECT_NAME} PUBLIC Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick ) target_include_directories(${PROJECT_NAME} PUBLIC . )
// main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include "Message.h" #include "MySingleton.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(u"qrc:/qt/qml/Main/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.addImportPath(QCoreApplication::applicationDirPath() + "/qml"); engine.addImportPath(":/"); engine.load(url); if (engine.rootObjects().isEmpty()) { return -1; } return app.exec(); }
// CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(typetest VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.5 REQUIRED COMPONENTS Quick) set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml) qt_standard_project_setup(REQUIRES 6.5) add_subdirectory(logicmodule) qt_add_executable(apptypetest main.cpp ) target_link_libraries(apptypetest PUBLIC logicmodule ) # No effect # target_include_directories(apptypetest # PUBLIC # "${PROJECT_SOURCE_DIR}/logicmodule" # logicmodule # ) # include_directories(logicmodule)
It all compiles fine but at runtime I get an error when trying to call MySingleton:
qrc:/qt/qml/Main/Main.qml:16: ReferenceError: MySingleton is not defined
I tried to research this issue but cannot find exactly my case, the closest I got is this one: qmltyperegistration include path does not acknowledge subdirectories
But the files with custom types seems to be included just fine without any prefixes.
I also noticed that in the build folder I have a file
build\Debug\logicmodule\logicmodule_qmltyperegistrations.cpp
and it contains calls toqmlRegisterTypesAndRevisions
but it seems that it doesn't have an effect?Also tried a project structure without any additional libraries (so without
logicmodule
lib, everything is in the project root and I have only oneCMakeLists
) and it seem to be working fine and all the custom types are recognized by QML.Could somebody point me to what am I doing wrong here with the library? Why can't QML recognize the type when it's defined inside a lib?
I also had this question posted on SO here for a few days already, but unfortunately no solutions so far.
-
I guess your problem comes down to
NO_PLUGIN
. The documation says the following:The STATIC QML modules also generate the static QML plugins if NO_PLUGIN is not specified. Targets that import such STATIC QML modules also need to explicitly link to corresponding QML plugins.
https://doc.qt.io/qt-6/qt-add-qml-module.html#target-structureI think that's why @dheerendra suggested you to make it shared lib.
Try removing
NO_PLUGIN
fromqt_add_qml_module()
& link againstlogicmoduleplugin
instead oflogicmodule
in your root's CMakeLists.txt. And make a clean build as well -
@monkeber said in Custom C++ type from a QML module is not defined when used inside QML file:
qt_add_library(${PROJECT_NAME} STATIC)
You can make it SHARED instead of STATIC.
qt_add_library(${PROJECT_NAME} SHARED)This should work. Not sure why static is not working.
-
Hi @Anumas
Yes, tried this, Qt Creator complains that such module is not found (I guess because Main.qml is a part of Main module and can't resolve the path) but the application compiles fine and there is still the same error:
qrc:/qt/qml/Main/Main.qml:18: ReferenceError: MySingleton is not defined
-
I guess your problem comes down to
NO_PLUGIN
. The documation says the following:The STATIC QML modules also generate the static QML plugins if NO_PLUGIN is not specified. Targets that import such STATIC QML modules also need to explicitly link to corresponding QML plugins.
https://doc.qt.io/qt-6/qt-add-qml-module.html#target-structureI think that's why @dheerendra suggested you to make it shared lib.
Try removing
NO_PLUGIN
fromqt_add_qml_module()
& link againstlogicmoduleplugin
instead oflogicmodule
in your root's CMakeLists.txt. And make a clean build as well -
Hi @dheerendra
Thank you for an interesting suggestion. After changing STATIC to SHARED I now have an error at the application start:
QQmlApplicationEngine failed to load component qrc:/qt/qml/Main/Main.qml: No such file or directory
and the app exits immediately after this.
I tried to play around with the path in
main.cpp
and tried"qrc:/qml/Main/Main.qml"
,":/qml/Main/Main.qml"
or":/qt/qml/Main/Main.qml"
but none of them fixed this.I also tried to google this and re-read the doc https://doc.qt.io/qt-6/qt-add-qml-module.htm and somewhat similar issues here and here.
And tried to make qt to generate a plugin:# logicmodule/CMakeLists.txt # ... qt_add_library(${PROJECT_NAME} SHARED) qt6_add_qml_module(${PROJECT_NAME} URI Main VERSION 1.0 # NO_PLUGIN # <- commented out RESOURCE_PREFIX "/qt/qml" QML_FILES Main.qml SOURCES MySingleton.h Message.h ) # ... other code is unchanged
# CMakeLists.txt # ... set(CMAKE_AUTORCC ON) # <- tried this just in case # ... target_link_libraries(apptypetest PUBLIC Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick # logicmoduleplugin # <- can't link to this because it's a MODULE_LIBRARY logicmodule # <- also tried to comment this one, no effect ) # ... other code is unchanged
But I still get this error:
QQmlApplicationEngine failed to load component qrc:/qt/qml/Main/Main.qml: No such file or directory
But in STATIC configuration from my original post it works and application at least starts (while still having issue with MySingleton is not being defined).
I suppose I've missed something while trying to convert to SHARED lib, maybe you could point out what I did wrong here please?
I was thinking maybe this issue has something to do with resource files? But I don't have explicitly defined resource files and registered everything through CMake assuming that it should handle it. Maybe I don't understand something here.
Also additional info I forgot to add to the original post:
I'm using Qt 6.7.0 and Qt Creator 13.0.0 if it helps. -
@monkeber after doing what I said you should get your app working
To fix Qt Creator complaining about unknown types, you have to modify your module definition:
project(logicmodulelib VERSION 0.1 LANGUAGES CXX) qt_add_library(${PROJECT_NAME} STATIC) qt_add_qml_module(${PROJECT_NAME} URI logicmodule VERSION 1.0 RESOURCE_PREFIX "/qt/qml" QML_FILES Main.qml SOURCES MySingleton.h Message.h ) ...
In the URI you MUST follow your project structure. https://doc.qt.io/qt-6/qtqml-writing-a-module.html
Update your root's
CMakeLists.txt
to link to the plugin correctly:target_link_libraries(apptypetest PUBLIC logicmodulelibplugin)
-
You can see the example in my repository.
https://github.com/QtDheeru/QtExamples/tree/master/QML/QMLSingleTonIssue -
@Anumas Thank you very much, your suggestion indeed helped me and now qml properly recognizes custom types!
A note regarding Qt Creator complaining about unknown types - for some reason implementing fixes as you suggested didn't help, but what helped is setting
QML_IMPORT_PATH
in rootCMakeLists.txt
, do you think this is a proper fix for this or is something wrong here?CMakeLists files now look like this:
# logicmodule/CMakeLists.txt project(logicmodulelib VERSION 0.1 LANGUAGES CXX) qt_add_library(${PROJECT_NAME} STATIC) qt_add_qml_module(${PROJECT_NAME} URI logicmodule VERSION 1.0 RESOURCE_PREFIX "/qt/qml" QML_FILES Main.qml SOURCES MySingleton.h Message.h ) target_link_libraries(${PROJECT_NAME} PUBLIC Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick ) target_include_directories(${PROJECT_NAME} PUBLIC . )
# CmakeLists.txt cmake_minimum_required(VERSION 3.16) project(typetest VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.5 REQUIRED COMPONENTS Quick) qt_policy(SET QTP0001 NEW) set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qt/qml) set(QML_IMPORT_PATH "${CMAKE_BINARY_DIR}/qt/qml" CACHE STRING "Qt Creator extra qml import paths" FORCE) qt_standard_project_setup(REQUIRES 6.5) add_subdirectory(logicmodule) qt_add_executable(apptypetest main.cpp ) target_link_libraries(apptypetest PUBLIC Qt6::Gui Qt6::Qml logicmodulelibplugin )
-
@dheerendra Sorry, I'm not sure I understood your example correctly. When I start your example I get an error:
QQmlApplicationEngine failed to load component qrc:/qt/qml/dheeru/Main/Main.qml: No such file or directory
Does it work for you? Maybe I'm doing something wrong.
I also tried to tweak it to make it work for me, but with no success so far.
-
Yes. It is working example. Did you make any changes to the program ?
I have failed case with StaticPlugin/CMakeLists.txt -
qt_add_library(${PROJECT_NAME} STATIC). Change this line to ->qt_add_library(${PROJECT_NAME} SHARED)Everything should work.
-
@Anumas Yes, I've tried to reset the code model, clean rebuild and also I've updated Qt Creator to 13.0.2 (from 13.0.0) just in case. Not sure what's wrong, but after commenting out setting
QML_IMPORT_PATH
again, rebuilding and resetting the code model - Qt Creator can't recognize the module:
QML_IMPORT_PATH
is indeed not inCMakeCache.txt
unless I set it from CMake.Maybe I indeed need to set it manually:
https://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html#importing-qml-modulesI'm also on Windows, not sure if it's relevant or not.
-
-
@dheerendra
Sorry, I'm not sure what am I doing wrong here, but even after changingqt_add_library(${PROJECT_NAME} STATIC)
toqt_add_library(${PROJECT_NAME} SHARED)
as you suggested I still get this error while trying to run the example:23:42:38: Starting E:\Projects\QtExamples-master\QML\QMLSingleTonIssue\build\Debug-Desktop_Qt_6_7_0_MSVC2019_64bit_MSVC2022\appQMLSingleTonIssue.exe... QML debugging is enabled. Only use this in a safe environment. QQmlApplicationEngine failed to load component qrc:/qt/qml/dheeru/Main/Main.qml: No such file or directory
What I did:
- Download your repo in zip archive.
- Unpack.
- In Qt Creator
Open File or Project
->QtExamples-master\QML\QMLSingleTonIssue\CMakeLists.txt
- Build and Run in Debug configuration.
I did not change anything in the code, just retried it.
-
@monkeber How did you solve the problem ? It helps if you post the same here.
-
Hi @dheerendra
I think the issue was in
NO_PLUGIN
as were suggested by @Anumas here:
https://forum.qt.io/post/802964Seems to be working fine with static library now. I marked that message as a solution.