Skip to main content

Installing Qt metatypes files

If you have been on invent.kde.org lately you might have seen some merge requests about “Install Qt metatypes” and wondered what that’s all about.

When defining QML types in C++ the buildsytem tries to capture as much information about the type as possible, so that tools like qmllint, qmlls, and the QML compiler know about what API the type provides. If that information cannot be gathered the code will still work fine at runtime, but the development experience will be degraded.

Normally, when all the types involved are from the local project (or Qt), and you are using the qt_add_qml_module CMake API as well as declarative type registration, things will work mostly out of the box. However, in some cases that’s not enough, and we need some extra steps.

Imagine we have a library MyLib, that exposes a class MyModel. That model isn’t registered to QML at all. Now we have a program MyProgram, that creates a subclass of MyModel, and registers that to QML:

#include <MyLib/MyModel>

class MySubModel : public MyModel {
    Q_OBJECT
    QML_ELEMENT
    ...
}

This will work fine at runtime, but produces a suspicious build warning:

Warning: mysubmodel.h:3: MyModel is used as base type but cannot be found.

Opening any QML file using MySubModel in an qmlls-capable editor will show that type information for MySubModel is limited or nonexistant. So how do we fix this? Enter: metatypes files.

During the build process moc processes your classes and extracts information about properties, signals, invokables, etc. That information is then processed by the QML tooling. For Qt’s own types that’s done out of the box, and for custom QML module’s types too, but if your custom module is using types from another library some extra steps are needed.

First, the library needs to extract its metatypes into a consumable file. This is done using the qt_extract_metatypes CMake API:

add_library(MyLib)

qt_extract_metatypes(MyLib)

This will produce a JSON file that contains information about the types in MyLib. If the QML module needing this is in the same buildsystem that’s enough to make things work. However, quite often it will be used by something in another project, so we need to install the file alongside the library:

add_library(MyLib)

# the path of the generated file will be stored in ${METATYPES_FILE}
qt_extract_metatypes(MyLib OUTPUT_FILES METATYPES_FILE)

install(TARGETS MyLib)
install(FILES ${METATYPES_FILE} DESTINATION ${KDE_INSTALL_QTMETATYPESDIR})

This will install the file, but that’s not enough for the consuming project to pick it up, we need to associate the metatypes file with the library. To make that happen we add the (public) sources for that library:

add_library(MyLib)

# the path of the generated file will be stored in ${METATYPES_FILE}
qt_extract_metatypes(MyLib OUTPUT_FILES METATYPES_FILE)

# extract the filename from the path
get_filename_component(METATYPES_FILE_NAME ${METATYPES_FILE} NAME)
# add metatypes file to the interface sources set
target_sources(MyLib INTERFACE $<INSTALL_INTERFACE:${KDE_INSTALL_QTMETATYPESDIR}/${METATYPES_FILE_NAME}>)

install(TARGETS MyLib)
install(FILES ${METATYPES_FILE} DESTINATION ${KDE_INSTALL_QTMETATYPESDIR})

This scary looking line of CMake basically boils down to “Everything that links against MyLib will get the installed metatypes file added to its sources”. This makes the QML machinery in the application pick it up.

With that, no changes to the application are necessary. The build warning disappears, and type information in the editor starts working.

Since it’s hard to know in advance whether a library’s types are going to be used that way it’s probably a good idea to do this for any library, especially since there’s effectively no cost to this, other than some CMake code. It would be great if Qt would take care of most of that code though, see https://qt-project.atlassian.net/browse/QTBUG-123052 and related patches.

A word on the install location: When installing Qt-related files there’s some subtleties involved when determining where to install things. Fortunatley ECM takes care of that for us, so it gained a new variable KDE_INSTALL_QTMETATYPESDIR for this.

This has been applied to a few KDE libraires already, but there’s likely more where it would be benefitial, to allow for better QML tooling and ultimately a better developer experience.

© Nicolas Fella, 2026 MastodonNicolas Fella
Powered by Hugo, theme Anubis.