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

Rust bindings for QQmlEngine & QQmlApplicationEngine #113

Closed
Be-ing opened this issue Mar 14, 2022 · 9 comments · Fixed by #412
Closed

Rust bindings for QQmlEngine & QQmlApplicationEngine #113

Be-ing opened this issue Mar 14, 2022 · 9 comments · Fixed by #412
Assignees
Labels
⬆️ feature New feature or request
Milestone

Comments

@Be-ing
Copy link
Contributor

Be-ing commented Mar 14, 2022

This could allow for writing QML applications in Rust without downstream application developers needing to write C++

@ahayzen-kdab
Copy link
Collaborator

So this goes against the current goals and focus of this tool, of not exposing intimate details about Qt to Rust and limiting scope to only plugins and modules which allows a safe and more idiomatic API. If you want to wrap the whole of the C++ Qt API there are other solutions which already exist for this purpose. Also if you want a Rust-only app then there are other toolkits which will be better suited (eg Slint UI), as even if you wrap the whole of the Qt API in Rust, it still requires the developer to have Qt knowledge.

Maybe eventually I could see something like the following code, but for the short/medium term this is won't fix. And i'm also not sure how useful this would be, as you still would likely want to perform connections / register other types etc. You still need a C++ compiler setup and the CMake side still needs configuring etc.

#[cxx_qt(app(resources = ["qml.qrc"], main_qml_file = "qrc:/qml/main.qml"))]
fn main() {
    println!("Hello world");
}

or

fn main() {
    cxx_qt::App::new("app_id")
        .resources(vec!("qml.qrc"))
        .main_qml_file("qrc:/qml/main.qml")
        .build()
        .unwrap()
}

(inspired by tokio)

@ahayzen-kdab ahayzen-kdab added ⬆️ feature New feature or request ❌ wontfix This will not be worked on labels Mar 15, 2022
@Be-ing
Copy link
Contributor Author

Be-ing commented Mar 15, 2022

So this goes against the current goals and focus of this tool, of not exposing intimate details about Qt to Rust and limiting scope to only plugins and modules which allows a safe and more idiomatic API. If you want to wrap the whole of the C++ Qt API there are other solutions which already exist for this purpose.

This won't require wrapping the whole C++ API of Qt, just enough to launch a QML application.

Also if you want a Rust-only app then there are other toolkits which will be better suited (eg Slint UI), as even if you wrap the whole of the Qt API in Rust, it still requires the developer to have Qt knowledge.

Slint is great! I'm using it for my own application. And there are other Rust GUI libraries as well. But none of them are nearly as mature as Qt and likely won't be for years to come. I agree that I probably wouldn't recommend using cxx-qt for a primarily Rust application to a developer who doesn't have prior Qt experience. But there are lots of developers with Qt experience. :)

i'm also not sure how useful this would be, as you still would likely want to perform connections / register other types etc.

Yes, there likely would be a bit more than this desired, but far from the full API of Qt.

You still need a C++ compiler setup and the CMake side still needs configuring etc.

A C++ compiler is required of course, but I think it could be feasible to do the build with Cargo without requiring CMake.

I think it would be valuable to have a single Qt binding crate that could be used both within C++ applications and within Rust applications. This could enable long term, step-by-step migration of existing Qt applications to primarily Rust. Also, I think it could attract substantially more contributors, especially if it is usable together with KDE Frameworks. I am curious about @Ayush1325's thoughts on that last point.

@Ayush1325
Copy link

I think it would be valuable to have a single Qt binding crate that could be used both within C++ applications and within Rust applications. This could enable long term, step-by-step migration of existing Qt applications to primarily Rust. Also, I think it could attract substantially more contributors, especially if it is usable together with KDE Frameworks. I am curious about @Ayush1325's thoughts on that last point.

Yes, I agree with this point. The problem with using Rust just for modules/plugins is that it will only be attractive to a very small set of people. For most small to medium-sized projects, it simply isn't worth it to use 2 languages/build systems, and thus attracting new developers will be difficult.

However, I also agree that allowing the writing of Qt applications in Rust isn't nearly as simple as just having wrappers for QQmlEngine and QQmlApplicationEngine. I am a collaborator in qmetaobject project and I can say that adding support for completely writing applications in Rust will take a lot more work, especially since it would be best if things like registering QObjects, etc is done at compile time.

Since qmetaobject already exists, I am more interested in the cxx-qt-lib crate and see if that can replace qttypes crate, then qmetaobject and cxx-qt could theoretically be used together. Then the bindings like kconfig-rs can rely on cxx-qt-lib and be used with both projects.

In short, for now, I think it is fine if cxx-qt focuses on modules/plugins and qmetaobject focuses on writing the whole application in Rust.

@Be-ing
Copy link
Contributor Author

Be-ing commented Mar 15, 2022

Since qmetaobject already exists, I am more interested in the cxx-qt-lib crate and see if that can replace qttypes crate, then qmetaobject and cxx-qt could theoretically be used together. Then the bindings like kconfig-rs can rely on cxx-qt-lib and be used with both projects.

To be clear, you would like to use cxx-qt-lib in qmetaobject? I didn't propose that before because I figure it would take a large effort, maybe as much work as it would to fill in the gaps to make cxx-qt usable for primarily Rust applications.

@Ayush1325
Copy link

Ayush1325 commented Mar 15, 2022

To be clear, you would like to use cxx-qt-lib in qmetaobject? I didn't propose that before because I figure it would take a large effort, maybe as much work as it would fill in the gaps to make cxx-qt usable for primarily Rust applications.

Well, I can't say anything for sure right now but I will probably start contributing to cxx-qt-lib once #105 is merged to first bring it to feature parity with qttypes. After that, I will try to see if it would be possible to replace qttypes with it. The feature parity part will take quite a while though so there's that. And I am not the maintainer of qmetaobject so I can't promise if everyone will agree to replace qttypes with cxx-qt-lib.

However, in my personal opinion, if we ignore the work to bring cxx-qt-lib up to feature parity with qttypes, then the amount of work it should take to replace qttypes with it should be less than having to add Rust application support in cxx-qt.

From my rough estimate, to add Rust application support to cxx-qt, we will need the following:

  1. Remove reliance on CMake. Maybe have a separate crate for applications that links to the qt stuff without CMake. It will also need to check the qt versions and platforms to work things out.
  2. Add support to register objects/singletons to QML at compile time. This is done using macros in qmetaobject and I am guessing we will need to do something similar here. Will also include support for connecting signals and slots.
  3. Since CMake is absent, the moc stuff, especially generating QMetaObject at compile time will need to be done from Rust.
  4. QRC support. Currently, qmetaobject has a qrc! macro for this.
  5. Support for QGadget, QEnum, etc. (Dunno if they already exist)

Basically, we will need to rewrite a lot of stuff that already exists in qmetaobject.

The work can be accelerated if someone is willing to mentor a project for GSoC from here (Of course I would love to participate as a student). I think someone mentioned in #kde-soc channel that I should see if someone would be willing to mentor something in cxx-qt as a KDE project in GSoC when I asked about a Rust project in KDE.

@Be-ing
Copy link
Contributor Author

Be-ing commented Mar 15, 2022

Interesting... @ogoffart, @ratijas, @rubdos, what are your thoughts on this?

@ogoffart
Copy link

From what I understand, this is the difference in philosophy between the two project. qmetaobject aim at just providing a idiomatic Rust API to use QML without having to care about C++ or the C++ API of Qt.

@Be-ing
Copy link
Contributor Author

Be-ing commented Aug 26, 2022

In #221 I got Cargo to run the entire build for an example QML application without needing CMake.

I made a helper crate for build.rs scripts called qt-build, which is in this repository now. This finds and links Qt and its dependencies using a regex to parse the .prl files that qmake uses. It also gets the header include paths for Qt. We have CI showing this works on Linux, macOS, and Windows, with Qt5 and Qt6, with static and dynamic linking, though there is still an issue with rpaths not getting set with dynamic linking due to that feature existing in Cargo yet (#224). The qt-build crate has helper methods for invoking moc and rcc, the output of which can then be compiled with cc, cpp_build, or cxx_build. qt-build does not compile any C++ on its own; I wrote it with the intention that it could also be used by qttypes and Whisperfish.

Now the cxx-qt-builder crate generates C++ code from the Rust module with the #[cxx_qt::bridge] attribute, uses qt-build to link Qt and run moc on the generated code, and compiles it with the cc crate. To get the whole executable building with Cargo, I wrote a small .cpp file which gets compiled by cc that has an extern "C" function invoked from the Rust executable's main function. This little .cpp file takes care of creating the QQmlApplicationEngine, initializing the Qt resource system, and registering the QML types. With this approach it is feasible to write most of an application in Rust with only ~25 lines of C++ code. Making Rust bindings for QGuiApplication, QQmlApplicationEngine, and qmlRegisterType is not needed. It would still be nice to be able to do this entirely from Rust without needing to manually write any C++ code. So, for me that's a low priority compared to other improvements for cxx-qt. Though if someone else wants to contribute those bindings that would be nice!

@Be-ing Be-ing self-assigned this Oct 18, 2022
@Be-ing Be-ing added this to the 0.5 milestone Oct 18, 2022
@ahayzen-kdab ahayzen-kdab assigned ahayzen-kdab and unassigned Be-ing Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 12, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 13, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 24, 2023
ahayzen-kdab added a commit to ahayzen-kdab/cxx-qt that referenced this issue Jan 24, 2023
Be-ing pushed a commit that referenced this issue Jan 24, 2023
Related to #291
Related to #113
Be-ing pushed a commit that referenced this issue Jan 24, 2023
@Be-ing Be-ing removed the ❌ wontfix This will not be worked on label Feb 9, 2023
@Be-ing
Copy link
Contributor Author

Be-ing commented Feb 9, 2023

It would still be nice to be able to do this entirely from Rust without needing to manually write any C++ code.

This is now implemented! Since #428 was merged yesterday, QML types and QRC resources can be automatically registered at build time. So now a QML application can be written entirely in Rust and built only with Cargo without needing CMake.

przempore pushed a commit to przempore/cxx-qt that referenced this issue Mar 15, 2023
przempore pushed a commit to przempore/cxx-qt that referenced this issue Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⬆️ feature New feature or request
Projects
None yet
4 participants