Home > Mobile >  qmltyperegistration include path does not acknowledge subdirectories
qmltyperegistration include path does not acknowledge subdirectories

Time:12-20

I am trying to build a Qt project with qml. The qml metatype registration looks into the top level qml directories only. I would like to have it look into subdirectories as well.

The project is structured like this:

./CMakeLists.txt
./ui
./ui/MainWindow.qml
./src
./src/controller
./src/controller/Foo.cpp
./src/controller/FileController.cpp
./src/controller/FileController.h
./main.cpp

My CMakeLists.txt looks as follows:

cmake_minimum_required(VERSION 3.25)
project(testproject)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick Widgets)

qt_standard_project_setup()

qt_add_executable(testproject)
target_sources(testproject PRIVATE 
    main.cpp
)


target_link_libraries(testproject PRIVATE 
    Qt6::Widgets
    Qt6::Gui 
    Qt6::Quick 
)

set_target_properties(testproject PROPERTIES
        CXX_STANDARD 17
        CXX_STANDARD_REQUIRED ON
        CXX_EXTENSIONS OFF
        OUTPUT_NAME some_test_exec
)

target_include_directories(testproject PUBLIC ${PROJECT_SOURCE_DIR}/include)


qt_add_qml_module(testproject
        URI testproject
        VERSION 1.0
        SOURCES
            src/controller/FileController.h
            src/controller/FileController.cpp
        QML_FILES
            ui/MainWindow.qml
)

I have a main function which starts the application:

#include <iostream>
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char* argv[]) {
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/testproject/ui/MainWindow.qml"_qs);
    engine.load(url);
    return app.exec();
}

I created a simple qml file in MainWindow.qml in here

ui/MainWindow.qml

which looks like this:

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    id: mainwindow
    visible: true
    width: 640
    height: 480
    menuBar: MenuBar {
        Menu {
            title: "File"
            MenuItem { text: "open" }
        }
    }
}

in the

src/controller

subdirectory, I create the following header file FileController.h

#include <QObject>
#include <QtQml/qqmlregistration.h>

class FileController : public QObject {
    Q_OBJECT
    QML_ELEMENT // WITHOUT THIS IT COMPILES FINE
    Q_PROPERTY(QString file  READ name WRITE setName NOTIFY filenameChanged)
private:
    QString filename;
    void setName(QString name);
public:
    FileController(QObject *parent);
    QString name();
signals:
    void filenameChanged();
};

and some implementation details in FileController.cpp

#include "FileController.h"

FileController::FileController(QObject *parent) : QObject(parent) {}

void FileController::setName(QString name) {filename = name;}

QString FileController::name() {return filename;}

When compiling, I get the following error:

[13/19] Building CXX object CMakeFiles/test....dir/testproject_qmltyperegistrations.cpp.o
FAILED: CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o 
/usr/bin/c   -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_QMLINTEGRATION_LIB -DQT_QMLMODELS_LIB -DQT_QML_LIB -DQT_QUICK_LIB -DQT_WIDGETS_LIB -I/some/test/directory/build/testproject_autogen/include -I/ome/test/directory/include -I/some/test/directory -isystem /usr/include/qt6/QtQml/6.4.1 -isystem /usr/include/qt6/QtQml/6.4.1/QtQml -isystem /usr/include/qt6/QtCore/6.4.1 -isystem /usr/include/qt6/QtCore/6.4.1/QtCore -isystem /usr/include/qt6/QtCore -isystem /usr/include/qt6 -isystem /usr/lib/qt6/mkspecs/linux-g   -isystem /usr/include/qt6/QtQml -isystem /usr/include/qt6/QtQmlIntegration -isystem /usr/include/qt6/QtNetwork -isystem /usr/include/qt6/QtWidgets -isystem /usr/include/qt6/QtGui -isystem /usr/include/qt6/QtQuick -isystem /usr/include/qt6/QtQmlModels -isystem /usr/include/qt6/QtOpenGL -fPIC -std=c  17 -MD -MT CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o -MF CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o.d -o CMakeFiles/testproject.dir/testproject_qmltyperegistrations.cpp.o -c /some/test/directory/build/testproject_qmltyperegistrations.cpp
/some/test/directory/qt/qml_in_other_dir/build/testproject_qmltyperegistrations.cpp:10:10: fatal error: FileController.h: No such file or directory
   10 | #include <FileController.h>

Apparently when registering qml metatype, Qt is not looking in the subdirectories for the corresponding headers. Or it should copy them, but doesn't. It doesn't have FileController.h in a directory in its include path.

  1. Why isn't the directory structure preserved with CMake and Qt?
  2. I want to have some logic in the qml files (specifically here open a file dialog and pass the result to the C class). In order to have qml and C interact, I need to register the class with the QML_ELEMENT macro. Am I doing something fundamentally wrong? What is the correct way to do this? (I could always fiddle with the include paths or put everything in a base directory, but that seems wrong).

Edit: the issue still occurs e.g. when putting Filecontroller.h into

./include/controller/

and adding

include

to the target_include_directories and adapting the include path in FileController.cpp to something like

#include <controller/FileController.h>

CodePudding user response:

You either need to add include_directories(src/controller) to your CMake file or set the include to #include <src/controller/FileController.h>.

Have a look at this SO question.

EDIT: I found these bugreports QTBUG-87221, QTBUG-101146 . The patch adds a note to the documentation:

All headers that declare QML types need to be accessible without any prefix from the project's include path.

  • Related