Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qml modules #13304

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Qml modules #13304

wants to merge 7 commits into from

Conversation

chubinou
Copy link
Contributor

@chubinou chubinou commented Jun 7, 2024

This MR aims to bring the support of QML modules to meson, the goal is to
provide something similar to CMake qt_add_qml_module function provided by Qt
(see https://doc.qt.io/qt-6/qt-add-qml-module.html)

fixes: #6988 #9683

what's provided

  • qml module generation, qmldir and qrc are automatically generated
  • automatic type registration, C++ classes can be automatically registered in
    the QML module
  • cache generation, the qmlcachegen tool can be invoked on qml files.

what's missing:

the scope of this PR is already large, I voluntary put aside some aspect of the module generation.

  • no qmltc integration
  • no plugin code generation
  • no linter target
  • no qml import scanning
  • no failsafe regarding which tool is available with a given version of Qt, some
    tools (or options) are not available with older version of Qt,
  • no 'past version' support, this would require being able to tag version to
    specific Qml files, which is not very practical in terms of API
  • cmake copies every qml in the build directory, maybe that's necessary for qml
    tooling, I haven't investigated this
CMake argument support comment
VERSION yes
PAST_MAJOR_VERSIONS no shipping different version of the same unit would probably require to be able to tag version per file
STATIC / SHARED N/A we don't generated the final target, the output of the function should be added to a lib/exe target
PLUGIN_TARGET no plugin is not generated
OUTPUT_DIRECTORY yes
RESOURCE_PREFIX yes
CLASS_NAME no plugin is not generated
TYPEINFO yes
IMPORTS yes
OPTIONAL_IMPORTS yes
DEFAULT_IMPORTS yes
DEPENDENCIES yes
IMPORT_PATH yes
SOURCES yes source can be provided for moc, sources should be added to the final target
QML_FILES yes
RESOURCES no resources can be added to the final target independently, there is no point supporting it there
OUTPUT_TARGETS N/A
DESIGNER_SUPPORTED yes
FOLLOW_FOREIGN_VERSIONING no
NAMESPACE yes
NO_PLUGIN no plugin is not generated
NO_PLUGIN_OPTIONAL no plugin is not generated
NO_CREATE_PLUGIN_TARGET no plugin is not generated
NO_GENERATE_PLUGIN_SOURCE no plugin is not generated
NO_GENERATE_QMLTYPES yes
NO_GENERATE_QMLDIR yes
NO_LINT no qmllint not supported
NO_CACHEGEN yes
NO_RESOURCE_TARGET_PATH
NO_IMPORT_SCAN no not supported
ENABLE_TYPE_COMPILER no qmltc is not supported
TYPE_COMPILER_NAMESPACE no qmltc is not supported
QMLTC_EXPORT_DIRECTIVE no qmltc is not supported
QMLTC_EXPORT_FILE_NAME no qmltc is not supported

@chubinou chubinou requested a review from jpakkane as a code owner June 7, 2024 15:43
@chubinou chubinou changed the title Qml modules Draft: Qml modules Jun 7, 2024
@chubinou chubinou force-pushed the qml_modules branch 2 times, most recently from 5a309af to 2c9b9eb Compare June 21, 2024 12:01
@chubinou
Copy link
Contributor Author

arch tests are failing because the CI doesn't provide QtQml for qt 6 which is a new requirement for the test

@chubinou chubinou changed the title Draft: Qml modules Qml modules Jun 21, 2024
Copy link
Member

@dcbaker dcbaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! I've taken a cursory glance, and there's a few smallish things I've noticed. I'd like to have another look later when I have more time to get into more of the details

Comment on lines 180 to 181
for check in checklist:
if check not in choices:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can simplify (and make a better error message) this to something like:

invalid = set(checklist).difference(choices)
if invalid:
    return f"invalid selections {', '.join(sorted(invalid))}, valid elements are {', '.join(sorted(choices))}."

preserve_paths: bool

class HasToolKwArgs(kwargs.ExtractRequired):

method: str
tools: T.List[str]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can make this a little more powerful (and maybe remove an assert later on) with:
tools: T.List[Literal['moc, 'lrelease', <insert reset of valid tools>]]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 746 to 747
else:
assert False, "unreachable"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to trust the type annotations for the final release, though this might be useful for bringup

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this function quite a bit, I took inspiration from the one in gnome.py

basename: str = os.path.basename(sourcepath)
classname: str = basename.rsplit('.', maxsplit=1)[0]

if not any(basename.endswith(ext) for ext in ['.qml', '.js', '.mjs']):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not any(basename.endswith(ext) for ext in ['.qml', '.js', '.mjs']):
if not basename.endswith(('.qml', '.js', '.mjs')):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if not any(basename.endswith(ext) for ext in ['.qml', '.js', '.mjs']):
raise MesonException(f'unexpected file type declared in qml sources {s}')

if len(classname) == 0 or '.' in classname or classname[0].islower():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if len(classname) == 0 or '.' in classname or classname[0].islower():
if not classname or '.' in classname or classname[0].islower():

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


cmd.extend(kwargs['extra_args'])

if namespace != '':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if namespace != '':
if namespace:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

description=f'Qml type registration for {target_name}',
)

@FeatureNew('qt.qml_module', '1.0')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@FeatureNew('qt.qml_module', '1.0')
@FeatureNew('qt.qml_module', '1.6')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 996 to 997
qrc_resouces: T.List[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]] = []
all_qml_files: T.Sequence[T.Union[FileOrString, build.CustomTarget]] = list(kwargs['qml_sources']) + list(kwargs['qml_singletons']) + list(kwargs['qml_internals'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it would be beneficial to use the Interpreter.source_strings_to_files method here to remove the strings and just have list[File | CustomTarget | CustomTargetIndex | GeneratedList] here, and then not have to do string handling internally.

@chubinou
Copy link
Contributor Author

some self comments on the PR:

I tried to follow Qt module directory structure

for the file MyClass.qml in the module Foo.Bar, this should looks like
Foo
|- Bar
|   |- qmldir
|   |- MyClass.qml
|   |- module.qmltypes

at the moment this is still a bit clumpsy:

  • for the tools to actually be able to use this, we should copy the .qml files to the Bar directory, but Meson doesn't really let me copy files to a subdirectory (I can probably cheat my way out of it, but choosed not to for the moment)
  • this is not really needed for the compilation parts, we could generate everything on a flat level, and do the file mapping in the qrc (it defines the internal paths of each resources). I thought that maybe I can make a special target to install the qml module tree for tooling purpose, maybe some custom target with an install_tag like in the gnome module, I haven't looked in depth at this.

@AdelKS
Copy link
Contributor

AdelKS commented Jul 12, 2024

Thank you for undertaking this work !

I wanted to give a try to registering QML modules but I am afraid I've hit against a regression introduced in this MR before I could get to it. Here's the reproducer:

git clone --depth=1 https://github.com/AdelKS/ZeGrapher.git
cd ZeGrapher
meson setup build
cd build
meson compile

which outputs this error

[59/203] Compiling C++ object src/libZeGrapherLib.a.p/meson-generated_moc_polynomialregression.cpp.o
FAILED: src/libZeGrapherLib.a.p/meson-generated_moc_polynomialregression.cpp.o 
c++ -Isrc/libZeGrapherLib.a.p -Isrc -I../src -Isubprojects/zecalculator/include -I../subprojects/zecalculator/include -I/usr/include/qt6/QtCore -I/usr/include/qt6 -I/usr/lib/qt6/mkspecs/linux-g++ -I/usr/include/qt6/QtGui -I/usr/include/qt6/QtWidgets -I/usr/include/qt6/QtNetwork -I/usr/include/qt6/QtSvg -I/usr/include/qt6/QtQuick -I/usr/include/qt6/QtQmlModels -I/usr/include/qt6/QtQmlIntegration -I/usr/include/qt6/QtOpenGL -I/usr/include/qt6/QtQml -I/usr/include/qt6/QtQuickWidgets -I/usr/include -fdiagnostics-color=always -DNDEBUG -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -std=c++20 -O3 '-D QT_NO_DEBUG_OUTPUT' '-D QT_NO_INFO_OUTPUT' '-D QT_NO_WARNING_OUTPUT' '-D QT_NO_DEBUG' -pipe -fPIC -DBOOST_ALL_NO_LIB -DQT_QUICKWIDGETS_LIB -DQT_QUICK_LIB -DQT_QMLMODELS_LIB -DQT_QMLINTEGRATION_LIB -DQT_OPENGL_LIB -DQT_QML_LIB -DQT_SVG_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -MD -MQ src/libZeGrapherLib.a.p/meson-generated_moc_polynomialregression.cpp.o -MF src/libZeGrapherLib.a.p/meson-generated_moc_polynomialregression.cpp.o.d -o src/libZeGrapherLib.a.p/meson-generated_moc_polynomialregression.cpp.o -c src/libZeGrapherLib.a.p/moc_polynomialregression.cpp
cc1plus: fatal error: src/libZeGrapherLib.a.p/moc_polynomialregression.cpp: No such file or directory

it looks like there's a naming convention that isn't respected between meson-generated_moc_polynomialregression.cpp.o and moc_polynomialregression.cpp ? The relevant meson file is this one

Or maybe it's related to the fact that I currently pass all headers that need a moc pass on them to meson's qt.compile_moc() method. I wanted to ask how does that interact with the new qt.qml_module() method with its moc_headers kwarg, because it looked like ninja was already complaining that a target is generated twice if I passed a header, that I already moc'ed with qt.compile_moc() , to qt.qml_module()

@chubinou
Copy link
Contributor Author

Hi, thanks for your interest

I wanted to give a try to registering QML modules but I am afraid I've hit against a regression introduced in this MR before I could get to it.

your repository doesn't use the feature from this MR, so I don't really see how this is a regression.

I tried to compile you project but I ended up with a lot of compilation issues (template issues in your math classes, compiled on ubuntu 22.04 with GCC 11.4), So I can't really help you there

Or maybe it's related to the fact that I currently pass all headers that need a moc pass on them to meson's qt.compile_moc() method. I wanted to ask how does that interact with the new qt.qml_module() method with its moc_headers kwarg, because it looked like ninja was already complaining that a target is generated twice if I passed a header, that I already moc'ed with qt.compile_moc() , to qt.qml_module()

qt.qml_module will moc the file itself as it needs to pass specific options to moc to extract type information, so qt.compile_moc becomes redundant

@AdelKS
Copy link
Contributor

AdelKS commented Jul 18, 2024

Hey, thanks for trying to look into it

template issues in your math classes, compiled on ubuntu 22.04 with GCC 11.4

Yeah I stopped trying to make "old" GCC or clang versions happy x)

your repository doesn't use the feature from this MR, so I don't really see how this is a regression.

Sorry, I haven't been clear enough: the master branch of my repo builds fine with latest release of meson 1.5.0, but not with this branch, this is before I make changes to meson.build to use qt.qml_module(). I need to try latest meson git commit to check, maybe my build failure has nothing to do with this MR.

qt.qml_module will moc the file itself as it needs to pass specific options to moc to extract type information, so qt.compile_moc becomes redundant

I understand. I have a noob suggestion on this aspect: I have this (maybe wrong ?) approach where I use a bash script to make a meson files() array of all the headers that contain the Q_OBJECT or Q_GADGET macros and qt.compile_moc() them. Is it doable or a good idea to change qt.compile_moc() in the same way so it always produces the type information qt.qml_module() needs, and make qt.qml_module() accept the output of qt.compile_moc() ? The benefit I see to this is to streamline how to deal with Qt's shenanigans: moc all the "special" headers, then add qml modules on top if/when needed. This at least also assumes that header files that don't have the QML_ELEMENT macro wouldn't make things harder for qt.qml_module()

@AdelKS
Copy link
Contributor

AdelKS commented Jul 18, 2024

I need to try latest meson git commit to check, maybe my build failure has nothing to do with this MR.

Okay I just tried on meson commit dfd22db4b, which is the latest meson commit before your MRs commits, and my repo could build, so this MR did at least introduce breaking changes, to qt.compile_moc() I assume ?

Would you be willing to install gcc-13 on your Ubuntu to confirm ?

add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt install -y gcc-13
git clone --depth=1 https://github.com/AdelKS/ZeGrapher.git
cd ZeGrapher
CXX=g++13 meson setup build
cd build
meson compile

mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
chubinou added a commit to chubinou/meson that referenced this pull request Aug 7, 2024
`outfiles` is the output list of the individual commands

Bug: mesonbuild/pull/13304#issuecomment-2226398671
chubinou added a commit to chubinou/meson that referenced this pull request Aug 7, 2024
`outfilelist` is the output list of the target, while `outfiles` is the output
list of the individual commands

Bug: mesonbuild/pull/13304#issuecomment-2226398671
@chubinou
Copy link
Contributor Author

chubinou commented Aug 7, 2024

@AdelKS the issue was due to some bad replacements in ninja backend, i opened #13526 to fix the issue

chubinou added a commit to chubinou/meson that referenced this pull request Aug 8, 2024
`outfilelist` is the output list of the target, while `outfiles` is the output
list of the individual commands

Bug: mesonbuild/pull/13304#issuecomment-2226398671
@chubinou
Copy link
Contributor Author

chubinou commented Aug 9, 2024

I updated the PR, it no longer requires the sources to be generated with a precise directory structure which should match meson philosophy.

I also added a 'devel' install target to allow installing the module definition (for qmllint or and qml tools)

@chubinou chubinou force-pushed the qml_modules branch 2 times, most recently from 3e31346 to e8e8465 Compare August 9, 2024 14:57
jpakkane pushed a commit that referenced this pull request Oct 12, 2024
`outfilelist` is the output list of the target, while `outfiles` is the output
list of the individual commands

Bug: /pull/13304#issuecomment-2226398671
@jpakkane jpakkane added this to the 1.7 milestone Oct 12, 2024
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
module_prefix_full: str = os.path.join(*(kwargs['resources_prefix'].split('/') + module_prefix_list))

qrc_resouces: T.List[T.Union[FileOrString, build.GeneratedTypes]] = []
all_qml: T.Sequence[T.Union[FileOrString, build.GeneratedTypes]] = list(kwargs['qml_sources']) + list(kwargs['qml_singletons']) + list(kwargs['qml_internals'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these already lists? Why cast them again to list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mypy fails otherwise

Unsupported left operand type for + ("Sequence[File | str | CustomTarget | CustomTargetIndex | GeneratedList]")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the original definition of kwargs should annotate these as T.List instead of the generic T.Sequence, if we need them to be a List type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it for a T.List, this seems to be enough

mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
@jpakkane
Copy link
Member

The next release is creeping closer so it would be nice to get this in. FWICT there are only some minor fixes + a rebase and this should be good to merge.

in `func_install_data`, `rename` parameter is `ContainerTypeInfo(list, str)`
in `module/python.py`, rename is `None`

`rename` is stored in `build.Data` object under the type `T.List[str]`
@chubinou
Copy link
Contributor Author

Sorry for the late update, I was first waiting for #13526 to get merged then I somehow missed the review notification late October

I made a few updates:

  • I removed the need to pass a target name, I instead derive a name from the module name. The derived name matches what is done by qmltyperegistar.
  • Module version is made optional too, it will default to 254.254 like cmake qt_add_qml_module
  • module can be installed with the devel tag, this allows qt tools (linter, designer) to use the module definition. Though, this makes the test suite fail if Qt6 is not found as the test.json expects these files to be installed, I'm not sure how to fix this.
  • added qt6-declarative dependency for arch CI
  • I added documentation for the function
  • code is rebased on master

mesonbuild/modules/_qt.py Outdated Show resolved Hide resolved
@eli-schwartz
Copy link
Member

eli-schwartz commented Dec 12, 2024

  • module can be installed with the devel tag, this allows qt tools (linter, designer) to use the module definition. Though, this makes the test suite fail if Qt6 is not found as the test.json expects these files to be installed, I'm not sure how to fix this.

This might only be possible by adding a new frameworks test specifically to handle qml, which can raise a SKIP if qt6 isn't installed. As opposed to the current test which simply tests all currently-installed Qt versions.

The alternative would be to somehow update the test harness to allow specifying expect_skip_on_jobname for installed files, which sounds neat albeit fiddly.

  • added qt6-declarative dependency for arch CI

Right, so that should mean the CI failure for that specific runner can be ignored. (The CI image builder for Arch does succeed, which is all we need.)

From a very superficial look it seems like all the other CI failures are image builders (always ignore these) and CI runners that don't test Qt6 and fall under the previous category.

@AdelKS
Copy link
Contributor

AdelKS commented Dec 12, 2024

Hey, thanks for #13526 and for this MR.

I tried to move one of the modules of my project to qml_module, using this small change, and I've hit against some issues

  • qmlcachegen complains about wrong input
  • The generated .cpp file that calls qmlRegisterTypesAndRevisions seems to not include the header I've given
Error output
[1/45] Qml cache loader for zegrapher_highlighter
Usage: /usr/lib64/qt6/libexec/qmlcachegen [options] [qml file]

Options:
  -h, --help                                   Displays help on commandline
                                               options.
  --help-all                                   Displays help, including generic
                                               Qt options.
  -v, --version                                Displays version information.
  --bare                                       Do not include default import
                                               directories. This may be used to
                                               run qmlcachegen on a project
                                               using a different Qt version.
  --filter-resource-file                       Filter out QML/JS files from a
                                               resource file that can be cached
                                               ahead of time instead
  --resource-file-mapping <old-name=new-name>  Path from original resource file
                                               to new one
  --resource <resource-file-name>              Qt resource file that might
                                               later contain one of the compiled
                                               files
  --resource-path <resource-path>              Qt resource file path
                                               corresponding to the file being
                                               compiled
  --resource-name <compiled-file-list>         Required to generate
                                               qmlcache_loader without qrc
                                               files. This is the name of the Qt
                                               resource the input files belong
                                               to.
  -i <qmldir file>                             Import extra qmldir
  -I <import directory>                        Look for QML modules in
                                               specified directory
  --only-bytecode                              Generate only byte code for
                                               bindings and functions, no C++
                                               code
  --verbose                                    Output compile warnings
  --warnings-are-errors                        Treat warnings as errors
  --validate-basic-blocks                      Performs checks on the basic
                                               blocks of a function compiled
                                               ahead of time to validate its
                                               structure and coherence
  --dump-aot-stats                             Dumps statistics about
                                               ahead-of-time compilation of
                                               bindings and functions
  --module-id <id>                             Identifies the module of the qml
                                               file being compiled for aot stats
  -o <file name>                               Output file name

Arguments:
  [qml file]                                   QML source file to generate
                                               cache for.
[2/45] Compiling C++ object src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmlcache_loader.cpp.o
FAILED: src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmlcache_loader.cpp.o 
c++ -Isrc/libZeGrapherLib.a.p -Isrc -I../src -Isubprojects/zecalculator/include -I../subprojects/zecalculator/include -I/usr/include/qt6/QtCore -I/usr/include/qt6 -I/usr/lib64/qt6/mkspecs/linux-g++ -I/usr/include/qt6/QtGui -I/usr/include/qt6/QtWidgets -I/usr/include/qt6/QtNetwork -I/usr/include/qt6/QtSvg -I/usr/include/qt6/QtQuick -I/usr/include/qt6/QtQmlMeta -I/usr/include/qt6/QtQmlWorkerScript -I/usr/include/qt6/QtQmlModels -I/usr/include/qt6/QtOpenGL -I/usr/include/qt6/QtQml -I/usr/include/qt6/QtQmlIntegration -I/usr/include/qt6/QtQuickWidgets -I/usr/include -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -Werror -std=c++20 -O0 -g '-D QT_QML_DEBUG' -pipe -fPIC -DBOOST_ALL_NO_LIB -DQT_QUICKWIDGETS_LIB -DQT_QUICK_LIB -DQT_QMLMETA_LIB -DQT_QMLWORKERSCRIPT_LIB -DQT_QMLMODELS_LIB -DQT_OPENGL_LIB -DQT_QML_LIB -DQT_QMLINTEGRATION_LIB -DQT_SVG_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -MD -MQ src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmlcache_loader.cpp.o -MF src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmlcache_loader.cpp.o.d -o src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmlcache_loader.cpp.o -c src/zegrapher_highlighter_qmlcache_loader.cpp
cc1plus: fatal error: src/zegrapher_highlighter_qmlcache_loader.cpp: No such file or directory
compilation terminated.
[4/45] Compiling C++ object src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmltyperegistrations.cpp.o
FAILED: src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmltyperegistrations.cpp.o 
c++ -Isrc/libZeGrapherLib.a.p -Isrc -I../src -Isubprojects/zecalculator/include -I../subprojects/zecalculator/include -I/usr/include/qt6/QtCore -I/usr/include/qt6 -I/usr/lib64/qt6/mkspecs/linux-g++ -I/usr/include/qt6/QtGui -I/usr/include/qt6/QtWidgets -I/usr/include/qt6/QtNetwork -I/usr/include/qt6/QtSvg -I/usr/include/qt6/QtQuick -I/usr/include/qt6/QtQmlMeta -I/usr/include/qt6/QtQmlWorkerScript -I/usr/include/qt6/QtQmlModels -I/usr/include/qt6/QtOpenGL -I/usr/include/qt6/QtQml -I/usr/include/qt6/QtQmlIntegration -I/usr/include/qt6/QtQuickWidgets -I/usr/include -fdiagnostics-color=always -D_GLIBCXX_ASSERTIONS=1 -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -Werror -std=c++20 -O0 -g '-D QT_QML_DEBUG' -pipe -fPIC -DBOOST_ALL_NO_LIB -DQT_QUICKWIDGETS_LIB -DQT_QUICK_LIB -DQT_QMLMETA_LIB -DQT_QMLWORKERSCRIPT_LIB -DQT_QMLMODELS_LIB -DQT_OPENGL_LIB -DQT_QML_LIB -DQT_QMLINTEGRATION_LIB -DQT_SVG_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -MD -MQ src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmltyperegistrations.cpp.o -MF src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmltyperegistrations.cpp.o.d -o src/libZeGrapherLib.a.p/meson-generated_.._zegrapher_highlighter_qmltyperegistrations.cpp.o -c src/zegrapher_highlighter_qmltyperegistrations.cpp
src/zegrapher_highlighter_qmltyperegistrations.cpp: In function ‘void qml_register_types_zegrapher_highlighter()’:
src/zegrapher_highlighter_qmltyperegistrations.cpp:23:34: error: ‘Highlighter’ was not declared in this scope
   23 |     qmlRegisterTypesAndRevisions<Highlighter>("zegrapher.highlighter", 1);
      |                                  ^~~~~~~~~~~
src/zegrapher_highlighter_qmltyperegistrations.cpp:23:46: error: no matching function for call to ‘qmlRegisterTypesAndRevisions<<expression error> >(const char [22], int)’
   23 |     qmlRegisterTypesAndRevisions<Highlighter>("zegrapher.highlighter", 1);
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from src/zegrapher_highlighter_qmltyperegistrations.cpp:7:
/usr/include/qt6/QtQml/qqml.h:919:6: note: candidate: ‘template<class ... Args> void qmlRegisterTypesAndRevisions(const char*, int, QList<int>*)’
  919 | void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/qt6/QtQml/qqml.h:919:6: note:   template argument deduction/substitution failed:
src/zegrapher_highlighter_qmltyperegistrations.cpp:23:46: error: template argument 1 is invalid
   23 |     qmlRegisterTypesAndRevisions<Highlighter>("zegrapher.highlighter", 1);
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

The commit just before, that doesn't use qml_module, compiles and runs fine.

I'm probably doing something wrong, but I couldn't find something that could help me out in the documentation and test cases of this MR.

How to reproduce

git clone --depth=1 https://github.com/AdelKS/ZeGrapher.git --branch meson-qml
cd ZeGrapher
CXX=g++13 meson setup build
cd build
meson compile

needs >=gcc-13, on ubuntu 22.04 can be obtained with

add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt install -y gcc-13

@chubinou
Copy link
Contributor Author

I removed the 'moc_source' argument as moc will complain about Qml definition in non-header files, and will likely fail to build (qmltyperegistrar will include the .cpp)

@eli-schwartz

This might only be possible by adding a new frameworks test specifically to handle qml, which can raise a SKIP if qt6 isn't installed. As opposed to the current test which simply tests all currently-installed Qt versions.

I went for this

@AdelKS

qmlcachegen complains about wrong input

I handle the case for qml modules without qml files and added a unit test about this

The generated .cpp file that calls qmlRegisterTypesAndRevisions seems to not include the header

Unfortunately this is a qt issue (see QTBUG-93443 and QTBUG-87221). From what I understand the generated JSON doesn't store the relative header path as they want their installed files to be relocatable, as a result the generated code for qmltyperegistrar doesn't know the path of the headers. This is mentioned in Qt documentation here

the solution for this is to explicitly add the header path to the include directories of the target. I added a note in the documentation about this

How to reproduce

your branch seems to be missing zc::eval::Cache and zc::eval::ObjectCache definition

@chubinou
Copy link
Contributor Author

chubinou commented Dec 13, 2024

This might only be possible by adding a new frameworks test specifically to handle qml, which can raise a SKIP if qt6 isn't installed.

so now, the CI fails because the tests are skipped. Should I :

  • blacklist pretty much all runners (as they don't have qt6)
  • add qt6 to the runner images (at least the Linux ones)

are the images updated before the CI runs?

@eli-schwartz
Copy link
Member

so now, the CI fails because the tests are skipped. Should I :

  • blacklist pretty much all runners (as they don't have qt6)
  • add qt6 to the runner images (at least the Linux ones)

Probably the latter is better because it provides more coverage, though in at least the case of Bionic I suspect the only option is to blacklist it. ;)

are the images updated before the CI runs?

No, but the image builder runs the testsuite too. Typically we manually ignore failures for Linux jobs when the corresponding image builder succeeds in the same commit.

@AdelKS
Copy link
Contributor

AdelKS commented Dec 13, 2024

Thanks for your input @chubinou

your branch seems to be missing zc::eval::Cache and zc::eval::ObjectCache definition

You probably re-used the clone you had before, in which case you need to do a little meson subprojects update --reset to get the ZeCalculator subproject to the proper version.

the solution for this is to explicitly add the header path to the include directories of the target

I tried here to put a meson.build file that

  1. Is at the same level as the QML C++ header file I want to give to qml_module()
  2. Give that folder to include_directories kwarg
    • It does add it to the compile commands as I see an -Isrc/Utils in the compile commands
      But it still doesn't work somehow.

But, if I move the QML C++ header file to the main include folder (in my case src), as I did here, then it works, not sure what the difference is... 🤔

This aims to bring the support of QML modules to meson, the goal is to
provide something similar to CMake `qt_add_qml_module` function provided by Qt
(see https://doc.qt.io/qt-6/qt-add-qml-module.html )

Fixes: mesonbuild#6988, mesonbuild#9683
These packages are required to test `qml_module` from qt
@chubinou
Copy link
Contributor Author

@AdelKS

you need to add the include dir where the file from highlighter_qmlmod are compiled

executable('ZeGrapher', 'main.cpp', compiled_ui, compiled_ressources, highlighter_qmlmod,
  link_with: zg_static_lib,
  include_directories: [inc, include_directories('Utils')],
  dependencies: [qt6_dep, boost_dep, zecalculator_dep],
install: true)

also, if you build a static library as in you first branch meson-qml beware that may need to use Q_INIT_RESOURCE to import the static entry points you or you have some linker surprises. I added a test case to illustrate the process

@klokik
Copy link
Contributor

klokik commented Dec 16, 2024

Moved one of our simpler projects to this implementation of modules - so far so good. There is probably a bug in qmlcachegen on handling paths with symlinks, but this is an edge case of my setup. Thanks for the great work!

A list of sources to be transpiled into .moc files for manual inclusion.
- `headers` (File | string | custom_target | custom_target index | generator_output)[]:
A list of headers to be transpiled into .cpp files
- `extra_args` string[]: Extra arguments to pass directly to `qt-moc`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have moc_extra_args and don't define this parameter in QmlModuleKwArgs

@AdelKS
Copy link
Contributor

AdelKS commented Dec 19, 2024

Thank you very much for your input @chubinou.

I could transfer my whole project to using qml_module() (commit here), I got these warnings but they had no consequence in the resulting exe (as far as I could tell)

[42/73] Qml type registration for ZeGrapher
Warning: highlighter.h:8: QSyntaxHighlighter is used as base type but cannot be found.
Warning: information.h:38: QObject is used as base type but cannot be found.
Warning: interactivegraph.h:50: Graph is used as base type but cannot be found.
Warning: mathobject.h:33: QObject is used as base type but cannot be found.
Warning: plotstyle.h:30: QObject is used as base type but cannot be found.
Warning: plotstyle.h:30: uint is used as enum type but cannot be found.
Warning: state.h:34: QObject is used as base type but cannot be found.
Warning: zcbase.h:32: QObject is used as base type but cannot be found.

It may be worth adding these two links to the documentation:

Cherry-on-top: any plans with adding support for qmltc ? 🤩

@chubinou
Copy link
Contributor Author

I updated documentation to reflect @klokik & @AdelKS remarks

@AdelKS

Warning: highlighter.h:8: QSyntaxHighlighter is used as base type but cannot be found.

maybe some missing includes/dep ? moc tend to to be lenient about this. Q_MOC_INCLUDE may help about this

also don't you need public inheritance rather than default (private)

any plans with adding support for qmltc ? 🤩

not in short term, I'm more interested in providing shader compilation (qsb) support

@AdelKS
Copy link
Contributor

AdelKS commented Dec 20, 2024

maybe some missing includes/dep ? moc tend to to be lenient about this. Q_MOC_INCLUDE may help about this

Thanks! Tried this

highlighter.h

#pragma once

#include <QSyntaxHighlighter>
#include <QQuickTextDocument>
#include "Utils/state.h"

/// @brief backend that highlights parsing errors in math expressions in LineEdit
class Highlighter: public QSyntaxHighlighter
{
  Q_OBJECT
  QML_ELEMENT
  // ...
  Q_MOC_INCLUDE("QSyntaxHighlighter")

same warning message, I don't know if this is a meson thing or a Qt thing, probably the later, this is the dep object I give to qml_module()

qt6_dep = dependency('qt6', modules: ['Core', 'Gui', 'Widgets', 'Network', 'Svg', 'Quick', 'Qml', 'QuickWidgets'])

not in short term, I'm more interested in providing shader compilation (qsb) support

That will also be very cool ! I may try to get the qmltc support added, I'll open a Draft PR and tag you if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

qt5 Ahead-of-Time compilation for qml
7 participants