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.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With