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.
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