Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Installation and Deployment
  4. CMake installation of QML Module fail
QtWS25 Last Chance

CMake installation of QML Module fail

Scheduled Pinned Locked Moved Solved Installation and Deployment
cmakeinstallqt6windowsqml modules
8 Posts 2 Posters 3.7k Views
  • 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.
  • L Offline
    L Offline
    lucast
    wrote on 1 Feb 2024, 17:01 last edited by
    #1

    Hello everyone !
    I'm developing an application in QML with a C++ back-end.
    The project is based on CMake ≥ 3.21 and Qt-6.6.1

    I try to make a package (but first at least an installation folder) for my app, with all the necessary dependencies.

    I'm using the qt cmake macros mostly introduced in qt 6.3.
    For this post, I renamed the project as "MyProject", and the integrated QML module "MyProject_Module".

    CMakeFile.txt (simplified):

    cmake_minimum_required(VERSION 3.21)
    
    project(MyProject
        VERSION 0.0.0
        LANGUAGES CXX
    )
    
    qt_standard_project_setup()
    
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(Qt6 6.6
        REQUIRED COMPONENTS
        Core
        Quick
        Qml
        Svg
        Widgets #Needed for MessageDialog
    )
    
    set(SRC_PATH ${CMAKE_CURRENT_LIST_DIR}/sources/common)
    
    qt_add_executable(${PROJECT_NAME}
        ${SRC_PATH}/main.cpp
        ${SRC_PATH}/StdAfx.h
        ${CMAKE_CURRENT_LIST_DIR}/README.md
        ${CMAKE_CURRENT_LIST_DIR}/.gitignore
    )
    
    qt_add_qml_module(${PROJECT_NAME}
        URI ${PROJECT_NAME}_Module
        VERSION 1.0
        RESOURCE_PREFIX ":/qt/qml/" 
        QML_FILES
            qml/DM_MainWindow.qml            #My QML files
            qml/DM_DeviceListSelector.qml 
        SOURCES
            ${SRC_PATH}/DM_Device.cpp        #Some QML elements in C++
            ${SRC_PATH}/DM_Device.h
    )
    
    target_include_directories(${PROJECT_NAME}
        PRIVATE ${SRC_PATH}
    )
    
    target_link_libraries(${PROJECT_NAME}
        PUBLIC
            Qt6::Core
            Qt6::Quick
            Qt6::Qml
            Qt6::Svg
            Qt6::Widgets #Needed for MessageDialog
    )
    
    set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/_install")
    install(TARGETS ${PROJECT_NAME}
        BUNDLE DESTINATION .
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    )
    
    qt_generate_deploy_qml_app_script(
        TARGET ${PROJECT_NAME}
        OUTPUT_SCRIPT deploy_qml_script
        NO_TRANSLATIONS
    )
    
    install(SCRIPT ${deploy_qml_script})
    

    When I run cmake --target install command, it install most of the dependences I want, but not the MyProject_Module.

    Here is the result target tree :

    _install
    ├── bin
        ├── MyProject.exe
        ├── All assets I requested to copy
        ├── qt.conf
        └── Qt .dlls installed by windeployqt (Qt6Core, Qt6Gui, opengl32sw...)
    ├── plugin
        ├── generic
        ├── iconengines
        ├── imageformats
        ├── networkinformation
        ├── platforminputcontexts
        ├── platforms
        ├── qmltooling
        ├── styles
        └── tls
    ├── qml
        ├── Qt (->qmlDir + dll from Qt modules)
        ├── QtQml  (->qmlDir + dll from QtQml modules)
        └── QtQuick  (->qmlDir + dll from QtQuick modules)
    

    My "MyPoject_Module" folder containing the qmlDir should have been copied into the _install/qml folder next to Qt's modules, but it's not and I don't manage to understand why...
    When I copy this folder here by hand, the app can be launched.

    I've edited the script generated by qt_generate_deploy_qml_app_script (and force to use it in install) to have more debug informations.

    <build-dir>/.qt/deploy_qml_app_MyProject_<some numbers>.cmake (modified for debug) :

    include(<build-dir>/.qt/QtDeploySupport.cmake)
    include("${CMAKE_CURRENT_LIST_DIR}/MyProject-plugins.cmake" OPTIONAL)
    set(__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "ZlibPrivate;EntryPointPrivate;Core;Gui;QmlIntegration;Network;Qml;QmlModels;OpenGL;Quick;Svg;Widgets")
    
    qt_deploy_qml_imports(TARGET MyProject 
        PLUGINS_FOUND plugins_found 
        NO_QT_IMPORTS #[Edited] To not be disturbed by Qt modules
        )
    
    include(CMakePrintHelpers)
    cmake_print_variables(plugins_found )
    
    qt_deploy_runtime_dependencies(
        EXECUTABLE <build-dir>/MyProject.exe
        ADDITIONAL_MODULES ${plugins_found}
        GENERATE_QT_CONF
        NO_TRANSLATIONS
    )
    

    When installing this script, I found that "plugins_found" variable is empty. (and it's full of qt modules when NO_QT_IMPORTS isn't defined)

    As I've seen from doc examples, and some projects from github, there isn't more thing to do to make it works.

    That is my first experience in deploying a qml application, and I'm running out of ideas for this problem. Does anyone see something that I do wrong, or something missing ?
    Note that I didn't publish the whole CMakeList.txt like including some external libs, that I think are not related to this issue.

    M 1 Reply Last reply 1 Feb 2024, 18:05
    0
    • M Mesrine
      2 Feb 2024, 09:56

      @lucast
      qt_generate_deploy_qml_app_script is part of the Qt CMake deployment API .

      This API takes care of deploying Qt dependencies of your project. Your module as your application has to be installed(by using CMake in this case).

      L Offline
      L Offline
      lucast
      wrote on 2 Feb 2024, 14:38 last edited by
      #5

      @Mesrine

      I've finally understand what was wrong in my project. I post the solution here hope this will help other people in futur !

      I misunderstood how to work with a QML module that is integrated in the target.

      As the qt-add-qml-module() documentation says about "Executable as a QML module",

      "In this case, there will be no plugin library, since the QML module will always be loaded directly as part of the application."

      This is why the _qt_internal_deploy_qml_imports_for_target() exclude the line of my internal module, and doesn't copy it at installation in the <install-dir>/qml/ directory.

      Now I've understood why the qt_generate_deploy_qml_app_script doesn't install my module. But I was still anoyed about having to provide a qmlDir for this module in the install dir, while this module should already be a part of the binary ressources...

      My mistake was that I called this API (from Qt6.5) to load the main QML file in my main.cpp, which search for DM_MainWindow.qml in QML Import Path

      engine.loadFromModule("MyProject_Module", "DM_MainWindow.qml");
      

      The qmlDir file, was usefull to the app because it make a link between the QML Resources's RelativePath+FileName and the FileName. Since, when passing QML Resources to qt_add_qml_module(), it's with the RelativePath+FileName format.

      To fix my problem, I've found 2 solution :

      • Solution 1 : Use old API to load QML Resource from Url :
      engine.load(QUrl(QStringLiteral("qrc:/qt/qml/MyProject_Module/qml/DM_MainWindow.qml")));
      

      where :
      - "qrc:/qt/qml" is from RESOURCE_PREFIX "qt/qml/" declaration in qt_add_qml_module()
      - "MyProject_Module" is from the URI ${PROJECT_NAME}_Module declaration in qt_add_qml_module()
      - "qml/DM_MainWindow.qml" is from the QML Resource passed to qt_add_qml_module() in RelativePath+FileName format

      • Solution 2 : Use QT_RESOURCE_ALIAS property on QML Resource files to save the link made by the qmlDir file, directly in the binary. I've so modified my CMakeList.txt as follow :
      set(QML_RESOURCES_PATH qml)
      set(QML_RESOURCES
          DM_MainWindow.qml
          DM_DeviceListSelector.qml
      )
      
      foreach(qmlFile IN LISTS QML_RESOURCES)
          set_source_files_properties(${QML_RESOURCES_PATH}/${qmlFile} PROPERTIES QT_RESOURCE_ALIAS ${qmlFile})
      endforeach()
      
      list(TRANSFORM QML_RESOURCES PREPEND "${QML_RESOURCES_PATH}/")
      
      qt_add_qml_module(${PROJECT_NAME}
          URI ${PROJECT_NAME}_Module
          VERSION 1.0
          RESOURCE_PREFIX "qt/qml/"
          QML_FILES
              ${QML_RESOURCES}
          SOURCES
              ${SRC_PATH}/DM_Device.cpp        #Some QML elements in C++
              ${SRC_PATH}/DM_Device.h
      )
      
      #No need to install module's directory then !
      

      With any of these 2 solutions, I'm now able to install the app and launch it, without the MyProject_Module/qmlDir in the installation directory. I would prefer the Solution 2 because it use the most recent APIs, and seems more close to the documentation.

      Thanks @Mesrine for your help !

      M 1 Reply Last reply 2 Feb 2024, 15:05
      0
      • L lucast
        1 Feb 2024, 17:01

        Hello everyone !
        I'm developing an application in QML with a C++ back-end.
        The project is based on CMake ≥ 3.21 and Qt-6.6.1

        I try to make a package (but first at least an installation folder) for my app, with all the necessary dependencies.

        I'm using the qt cmake macros mostly introduced in qt 6.3.
        For this post, I renamed the project as "MyProject", and the integrated QML module "MyProject_Module".

        CMakeFile.txt (simplified):

        cmake_minimum_required(VERSION 3.21)
        
        project(MyProject
            VERSION 0.0.0
            LANGUAGES CXX
        )
        
        qt_standard_project_setup()
        
        set(CMAKE_AUTOMOC ON)
        set(CMAKE_CXX_STANDARD_REQUIRED ON)
        
        find_package(Qt6 6.6
            REQUIRED COMPONENTS
            Core
            Quick
            Qml
            Svg
            Widgets #Needed for MessageDialog
        )
        
        set(SRC_PATH ${CMAKE_CURRENT_LIST_DIR}/sources/common)
        
        qt_add_executable(${PROJECT_NAME}
            ${SRC_PATH}/main.cpp
            ${SRC_PATH}/StdAfx.h
            ${CMAKE_CURRENT_LIST_DIR}/README.md
            ${CMAKE_CURRENT_LIST_DIR}/.gitignore
        )
        
        qt_add_qml_module(${PROJECT_NAME}
            URI ${PROJECT_NAME}_Module
            VERSION 1.0
            RESOURCE_PREFIX ":/qt/qml/" 
            QML_FILES
                qml/DM_MainWindow.qml            #My QML files
                qml/DM_DeviceListSelector.qml 
            SOURCES
                ${SRC_PATH}/DM_Device.cpp        #Some QML elements in C++
                ${SRC_PATH}/DM_Device.h
        )
        
        target_include_directories(${PROJECT_NAME}
            PRIVATE ${SRC_PATH}
        )
        
        target_link_libraries(${PROJECT_NAME}
            PUBLIC
                Qt6::Core
                Qt6::Quick
                Qt6::Qml
                Qt6::Svg
                Qt6::Widgets #Needed for MessageDialog
        )
        
        set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/_install")
        install(TARGETS ${PROJECT_NAME}
            BUNDLE DESTINATION .
            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
            RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        )
        
        qt_generate_deploy_qml_app_script(
            TARGET ${PROJECT_NAME}
            OUTPUT_SCRIPT deploy_qml_script
            NO_TRANSLATIONS
        )
        
        install(SCRIPT ${deploy_qml_script})
        

        When I run cmake --target install command, it install most of the dependences I want, but not the MyProject_Module.

        Here is the result target tree :

        _install
        ├── bin
            ├── MyProject.exe
            ├── All assets I requested to copy
            ├── qt.conf
            └── Qt .dlls installed by windeployqt (Qt6Core, Qt6Gui, opengl32sw...)
        ├── plugin
            ├── generic
            ├── iconengines
            ├── imageformats
            ├── networkinformation
            ├── platforminputcontexts
            ├── platforms
            ├── qmltooling
            ├── styles
            └── tls
        ├── qml
            ├── Qt (->qmlDir + dll from Qt modules)
            ├── QtQml  (->qmlDir + dll from QtQml modules)
            └── QtQuick  (->qmlDir + dll from QtQuick modules)
        

        My "MyPoject_Module" folder containing the qmlDir should have been copied into the _install/qml folder next to Qt's modules, but it's not and I don't manage to understand why...
        When I copy this folder here by hand, the app can be launched.

        I've edited the script generated by qt_generate_deploy_qml_app_script (and force to use it in install) to have more debug informations.

        <build-dir>/.qt/deploy_qml_app_MyProject_<some numbers>.cmake (modified for debug) :

        include(<build-dir>/.qt/QtDeploySupport.cmake)
        include("${CMAKE_CURRENT_LIST_DIR}/MyProject-plugins.cmake" OPTIONAL)
        set(__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "ZlibPrivate;EntryPointPrivate;Core;Gui;QmlIntegration;Network;Qml;QmlModels;OpenGL;Quick;Svg;Widgets")
        
        qt_deploy_qml_imports(TARGET MyProject 
            PLUGINS_FOUND plugins_found 
            NO_QT_IMPORTS #[Edited] To not be disturbed by Qt modules
            )
        
        include(CMakePrintHelpers)
        cmake_print_variables(plugins_found )
        
        qt_deploy_runtime_dependencies(
            EXECUTABLE <build-dir>/MyProject.exe
            ADDITIONAL_MODULES ${plugins_found}
            GENERATE_QT_CONF
            NO_TRANSLATIONS
        )
        

        When installing this script, I found that "plugins_found" variable is empty. (and it's full of qt modules when NO_QT_IMPORTS isn't defined)

        As I've seen from doc examples, and some projects from github, there isn't more thing to do to make it works.

        That is my first experience in deploying a qml application, and I'm running out of ideas for this problem. Does anyone see something that I do wrong, or something missing ?
        Note that I didn't publish the whole CMakeList.txt like including some external libs, that I think are not related to this issue.

        M Offline
        M Offline
        Mesrine
        wrote on 1 Feb 2024, 18:05 last edited by
        #2

        @lucast

        I normally install that folder also using CMake install macro.
        I do not know of any qt macro to copy that folder and i think the folder should be installed.
        In your case, it should be like

        install(DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME}_Module
            DESTINATION ${CMAKE_INSTALL_PREFIX}/qml
        )
        
        1 Reply Last reply
        0
        • L Offline
          L Offline
          lucast
          wrote on 2 Feb 2024, 09:40 last edited by lucast 2 Feb 2024, 09:42
          #3

          @Mesrine

          Thank you for your answer ! Yes, this is what I think to do if I don't find other solutions.

          The reason I created this topic, is because, according to the qt_generate_deploy_qml_app_script() documentation, I supposed that this command should have done it for me :

          "Installing an executable target that is also a QML module requires deploying a number of things in addition to the target itself. Qt libraries and other libraries from the project, Qt plugins, and the runtime parts of all QML modules the application uses may all need to be installed too.
          [...]
          QML modules are installed to the appropriate location for the platform"

          Moreover, in the example provided, there isn't other lines after :

          qt_generate_deploy_qml_app_script(
             TARGET MyApp
             OUTPUT_SCRIPT deploy_script
             #[...]
          )
          install(deploy_script)
          

          I've also noticed it in github projects such as addhoursandminutes, HLA-NoVR-Launcher or nheko projects.

          Also, to be sure my module is well created, I've put this command just before the qt_generate_deploy_qml_app_script() :

          qt_query_qml_module(${PROJECT_NAME}
              URI module_uri
              VERSION module_version
              PLUGIN_TARGET module_plugin_target
              TARGET_PATH module_target_path
              QMLDIR module_qmldir
              TYPEINFO module_typeinfo
              QML_FILES module_qml_files
              QML_FILES_DEPLOY_PATHS qml_files_deploy_paths
              RESOURCES module_resources
              RESOURCES_DEPLOY_PATHS resources_deploy_paths
          )
          

          And this return me correct results and path :

          [cmake] -- module_uri="MyProject_Module"
          [cmake] -- module_version="1.0"
          [cmake] -- module_plugin_target=""
          [cmake] -- module_target_path="MyProject_Module"
          [cmake] -- module_qmldir="<build-dir>/MyProject_Module/qmldir"
          [cmake] -- module_typeinfo="<build-dir>/MyProject_Module/MyProject.qmltypes"
          [cmake] -- module_qml_files="<project-dir>/qml/DM_MainWindow.qml;<project-dir>/qml/DM_DeviceListSelector.qml
          [cmake] -- qml_files_deploy_paths="qml/DM_MainWindow.qml;qml/DM_DeviceListSelector.qml"
          [cmake] -- module_resources=""
          [cmake] -- resources_deploy_paths=""
          

          I've also inspected the commands and scripts generated under qt_generate_deploy_qml_app_script():

          1- The qt_deploy_qml_imports() generate a cmake file under <build-dir>/.qt/deploy_qml_imports/MyProject.cmake, which contain this code :

          # Auto-generated deploy QML imports script for target "MyProject".
          # Do not edit, all changes will be lost.
          # This file should only be included by qt_deploy_qml_imports().
          
          set(__qt_opts )
          if(arg_NO_QT_IMPORTS)
              list(APPEND __qt_opts NO_QT_IMPORTS)
          endif()
          
          _qt_internal_deploy_qml_imports_for_target(
              ${__qt_opts}
              IMPORTS_FILE "<build-dir>/.qt_plugins/Qt6_QmlPlugins_Imports_MyProject.cmake"
              PLUGINS_FOUND __qt_internal_plugins_found
              QML_DIR     "${arg_QML_DIR}"
              PLUGINS_DIR "${arg_PLUGINS_DIR}"
          )
          
          if(arg_PLUGINS_FOUND)
              set(${arg_PLUGINS_FOUND} "${__qt_internal_plugins_found}" PARENT_SCOPE)
          endif()
          
          1. The <build-dir>/.qt_plugins/Qt6_QmlPlugins_Imports_MyProject.cmake contains a list of Qt modules, including my MyProject_Module ! (See qml_import_scanner_import_29 ):
          set(qml_import_scanner_imports_count 31)
          set(qml_import_scanner_import_0 "CLASSNAME;QtQuick2Plugin;LINKTARGET;Qt6::qtquick2plugin;NAME;QtQuick;PATH;C:/Qt/6.6.1/mingw_64/qml/QtQuick;PLUGIN;qtquick2plugin;PLUGINISOPTIONAL;;PREFER;:/qt-project.org/imports/QtQuick/;RELATIVEPATH;QtQuick;TYPE;module;")
          set(qml_import_scanner_import_1 "CLASSNAME;QtQmlMetaPlugin;[...]")
          [...] #Other Qt modules (qml_import_scanner_import_2...26)
          set(qml_import_scanner_import_27 "CLASSNAME;QtQuickLayoutsPlugin;[...]")
          set(qml_import_scanner_import_28 "NAME;QtQuick.Controls.Styles;TYPE;module;")
          set(qml_import_scanner_import_29 "COMPONENTS;<build-dir>/MyProject_Module/qml/DM_DeviceListSelector.qml;<build-dir>/MyProject_Module/qml/DM_MainWindow.qml;NAME;MyProject_Module;PATH;<build-dir>/MyProject_Module;PREFER;:/:/qt/qml/MyProject_Module/;RELATIVEPATH;MyProject_Module;TYPE;module;")
          set(qml_import_scanner_import_30 "CLASSNAME;QtLabsPlatformPlugin;[...]")
          

          I don't have any warning (except a "Warning: using binaries from different directories" but not sure it's related), so I don't know why the _qt_internal_deploy_qml_imports_for_target() doesn't parse my MyProject_Module :(

          M 1 Reply Last reply 2 Feb 2024, 09:56
          0
          • L lucast
            2 Feb 2024, 09:40

            @Mesrine

            Thank you for your answer ! Yes, this is what I think to do if I don't find other solutions.

            The reason I created this topic, is because, according to the qt_generate_deploy_qml_app_script() documentation, I supposed that this command should have done it for me :

            "Installing an executable target that is also a QML module requires deploying a number of things in addition to the target itself. Qt libraries and other libraries from the project, Qt plugins, and the runtime parts of all QML modules the application uses may all need to be installed too.
            [...]
            QML modules are installed to the appropriate location for the platform"

            Moreover, in the example provided, there isn't other lines after :

            qt_generate_deploy_qml_app_script(
               TARGET MyApp
               OUTPUT_SCRIPT deploy_script
               #[...]
            )
            install(deploy_script)
            

            I've also noticed it in github projects such as addhoursandminutes, HLA-NoVR-Launcher or nheko projects.

            Also, to be sure my module is well created, I've put this command just before the qt_generate_deploy_qml_app_script() :

            qt_query_qml_module(${PROJECT_NAME}
                URI module_uri
                VERSION module_version
                PLUGIN_TARGET module_plugin_target
                TARGET_PATH module_target_path
                QMLDIR module_qmldir
                TYPEINFO module_typeinfo
                QML_FILES module_qml_files
                QML_FILES_DEPLOY_PATHS qml_files_deploy_paths
                RESOURCES module_resources
                RESOURCES_DEPLOY_PATHS resources_deploy_paths
            )
            

            And this return me correct results and path :

            [cmake] -- module_uri="MyProject_Module"
            [cmake] -- module_version="1.0"
            [cmake] -- module_plugin_target=""
            [cmake] -- module_target_path="MyProject_Module"
            [cmake] -- module_qmldir="<build-dir>/MyProject_Module/qmldir"
            [cmake] -- module_typeinfo="<build-dir>/MyProject_Module/MyProject.qmltypes"
            [cmake] -- module_qml_files="<project-dir>/qml/DM_MainWindow.qml;<project-dir>/qml/DM_DeviceListSelector.qml
            [cmake] -- qml_files_deploy_paths="qml/DM_MainWindow.qml;qml/DM_DeviceListSelector.qml"
            [cmake] -- module_resources=""
            [cmake] -- resources_deploy_paths=""
            

            I've also inspected the commands and scripts generated under qt_generate_deploy_qml_app_script():

            1- The qt_deploy_qml_imports() generate a cmake file under <build-dir>/.qt/deploy_qml_imports/MyProject.cmake, which contain this code :

            # Auto-generated deploy QML imports script for target "MyProject".
            # Do not edit, all changes will be lost.
            # This file should only be included by qt_deploy_qml_imports().
            
            set(__qt_opts )
            if(arg_NO_QT_IMPORTS)
                list(APPEND __qt_opts NO_QT_IMPORTS)
            endif()
            
            _qt_internal_deploy_qml_imports_for_target(
                ${__qt_opts}
                IMPORTS_FILE "<build-dir>/.qt_plugins/Qt6_QmlPlugins_Imports_MyProject.cmake"
                PLUGINS_FOUND __qt_internal_plugins_found
                QML_DIR     "${arg_QML_DIR}"
                PLUGINS_DIR "${arg_PLUGINS_DIR}"
            )
            
            if(arg_PLUGINS_FOUND)
                set(${arg_PLUGINS_FOUND} "${__qt_internal_plugins_found}" PARENT_SCOPE)
            endif()
            
            1. The <build-dir>/.qt_plugins/Qt6_QmlPlugins_Imports_MyProject.cmake contains a list of Qt modules, including my MyProject_Module ! (See qml_import_scanner_import_29 ):
            set(qml_import_scanner_imports_count 31)
            set(qml_import_scanner_import_0 "CLASSNAME;QtQuick2Plugin;LINKTARGET;Qt6::qtquick2plugin;NAME;QtQuick;PATH;C:/Qt/6.6.1/mingw_64/qml/QtQuick;PLUGIN;qtquick2plugin;PLUGINISOPTIONAL;;PREFER;:/qt-project.org/imports/QtQuick/;RELATIVEPATH;QtQuick;TYPE;module;")
            set(qml_import_scanner_import_1 "CLASSNAME;QtQmlMetaPlugin;[...]")
            [...] #Other Qt modules (qml_import_scanner_import_2...26)
            set(qml_import_scanner_import_27 "CLASSNAME;QtQuickLayoutsPlugin;[...]")
            set(qml_import_scanner_import_28 "NAME;QtQuick.Controls.Styles;TYPE;module;")
            set(qml_import_scanner_import_29 "COMPONENTS;<build-dir>/MyProject_Module/qml/DM_DeviceListSelector.qml;<build-dir>/MyProject_Module/qml/DM_MainWindow.qml;NAME;MyProject_Module;PATH;<build-dir>/MyProject_Module;PREFER;:/:/qt/qml/MyProject_Module/;RELATIVEPATH;MyProject_Module;TYPE;module;")
            set(qml_import_scanner_import_30 "CLASSNAME;QtLabsPlatformPlugin;[...]")
            

            I don't have any warning (except a "Warning: using binaries from different directories" but not sure it's related), so I don't know why the _qt_internal_deploy_qml_imports_for_target() doesn't parse my MyProject_Module :(

            M Offline
            M Offline
            Mesrine
            wrote on 2 Feb 2024, 09:56 last edited by
            #4

            @lucast
            qt_generate_deploy_qml_app_script is part of the Qt CMake deployment API .

            This API takes care of deploying Qt dependencies of your project. Your module as your application has to be installed(by using CMake in this case).

            L 1 Reply Last reply 2 Feb 2024, 14:38
            0
            • M Mesrine
              2 Feb 2024, 09:56

              @lucast
              qt_generate_deploy_qml_app_script is part of the Qt CMake deployment API .

              This API takes care of deploying Qt dependencies of your project. Your module as your application has to be installed(by using CMake in this case).

              L Offline
              L Offline
              lucast
              wrote on 2 Feb 2024, 14:38 last edited by
              #5

              @Mesrine

              I've finally understand what was wrong in my project. I post the solution here hope this will help other people in futur !

              I misunderstood how to work with a QML module that is integrated in the target.

              As the qt-add-qml-module() documentation says about "Executable as a QML module",

              "In this case, there will be no plugin library, since the QML module will always be loaded directly as part of the application."

              This is why the _qt_internal_deploy_qml_imports_for_target() exclude the line of my internal module, and doesn't copy it at installation in the <install-dir>/qml/ directory.

              Now I've understood why the qt_generate_deploy_qml_app_script doesn't install my module. But I was still anoyed about having to provide a qmlDir for this module in the install dir, while this module should already be a part of the binary ressources...

              My mistake was that I called this API (from Qt6.5) to load the main QML file in my main.cpp, which search for DM_MainWindow.qml in QML Import Path

              engine.loadFromModule("MyProject_Module", "DM_MainWindow.qml");
              

              The qmlDir file, was usefull to the app because it make a link between the QML Resources's RelativePath+FileName and the FileName. Since, when passing QML Resources to qt_add_qml_module(), it's with the RelativePath+FileName format.

              To fix my problem, I've found 2 solution :

              • Solution 1 : Use old API to load QML Resource from Url :
              engine.load(QUrl(QStringLiteral("qrc:/qt/qml/MyProject_Module/qml/DM_MainWindow.qml")));
              

              where :
              - "qrc:/qt/qml" is from RESOURCE_PREFIX "qt/qml/" declaration in qt_add_qml_module()
              - "MyProject_Module" is from the URI ${PROJECT_NAME}_Module declaration in qt_add_qml_module()
              - "qml/DM_MainWindow.qml" is from the QML Resource passed to qt_add_qml_module() in RelativePath+FileName format

              • Solution 2 : Use QT_RESOURCE_ALIAS property on QML Resource files to save the link made by the qmlDir file, directly in the binary. I've so modified my CMakeList.txt as follow :
              set(QML_RESOURCES_PATH qml)
              set(QML_RESOURCES
                  DM_MainWindow.qml
                  DM_DeviceListSelector.qml
              )
              
              foreach(qmlFile IN LISTS QML_RESOURCES)
                  set_source_files_properties(${QML_RESOURCES_PATH}/${qmlFile} PROPERTIES QT_RESOURCE_ALIAS ${qmlFile})
              endforeach()
              
              list(TRANSFORM QML_RESOURCES PREPEND "${QML_RESOURCES_PATH}/")
              
              qt_add_qml_module(${PROJECT_NAME}
                  URI ${PROJECT_NAME}_Module
                  VERSION 1.0
                  RESOURCE_PREFIX "qt/qml/"
                  QML_FILES
                      ${QML_RESOURCES}
                  SOURCES
                      ${SRC_PATH}/DM_Device.cpp        #Some QML elements in C++
                      ${SRC_PATH}/DM_Device.h
              )
              
              #No need to install module's directory then !
              

              With any of these 2 solutions, I'm now able to install the app and launch it, without the MyProject_Module/qmlDir in the installation directory. I would prefer the Solution 2 because it use the most recent APIs, and seems more close to the documentation.

              Thanks @Mesrine for your help !

              M 1 Reply Last reply 2 Feb 2024, 15:05
              0
              • L lucast has marked this topic as solved on 2 Feb 2024, 14:38
              • L lucast has marked this topic as unsolved on 2 Feb 2024, 14:39
              • L lucast has marked this topic as solved on 2 Feb 2024, 14:39
              • L lucast
                2 Feb 2024, 14:38

                @Mesrine

                I've finally understand what was wrong in my project. I post the solution here hope this will help other people in futur !

                I misunderstood how to work with a QML module that is integrated in the target.

                As the qt-add-qml-module() documentation says about "Executable as a QML module",

                "In this case, there will be no plugin library, since the QML module will always be loaded directly as part of the application."

                This is why the _qt_internal_deploy_qml_imports_for_target() exclude the line of my internal module, and doesn't copy it at installation in the <install-dir>/qml/ directory.

                Now I've understood why the qt_generate_deploy_qml_app_script doesn't install my module. But I was still anoyed about having to provide a qmlDir for this module in the install dir, while this module should already be a part of the binary ressources...

                My mistake was that I called this API (from Qt6.5) to load the main QML file in my main.cpp, which search for DM_MainWindow.qml in QML Import Path

                engine.loadFromModule("MyProject_Module", "DM_MainWindow.qml");
                

                The qmlDir file, was usefull to the app because it make a link between the QML Resources's RelativePath+FileName and the FileName. Since, when passing QML Resources to qt_add_qml_module(), it's with the RelativePath+FileName format.

                To fix my problem, I've found 2 solution :

                • Solution 1 : Use old API to load QML Resource from Url :
                engine.load(QUrl(QStringLiteral("qrc:/qt/qml/MyProject_Module/qml/DM_MainWindow.qml")));
                

                where :
                - "qrc:/qt/qml" is from RESOURCE_PREFIX "qt/qml/" declaration in qt_add_qml_module()
                - "MyProject_Module" is from the URI ${PROJECT_NAME}_Module declaration in qt_add_qml_module()
                - "qml/DM_MainWindow.qml" is from the QML Resource passed to qt_add_qml_module() in RelativePath+FileName format

                • Solution 2 : Use QT_RESOURCE_ALIAS property on QML Resource files to save the link made by the qmlDir file, directly in the binary. I've so modified my CMakeList.txt as follow :
                set(QML_RESOURCES_PATH qml)
                set(QML_RESOURCES
                    DM_MainWindow.qml
                    DM_DeviceListSelector.qml
                )
                
                foreach(qmlFile IN LISTS QML_RESOURCES)
                    set_source_files_properties(${QML_RESOURCES_PATH}/${qmlFile} PROPERTIES QT_RESOURCE_ALIAS ${qmlFile})
                endforeach()
                
                list(TRANSFORM QML_RESOURCES PREPEND "${QML_RESOURCES_PATH}/")
                
                qt_add_qml_module(${PROJECT_NAME}
                    URI ${PROJECT_NAME}_Module
                    VERSION 1.0
                    RESOURCE_PREFIX "qt/qml/"
                    QML_FILES
                        ${QML_RESOURCES}
                    SOURCES
                        ${SRC_PATH}/DM_Device.cpp        #Some QML elements in C++
                        ${SRC_PATH}/DM_Device.h
                )
                
                #No need to install module's directory then !
                

                With any of these 2 solutions, I'm now able to install the app and launch it, without the MyProject_Module/qmlDir in the installation directory. I would prefer the Solution 2 because it use the most recent APIs, and seems more close to the documentation.

                Thanks @Mesrine for your help !

                M Offline
                M Offline
                Mesrine
                wrote on 2 Feb 2024, 15:05 last edited by
                #6

                @lucast said in CMake installation of QML Module fail:

                In this case, there will be no plugin library, since the QML module will always be loaded directly as part of the application."

                True, you do not need to install the plugin target or the module dir in that case. Because it is compiled in the application. I was referring when installing a module library.

                Solution 1 : Use old API to load QML Resource from Url :

                I prefer solution 1, which is cleaner. Why do you say is the old API?

                L 1 Reply Last reply 2 Feb 2024, 16:53
                0
                • M Mesrine
                  2 Feb 2024, 15:05

                  @lucast said in CMake installation of QML Module fail:

                  In this case, there will be no plugin library, since the QML module will always be loaded directly as part of the application."

                  True, you do not need to install the plugin target or the module dir in that case. Because it is compiled in the application. I was referring when installing a module library.

                  Solution 1 : Use old API to load QML Resource from Url :

                  I prefer solution 1, which is cleaner. Why do you say is the old API?

                  L Offline
                  L Offline
                  lucast
                  wrote on 2 Feb 2024, 16:53 last edited by lucast 2 Feb 2024, 16:55
                  #7

                  @Mesrine said in CMake installation of QML Module fail:

                  I prefer solution 1, which is cleaner. Why do you say is the old API?

                  I said that because the loadFromModule API is from Qt6.5, and load(Url()) is from Qt5. So loadFromModule appears to me to be the most recent way to load a qml resource from c++.
                  The name also match the CMake and QML strategy, which considers internal QML resources as a "module".

                  This solution also avoid me to have the .qml files's relative path in the resource's url. I prefer to distinct them, and access files in resources directly by their names.

                  I may have used "oldest API" instead of "old API" !

                  M 1 Reply Last reply 2 Feb 2024, 17:20
                  1
                  • L lucast
                    2 Feb 2024, 16:53

                    @Mesrine said in CMake installation of QML Module fail:

                    I prefer solution 1, which is cleaner. Why do you say is the old API?

                    I said that because the loadFromModule API is from Qt6.5, and load(Url()) is from Qt5. So loadFromModule appears to me to be the most recent way to load a qml resource from c++.
                    The name also match the CMake and QML strategy, which considers internal QML resources as a "module".

                    This solution also avoid me to have the .qml files's relative path in the resource's url. I prefer to distinct them, and access files in resources directly by their names.

                    I may have used "oldest API" instead of "old API" !

                    M Offline
                    M Offline
                    Mesrine
                    wrote on 2 Feb 2024, 17:20 last edited by
                    #8

                    @lucast

                    Thanks, indeed it aligns better with the new design.
                    I will try to use loadFromModule API from now on
                    According to this will improve compilation time when changing qml files, that is something I was looking for.

                    1 Reply Last reply
                    0

                    5/8

                    2 Feb 2024, 14:38

                    • Login

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