Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET

Setting up QML module dependencies with qt_add_qml_module()´s DEPENDENCIES TARGET

Scheduled Pinned Locked Moved Solved QML and Qt Quick
5 Posts 2 Posters 119 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    GergoK
    wrote last edited by
    #1

    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 the DEPENDENCIES 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.qml
    

    The 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)
    

    sources folder´s CMake:

    add_subdirectory(Modules)
    add_subdirectory(App)
    

    Modules folder´s CMake:

    add_subdirectory(ModuleA)
    

    ModuleA folder´s CMake:

    qt_add_qml_module(ModuleA
        URI Modules.ModuleA
        SHARED
        QML_FILES
            ItemA.qml
    )
    

    App folder´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 ModuleA QML module will be put under:
    build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\Modules\ModuleA

    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

    So the Main.qml´s statement import Modules.ModuleA does not find the module.
    But writing import ModuleA instead 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 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.

    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"

    JKSHJ 1 Reply Last reply
    2
    • G GergoK

      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 the DEPENDENCIES 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.qml
      

      The 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)
      

      sources folder´s CMake:

      add_subdirectory(Modules)
      add_subdirectory(App)
      

      Modules folder´s CMake:

      add_subdirectory(ModuleA)
      

      ModuleA folder´s CMake:

      qt_add_qml_module(ModuleA
          URI Modules.ModuleA
          SHARED
          QML_FILES
              ItemA.qml
      )
      

      App folder´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 ModuleA QML module will be put under:
      build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug\sources\Modules\ModuleA

      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

      So the Main.qml´s statement import Modules.ModuleA does not find the module.
      But writing import ModuleA instead 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 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.

      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"

      JKSHJ Offline
      JKSHJ Offline
      JKSH
      Moderators
      wrote last edited by
      #2

      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 toolchain

      I 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)

      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

      1 Reply Last reply
      0
      • G Offline
        G Offline
        GergoK
        wrote last edited by
        #3

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

        JKSHJ 1 Reply Last reply
        0
        • G GergoK

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

          JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote last edited by JKSH
          #4

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

          The easiest ways to make things work are:

          • Change your library from SHARED to STATIC, 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 the DEPENDENCIES TARGET

          IMHO, that section oversimplifies things because:

          • DEPENDENCIES TARGET doesn't help your un-deployed executable find your dynamically-linked modules, as you've found out
          • DEPENDENCIES TARGET doesn'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.

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          1 Reply Last reply
          1
          • G Offline
            G Offline
            GergoK
            wrote last edited by
            #5

            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=2617125

            Just like you said setting the QT_QML_OUTPUT_DIRECTORY is 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.

            1 Reply Last reply
            0
            • G GergoK has marked this topic as solved

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved