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
6 Posts 2 Posters 140 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. [EDIT: No, this was wrong. It was a bug in Qt 6.10.2 but fixed in Qt 6.11.0-beta3 --JKSH]

          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.

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

              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.

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

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

              Thanks 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 TARGET does put import paths inside qt.conf for the runtime engine to use without deploying.

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

              1 Reply Last reply
              0

              • Login

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