Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET
-
TLDR
The article Modern QML modules | Qt Qml | Qt 6.10.2 says that setting the
QT_QML_OUTPUT_DIRECTORY
variable is not necessary anymore if the dependencies are declared in theDEPENDENCIES TARGET
of the QML module, but this does not seem to be the case.
I am suspecting a Qt bug here, but wanted to confirm it before filing a Jira issue. Maybe I just forgot something trivial.Detailed description
My test project has the following structure:
DynamicLinkingCustomStructureModernExample │ CMakeLists.txt └───sources │ CMakeLists.txt ├───App │ CMakeLists.txt │ main.cpp │ Main.qml └───Modules │ CMakeLists.txt └───ModuleA CMakeLists.txt ItemA.qmlThe top-level CMake:
cmake_minimum_required(VERSION 3.22) project(DynamicLinkingCustomStructureModernExample VERSION 0.1 LANGUAGES CXX) find_package(Qt6 REQUIRED COMPONENTS Quick) qt_standard_project_setup(REQUIRES 6.8) # The article suggests that this is not necessary anymore #set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(sources)sourcesfolder´s CMake:add_subdirectory(Modules) add_subdirectory(App)Modulesfolder´s CMake:add_subdirectory(ModuleA)ModuleAfolder´s CMake:qt_add_qml_module(ModuleA URI Modules.ModuleA SHARED QML_FILES ItemA.qml )Appfolder´s CMake:qt_add_executable(App main.cpp ) qt_add_qml_module(App URI DynamicLinkingCustomStructureModernExample DEPENDENCIES TARGET ModuleA QML_FILES Main.qml ) target_link_libraries(App PRIVATE Qt6::Quick PRIVATE ModuleA )ItemA.qml:import QtQuick Rectangle { color: "lightgreen" implicitWidth: text.implicitWidth + 20 implicitHeight: text.implicitHeight + 20 Text { id: text anchors.centerIn: parent text: "ItemA" color: "darkgreen" } }Main.qml:import Modules.ModuleA import QtQuick import QtQuick.Controls ApplicationWindow { width: 400 height: 100 visible: true Rectangle { anchors.fill: parent color: "lightblue" Text { anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 20 } text: "DynamicLinkingCustomStructureModernExample - Main" color: "darkblue" } ItemA { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom bottomMargin: 20 } } } }main.cpp:#include <QDirIterator> #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [](QObject *object, const QUrl &url) { qDebug() << "Object created! URL: " << url; }, Qt::QueuedConnection); QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { qDebug() << "Object creation failed! Exiting..."; QCoreApplication::exit(-1); }, Qt::QueuedConnection); // Logging the import paths and available resources to see which modules were found { qDebug() << "QML Import paths"; auto importPaths = engine.importPathList(); for (auto &importPath : importPaths) qDebug() << "\t" << importPath; qDebug() << "Available resources"; auto dirIterator = QDirIterator{":/", QDir::AllEntries, QDirIterator::Subdirectories}; while (dirIterator.hasNext()) qDebug() << "\t" << dirIterator.next(); } // Loading the QML modules to see whether they can be found engine.loadFromModule("DynamicLinkingCustomStructureModernExample", "Main"); return app.exec(); }The issue is that the
ModuleAQML module will be put under:
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\Modules\ModuleAWhen setting the
DEPENDENCIES TARGETthe following path will be added to import paths:
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\ModulesSo the
Main.qml´s statementimport Modules.ModuleAdoes not find the module.
But writingimport ModuleAinstead fails too, as then QML says that I should use the full URI.I would expect the path
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources
to be added as an import path by the toolchain, then I could use theURI
to import the module without any workaround. If I add this path manually inmain.cpp
as an import path, then the module will be found.Another forum topic with a similar project structure (solved by setting
QT_QML_OUTPUT_DIRECTORY):
"Correct way to make QML modules Qt 6.5-6.9" -
TLDR
The article Modern QML modules | Qt Qml | Qt 6.10.2 says that setting the
QT_QML_OUTPUT_DIRECTORY
variable is not necessary anymore if the dependencies are declared in theDEPENDENCIES TARGET
of the QML module, but this does not seem to be the case.
I am suspecting a Qt bug here, but wanted to confirm it before filing a Jira issue. Maybe I just forgot something trivial.Detailed description
My test project has the following structure:
DynamicLinkingCustomStructureModernExample │ CMakeLists.txt └───sources │ CMakeLists.txt ├───App │ CMakeLists.txt │ main.cpp │ Main.qml └───Modules │ CMakeLists.txt └───ModuleA CMakeLists.txt ItemA.qmlThe top-level CMake:
cmake_minimum_required(VERSION 3.22) project(DynamicLinkingCustomStructureModernExample VERSION 0.1 LANGUAGES CXX) find_package(Qt6 REQUIRED COMPONENTS Quick) qt_standard_project_setup(REQUIRES 6.8) # The article suggests that this is not necessary anymore #set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(sources)sourcesfolder´s CMake:add_subdirectory(Modules) add_subdirectory(App)Modulesfolder´s CMake:add_subdirectory(ModuleA)ModuleAfolder´s CMake:qt_add_qml_module(ModuleA URI Modules.ModuleA SHARED QML_FILES ItemA.qml )Appfolder´s CMake:qt_add_executable(App main.cpp ) qt_add_qml_module(App URI DynamicLinkingCustomStructureModernExample DEPENDENCIES TARGET ModuleA QML_FILES Main.qml ) target_link_libraries(App PRIVATE Qt6::Quick PRIVATE ModuleA )ItemA.qml:import QtQuick Rectangle { color: "lightgreen" implicitWidth: text.implicitWidth + 20 implicitHeight: text.implicitHeight + 20 Text { id: text anchors.centerIn: parent text: "ItemA" color: "darkgreen" } }Main.qml:import Modules.ModuleA import QtQuick import QtQuick.Controls ApplicationWindow { width: 400 height: 100 visible: true Rectangle { anchors.fill: parent color: "lightblue" Text { anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 20 } text: "DynamicLinkingCustomStructureModernExample - Main" color: "darkblue" } ItemA { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom bottomMargin: 20 } } } }main.cpp:#include <QDirIterator> #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [](QObject *object, const QUrl &url) { qDebug() << "Object created! URL: " << url; }, Qt::QueuedConnection); QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { qDebug() << "Object creation failed! Exiting..."; QCoreApplication::exit(-1); }, Qt::QueuedConnection); // Logging the import paths and available resources to see which modules were found { qDebug() << "QML Import paths"; auto importPaths = engine.importPathList(); for (auto &importPath : importPaths) qDebug() << "\t" << importPath; qDebug() << "Available resources"; auto dirIterator = QDirIterator{":/", QDir::AllEntries, QDirIterator::Subdirectories}; while (dirIterator.hasNext()) qDebug() << "\t" << dirIterator.next(); } // Loading the QML modules to see whether they can be found engine.loadFromModule("DynamicLinkingCustomStructureModernExample", "Main"); return app.exec(); }The issue is that the
ModuleAQML module will be put under:
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\Modules\ModuleAWhen setting the
DEPENDENCIES TARGETthe following path will be added to import paths:
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\ModulesSo the
Main.qml´s statementimport Modules.ModuleAdoes not find the module.
But writingimport ModuleAinstead fails too, as then QML says that I should use the full URI.I would expect the path
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources
to be added as an import path by the toolchain, then I could use theURI
to import the module without any workaround. If I add this path manually inmain.cpp
as an import path, then the module will be found.Another forum topic with a similar project structure (solved by setting
QT_QML_OUTPUT_DIRECTORY):
"Correct way to make QML modules Qt 6.5-6.9"Hi, and welcome!
@GergoK said in Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET:
When setting the DEPENDENCIES TARGET the following path will be added to import paths:
build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\Modules...
I would expect the path build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources
to be added as an import path by the toolchainI believe this bug has been fixed. Can you please try upgrading to a newer version of Qt? (6.8.6 LTS or 6.10.2)
-
Thank you, @JKSH for your answer.
The only Qt version installed on my PC is 6.10.2 llvm-mingw-64.
After applying the CMake changeqt_standard_project_setup(REQUIRES 6.10)the issue is still present.I will file this as a bug as I did not find anything related in Jira.
-
Thank you, @JKSH for your answer.
The only Qt version installed on my PC is 6.10.2 llvm-mingw-64.
After applying the CMake changeqt_standard_project_setup(REQUIRES 6.10)the issue is still present.I will file this as a bug as I did not find anything related in Jira.
You're welcome.
@GergoK said in Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET:
I would expect the path build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources
to be added as an import path by the toolchain, then I could use the URI
to import the module without any workaround. If I add this path manually in main.cpp
as an import path, then the module will be found.Actually, I just realized that you're talking about a runtime error -- I previously thought you had a compile-time or edit-time error, sorry for misreading.
[EDIT: No, this was wrong. It was a bug in Qt 6.10.2 but fixed in Qt 6.11.0-beta3 --JKSH]DEPENDENCIES TARGETonly affects compile-time tools (like the QML Compiler) and edit-time tools (like the QML Language Server). It has no effect on your runtime QML engine.The easiest ways to make things work are:
- Change your library from
SHAREDtoSTATIC, OR - Apply
set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
Alternatively, you could deploy your project so that everything is installed into a final location (see https://doc.qt.io/qt-6/qt-generate-deploy-qml-app-script.html ), but this is a bit heavy during development.
The article Modern QML modules | Qt Qml | Qt 6.10.2 says that setting the
QT_QML_OUTPUT_DIRECTORY
variable is not necessary anymore if the dependencies are declared in theDEPENDENCIES TARGETIMHO, that section oversimplifies things because:
DEPENDENCIES TARGETdoesn't help your un-deployed executable find your dynamically-linked modules, as you've found outDEPENDENCIES TARGETdoesn't help QML tools find your modules if their folder doesn't match their URI (see the "Mismatched.URI.Lib" example at [QTBUG-137199] Minimize discrepancies in QML import paths between different QML tools, out-of-the-box)
Currently,
set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})is still very valuable for fixing many kinds of headaches. - Change your library from
-
Thank you for your input.
I have reported this as a bug before I noticed your answer. They have confirmed that there is an issue here:
https://qt-project.atlassian.net/browse/QTBUG-144510?focusedCommentId=2617125Just like you said setting the
QT_QML_OUTPUT_DIRECTORYis a good workaround here. This is the solution I have applied to my project at the end.But then I got annoyed a bit that most of the documentation and other resources are promoting static linking only and created a repo where I collect the different options we have. That is when I stumbled upon this issue with the
DEPENDENCIES TARGET. I will post it here when I'm done with it. -
G GergoK has marked this topic as solved
-
Thank you for your input.
I have reported this as a bug before I noticed your answer. They have confirmed that there is an issue here:
https://qt-project.atlassian.net/browse/QTBUG-144510?focusedCommentId=2617125Just like you said setting the
QT_QML_OUTPUT_DIRECTORYis a good workaround here. This is the solution I have applied to my project at the end.But then I got annoyed a bit that most of the documentation and other resources are promoting static linking only and created a repo where I collect the different options we have. That is when I stumbled upon this issue with the
DEPENDENCIES TARGET. I will post it here when I'm done with it.@GergoK said in Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET:
I have reported this as a bug before I noticed your answer. They have confirmed that there is an issue here:
https://qt-project.atlassian.net/browse/QTBUG-144510?focusedCommentId=2617125Thanks for writing up the bug report. Looks like it all works as expected on Qt 6.11 (you can download the beta version now)
@JKSH said in Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET:
DEPENDENCIES TARGET only affects compile-time tools (like the QML Compiler) and edit-time tools (like the QML Language Server). It has no effect on your runtime QML engine.
My apologies, this was wrong.
DEPENDENCIES TARGETdoes put import paths inside qt.conf for the runtime engine to use without deploying.