Building a simple Qt application with Rust
CXX-Qt provides helper libraries that make it easy for the Rust build system to link to Qt.
The goal for now is to create a simple program that just launches an Qt/QML application.
✅ In the workspace create a new Rust application
cargo new --bin qt-gui
✅ Add the new crate to the workspace
[workspace]
members = ["cli", "image-manipulation", "qt-gui"]
resolver = "2"
✅ Then enter our new crate
cd qt-gui
✅ Add a simple QML main file in qml/main.qml
$ mkdir qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
ApplicationWindow {
height: 480
title: qsTr("Hello World")
visible: true
width: 640
}
✅ Add dependencies to the Cargo.toml
file
[dependencies]
rustagram2 = "*"
image-manipulation = { path = "../image-manipulation" }
cxx = "1.0.95"
cxx-qt = "0.6"
cxx-qt-lib = "0.6"
[build-dependencies]
# The "link_qt_object_files" is required when using Cargo to link to Qt statically.
cxx-qt-build = { version = "0.6", features = [ "qt_qml", "link_qt_object_files" ] }
CXX-Qt is split up into multiple crates.
- CXX-Qt - Allows you to create QObjects from Rust and to interact with existing QObjects
- CXX-Qt-lib - Library of bindings to Qt types like
QString
,QApplication
, etc. - CXX-Qt-build - A build-system library to link Rust with Qt, build QML modules, etc.
We will also need CXX itself later on, so include that as well.
✅ Next to the Cargo.toml
file, add a build.rs
file with the following contents:
use cxx_qt_build::{CxxQtBuilder, QmlModule};
fn main() {
CxxQtBuilder::new()
// - Qt Core is always linked
// - Qt Qml is linked by enabling the qt_qml Cargo feature.
// - Qt Qml requires linking Qt Network on macOS
.qt_module("Network")
.qt_module("Quick")
.qml_module(QmlModule::<&str, _> {
uri: "com.kdab.cxx_qt.demo",
rust_files: &[],
qml_files: &["qml/main.qml"],
..Default::default()
})
.build();
}
It uses the cxx-qt-build
library to:
- Check that the QtQuick module is available
- Create a QML module out of the
main.qml
file. - Link the QML module and Qt itself to our Rust application.
Troubleshooting: It is important that the
build.rs
file is next to theCargo.toml
file at the root of the crate.It can NOT be located in the
src/
directory.
✅ Add the startup code to src/main.rs
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};
fn main() {
// Create the application and engine
let mut app = QGuiApplication::new();
let mut engine = QQmlApplicationEngine::new();
// Load the QML path into the engine
if let Some(engine) = engine.as_mut() {
engine.load(&QUrl::from("qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml"));
}
// Start the app
if let Some(app) = app.as_mut() {
app.exec();
}
}
Take a minute to thoroughly read this code and compare it to a typical C++ main function that launches a Qt application.
❓ What is different? What is similar?
❓ Why are theif let Some(...)
expressions necessary?
✅ Run the application
cargo run
If
qmake
is not in your path, remember to tell Cargo where to find it with theQMAKE
environment variable.QMAKE=.../qmake cargo run
✅ An empty window appears