CXX-Qt: Safe Rust bindings for Qt
kdab.com
kdab.com
Rust doesn’t need more Qt crates. It needs one Qt crate that is complete and works well. (Or, ideally, a native Rust cross-platform GUI crate that works as well as Qt, but that’s an even longer and harder task.)
The post also explains why they started from scratch vs. existing approaches - I'm not qualified to evaluate the claims, but I think they deserve some credit for explicitly talking through their reasons.
Especially if we want to use QtWidgets, the API surface is huge. There are a bunch of bindings with different language, but even the ones that are officially supported like PySide will still be second class citizen and awkward to use.
Automated binding generation will never give you idiomatic API in whatever language. And if you want an idiomatic library that wraps Qt, it's going to take a huge amount of work.
Which is why I think restricting to QML makes sense because that's a much smaller API surface. That was the ambition behind my previous crate that exposes QML to rust: https://github.com/woboq/qmetaobject-rs/
But now I've moved on to another GUI project: Slint https://github.com/slint-ui/slint It is implemented in Rust, but from the start aim to expose its API to several programming languages so bindings can be made idiomatic in almost every programming languages.
The official Qt for Python binding fits in very well with the language and style I think, but when using it in C++, I have to mix wildly different styles and me no likely.
In Python they did an excellent job with all of that.
If you can show me a codebase that you think is modern C++ and uses Qt, it would be much appreaciated. I keep running into walls and havng to go back to coding like it's 98 basically, but hey, love to be shown it's me.
that's because Python has unicode strings. C++ doesn't have a single, canonical unicode string type.
QString and QStringView are fundamentally different data types than std::string and std::string_view which aren't unicode ; the std::string and std::string_view Qt equivalents are QByteArray and QByteArrayView.
Naturally they care most about the people that support their families.
Anyone that dislikes this is free to provide pull requests.
On a small project of mine, macros were also my choice for working around lack of inheritance; I wonder how this scale on large(r) projects, including this one.
Previously, additionally, all base class methods were generated for derived classes (structs). This was removed due to high compile times
This project takes the same approach. It is aimed to put Rust at the core (business logic) of the application and code the UI in C++ or QML. This way you sidestep the enormous work of writing bindings for the Qt libraries.
Here's a talk on the idea. <https://archive.fosdem.org/2018/schedule/event/rust_qt_bindi...>
KDAB hires some of the best Qt coders, so this effort by them might get more traction. Using macros and annotations like Oliviers project is nice. When RQBG started procedural macros were not attractive yet.
This new project is on Microsoft GitHub which means I won't be contributing. I prefer to work on projects that are self-hosted by communities like KDE, GNOME, Debian instead of being locked on a closed platform of a competitor.
Or I guess you could put a Rust wasm app into electron also and have accessibility support that way. Has to be one that uses a real DOM and not just renders to a canvas or WebGL though.
There are sound reasons to prefer the latter. When it is lightweight enough, the mapping is intuitive and obvious, so the original documentation mostly suffices, modulo some release notes. If something doesn't work right, is is very likely your code, not the mapping, at fault. Anything omitted from the mapping is easy to add, compatibly.
The promise of a heavyweight mapping is always that you won't need to understand the thing mapped, that the mapping itself will (1) be fully documented, and (2) work. Neither is ever wholly true. As a result, you need to understand both libraries, and also the (lightweight) mapping between them, and work around all the bugs and infelicities in all three -- mostly without help, because nobody else understands all that any better than you do. When something doesn't work, you have to determine if it is your code, the mapping library, or the thing mapped that is at fault.
Lightweight mappings are always ugly. You end up with your own, custom, heavier mapping, but just to the parts you are actually using, and that you actually understand. It is tempting to fill that out and publish it, which is the actual origin of all the mappings you find published. Resist.
As someone who has never implemented a native GUI library, what makes them so difficult to implement that we see so almost no language-native ones? Is it a matter of it not being monetizable, or something else?
Consider a simple text input: In some languages (e.g. 'syllable based' korean Hangul) you have to compose multiple keystrokes to get to a complex letter. While you type, the last and as well as the second-to-last complex-characters might still 'trade' consonants and vowels among each other.
Now layer in more Dimensions, such as validating that input or line-wrapping, elision and many more.
To my mind, only few libraries got to this level of detail without breaking apart on complexity. It requires high maintainer stamina or massive investments.
Just having proper abstractions over each platform[1]'s:
- windowing
- KB/mouse/tablet/touch input
- raster painting
- 3D APIs (Vk, D3D, GL, Metal...)
- text layout and rendering
- support for accessibility APIs
+ things such as generic data models for tables and trees, etc... is already an immense amount of work, and you haven't even started drawing a single button yet.
* https://github.com/qt/qtbase/tree/dev/src/plugins/platforms
Qt also recreates a ton of features found in C++ and if we're considering a new language, chances are the language itself has features that make Qt's unnecessary.
Also you certainly do not need something like moc to make a GUI library, which comes back to what i originally wrote in that you do not need to replicate Qt to have a GUI library.
There sure is some overlap with what Qt offers that most language offers (Containers, Networking, Database, threading, ...). But purely in the context of making a UI library, there is still a huge amount of things that Qt offers that needs to be replicated.
Yes, you need to implement similar functionality, like abstracting the window system, input handling, text, etc but you do not need to replicate what Qt does to have a GUI toolkit.
Qt is very complex and Qt is (among others) a GUI library but Qt being complex doesn't mean that GUI libraries have to be complex.
However, here is your experience with almost every other toolkit: Download it, compile it, build a couple test screens with it, maybe even build a couple of your production screens with it, then the inevitable disaster: You have some requirement, and you need a calendar that can highlight certain dates, or that gives you mouseevents on each individual date, or allows Jewish as well as Gregorian calendars, or that allows you to add things between the month name and the month days other than what the widget already puts there, or that... etc., for any of dozens of specialized requirements. And then you bounce off the toolkit and tell people in online discussions that you really enjoyed working with it, it was nice that it was so simple, and it has a lot of promise and you hope the developers keep working on it, but it wasn't suitable for your needs and Qt had exactly the widget you needed or at least the widget you needed had the plugin points you needed to do your job.
(In the meantime, the project stalls and dies because nobody else is using it either, but all for different reasons.)
And you hadn't even gotten a tenth of your dialogs started.
Another common one is, as people say, trying to add a rich text dialog and getting hit hard by bugs, counterintuitive behaviors, internationalization issues, etc.
Nobody uses all of what Qt offers. I can't even imagine what it would look like for a program to use literally everything it has. Even a full office suite would be pressed to do that. But everybody uses lots of different things. Put 10 Qt GUI users together and they'll use very different subsets beyond the bare basics like layouts and simple buttons.
Simply to write a binding to a GUI toolkit, ignoring all the other aspects of Qt, is itself a major project. There's been more than one Python project for it, and it is a project, generally more than one person could hope to do. To write a full toolkit that won't give people the experience above is enormous.
And that is why it is important to select your language carefully if you're writing a GUI-heavy project. You can't just pick up your favorite language and casually expect every widget you need to be available. Even if you nominally have "a binding to Qt" in your language, in my experience it's important to still double check that the binding to the widget(s) you need actually work, because anything beyond those bare basic layout, buttons, and bindings to simple widgets everybody uses is still quite possibly broken, or incompletely bound so it can't actually be used (which means nobody can have ever even tried this widget), or straight-up missing, or it's present but there's no way to correctly subclass something then make the bound widget use your subclass (in the foreign language) correctly, or something.
Nor can you just bide your time and hope a toolkit appears. They're enormous projects, even just to get one to the point that most developers don't generally hit a vital bit of missing functionality, let alone to get one full of all the features someone could reasonably want.
1. That you need to replicate Qt to have the same or equivalent features for a GUI toolkit (remember that what i made explicitly that Qt is more than just a GUI toolkit) or you will not have the same features at all
2. That you will "hit" said missing feature
None of these have to do anything with making a GUI library though. #1 is especially questionable since even if you need the non-GUI functionality Qt provides, it might be something the language already has (remember that this is about other languages aside from C and C++) and/or you may even find a separate library that provides such functionality.
And yes, inertia and image does affect A LOT. People do choose projects only because of the perceived safety of those projects from being used by other people. This is why regardless of features, many people stick or flock to languages/libraries/frameworks/etc for their communities and "community" or "ecosystem" is a common concern about something new. This is something you can see often in Hacker News posts too.
* Internationalisation
* Concurrency, parallelism, and perhaps async (probably less of an issue with modern C++, but Qt still has plenty on offer here [0])
* Integration with various platform-specific build tools and IDEs
It's quite possible to make a good GUI, just lots of mundane small issues to deal with, and it's overall a massive undertaking. It requires at least an extremely good knowledge of how different languages deal with text and input it.
The secret, I suspect, is probably "money".
And people tend to use what they see other people using, thus repeating the cycle.
So you see these 15 year old libraries being used because other people are using these 15 year old libraries because they are written in languages that can be (relatively) easily be wrapped (both C and C++ wrapping can be done automatically and there are many tools for that - largely because this is something a ton of people want to do, so again, it feeds back to the cycle of things being popular because they are popular).
But there are lots of new toolkits being made, you can even find a submission for a new one in Hacker News almost every month (though the responses are pretty much the same in all of them :-P).
Accessibility and internationalization are really hard though, right?
I'm finally doing something about the accessibility issue: https://github.com/AccessKit/accesskit Still have a long way to go though.
In contrast, GTK is written in C AFAIK, and anytime a new language springs up the very first thing you generally see is a GTK wrapper. I have always suspected this is because C is far easier to wrap since most languages have a well defined C FFI, but typically lack a C++ one (due to lack of std ABI) thus Qt/wxWidgets bindings typically lag GTK.
Qt on the other hand is very much a C++ OOP style, so if there's an impedance mismatch representing that in your language, as is the case for Rust, C or Go, then it gets much harder to do. The C++ bindings do present difficulty of course, but you can see from e.g. PyQT that if the pattern works in your language it's one that can be overcome.
So yes, there are tools, my point is it is still much easier to wrap a C based API because you can often just use your language FFI, not an external toolset.
(For more specialised, niche gui toolkits the answer is that they're out there, but you've never heard of them because they don't enjoy the network effects that a wider user base gets the big toolkits)
My current work is exactly at the place where those tech universes overlap and integrate.
Unity's probably been investing the most into a more complete 2D toolkit (which is their third or fourth generation of 2D UI toolkit bundled with the engine) lately. Among the FOSS game engine projects Bevy has made strong 2D suitable for UI an explicit goal. But that one true converged contender is still not even on the horizon yet, IMHO.
We know from experience that rewriting our entire system from scratch will take 5 years and cost $150million: I won't even attempt to convince management of that. Our current C++ should be good for 25 years as just C++. if we maintain it well (the major surgery mentioned above) it can last indefinitely. However replacing the current QT GUI is not on the table, it already has our themes. Maybe someday in the future it will be on the table if there is better one and it can work well (look at feel) with out current QT GUI, but for today we don't complain about QT.
We want screenshots. Images of the end product GUI.
EDIT: i.e. after looking at the QML, from quick glance it'll render two lines of text and two buttons in QML default styling. What do you gain from that?
I'd go as far to say that if you need screenshot for this, you may not be their primary audience.
- The qmetaobject crate tries to be idiomatic rust and to be used without any C++
- As far as the user is concerned, there shouldn't be any call involving C++
- It does follow the Rust multi-threading guarantees
- The License is the same as CXX-Qt
- It does support plugins: https://github.com/woboq/qmetaobject-rs/tree/master/examples...
- It uses code generation via macro
[1]: https://www.qt.io/licensing/open-source-lgpl-obligations
First of all, bitcoin does not circonvent tax law. (And linking does not circonvent GPL)
I take your point the Qt company wants (L)GPL licensing to sound scary, so they can sell licenses.
The question about dynamic linking is valid, since Rust's build system, Cargo, produces a static binary by default.
Since most important part of Qt are LGPL, you can use this crate and other Qt binding crates to develop proprietary applications.
(Only if you wish to use one of the few parts that are "only" GPL, then you need to release the final product and all its parts under the GPL, or acquire a Qt license)