Search code examples
cmakeqmlqt6

QQmlApplicationEngine failed to load component when building QML app with CMake without IDE


I am working on QML application. For now, this application only consists of different QML files and one main.cpp file with only main function. Later on, I will be also adding business logic to it.

I am building an application with CMake without using any IDE.

My application builds and links with no problem, but when I try to run the application it always fails to load Main.qml and start the application.

qt.qml.import: addImportPath: "/home/username/Qt/6.5.3/gcc_64/qml"
qt.qml.import: addImportPath: "qrc:/qt/qml"
qt.qml.import: addImportPath: "qrc:/qt-project.org/imports"
qt.qml.import: addImportPath: "/home/username/Project/ApplicationProject/build"
qt.qml.import: addLibraryImport:  "UI" version ' invalid ' as ""
qt.qml.import: importExtension:  loaded "/home/username/Project/ApplicationProject/build/UI/qmldir"
qt.qml.import: resolvePlugin Could not resolve dynamic plugin with base name "UIplugin" in "/home/username/Project/ApplicationProject/build/UI"  file does not exist
qt.qml.import: locateLocalQmldir: UI module's qmldir found at ""
qt.qml.import: LoadHelper: Errors loading  "UI" QList(file:///home/username/Project/ApplicationProject/build/UI/qmldir: module "UI" plugin "UIplugin" not found)
QQmlApplicationEngine failed to load component
<Unknown File>: No module named "UI" found

I've set export QML_IMPORT_TRACE=1 for verbose output

My simplified root CMakeLists.txt file looks like this:

cmake_minimum_required(VERSION 3.20)

project(App VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Quick Gui QuickControls2 Qml Svg)
qt_standard_project_setup(REQUIRES 6.5)

qt_add_executable(App
    src/main.cpp
)

add_subdirectory(UI)

target_link_libraries(App PRIVATE Qt6::Quick Qt6::Gui Qt6::QuickControls2 Qt6::Svg Qt6::Qml)
target_link_libraries(App PRIVATE UI)

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_INSTALL_PREFIX "/usr/lib/" CACHE PATH "..." FORCE)
endif()

install(TARGETS App
    BUNDLE  DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

qt_generate_deploy_qml_app_script(
    TARGET App
    OUTPUT_SCRIPT deploy_script
    NO_UNSUPPORTED_PLATFORM_ERROR
    DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)

install(SCRIPT ${deploy_script})

The CMakeLists.txt in UI folder, where Main.qml is placed, looks like this:

qt_add_qml_module(UI
    URI UI
    NO_PLUGIN
    VERSION 1.0
    QML_FILES
        Main.qml
)

target_link_libraries(UI PUBLIC
    OtherQML1
    OtherQML2
    OtherQML3
    OtherQML4
)

add_subdirectory(OtherQML1)
add_subdirectory(OtherQML2)
add_subdirectory(OtherQML3)
add_subdirectory(OtherQML4)

And my main.cpp file, which is in root project folder in src directory:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickStyle>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickStyle::setStyle("Universal");

    QQmlApplicationEngine engine;
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
        &app, []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.loadFromModule("UI", "Main");

    return app.exec();
}

I've tried adding NO_PLUGIN option to qt_add_qml_module(UI call, as I'm not currently using any plugins or cpp files as backing target (if I'm correctly understanding the concept), but then it tries to load Main.qml and fails to find it:

qt.qml.import: addImportPath: "/home/username/Qt/6.5.3/gcc_64/qml"
qt.qml.import: addImportPath: "qrc:/qt/qml"
qt.qml.import: addImportPath: "qrc:/qt-project.org/imports"
qt.qml.import: addImportPath: "/home/username/Project/ApplicationProject/build"
qt.qml.import: addLibraryImport:  "UI" version ' invalid ' as ""
qt.qml.import: importExtension:  loaded "/home/username/Project/ApplicationProject/build/UI/qmldir"
qt.qml.import: resolvePlugin Could not resolve dynamic plugin with base name "UIplugin" in "/home/username/Project/ApplicationProject/build/UI"  file does not exist
qt.qml.import: locateLocalQmldir: UI module's qmldir found at ""
qt.qml.import: LoadHelper: Errors loading  "UI" QList(file:///home/username/Project/ApplicationProject/build/UI/qmldir: module "UI" plugin "UIplugin" not found)
QQmlApplicationEngine failed to load component
<Unknown File>: No module named "UI" found

I see that this is the path in qmldir in build/UI folder

module UI
typeinfo UI.qmltypes
prefer :/qt/qml/UI/
Main 1.0 Main.qml

in the same folder I have build/UI/UI_qml_module_dir_map.qrc, which defines alias to correct path:

<RCC>
  <qresource prefix="/">
    <file alias="/qt/qml/UI">/home/username/Project/ApplicationProject/build/UI</file>

  </qresource>
</RCC>

My questions are:

  1. How can I solve this issue and what is the reason for it? Is it due to my folder structure?

  2. Can someone reference to me some sources explaining QT Recourse System (qrc) and etc. I was reading documentation and can seem to grasp the concept. Where does qrc:/qt/qml path actually is? How to place modules there? Do I need to create my own paths relative to my build/install directories or should I add them to qrc:/qt/qml?


Solution

  • in root CMakeLists.txt change target_link_libraries(App PRIVATE UI) to target_link_libraries(App PRIVATE UIplugin)

    main.cpp:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickStyle>
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        QQuickStyle::setStyle("Universal");
        engine.addImportPath(":/");
    
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
            &app, []() { QCoreApplication::exit(-1); },
            Qt::QueuedConnection);
        engine.loadFromModule("UI", "Main");
    
        return app.exec();
    }
    

    The CMakeLists.txt in UI folder

    qt_add_qml_module(UI
            URI UI
            VERSION 1.0
            QML_FILES
                Main.qml
        )
        
        add_subdirectory(OtherQML1)
        add_subdirectory(OtherQML2)
        add_subdirectory(OtherQML3)
        add_subdirectory(OtherQML4)
        
        target_link_libraries(UI PUBLIC
            OtherQML1plugin
            OtherQML2plugin
            OtherQML3plugin
            OtherQML4plugin
        )
    
    • Remove your .qrc files and use cmakelist to add a qml file to the project.