Rustはたまに触る程度で継続的にプログラミングを行っていないので時間が立つと忘れてしまいます。継続的に触れる機会としてなにかアプリケーションを作ろうと思います。ということでまずは見た目から。Rustで気になるGUI crateを試してみます。
どうやらデファクトスタンダードなGUI crateは現時点では存在せず、安定度もまちまちなようです。
そこで気になるcrateを使ってビルドができるのか?軽くサンプルプログラムを動作させて問題がなさそうか?、調べて見たいと思います。
2024/04-5月頃の情報になります。
ターゲット環境
開発環境
- Ubuntu 23.04 Desktop
- とりあえずOSBoxesよりダウンロードしたもので試用
- こちらでクロスコンパイルしてWindows向けにする
- 開発中はMobaXtermで画面をリモートに表示させたい
- rustc 1.77.2 (25ef9e3d8 2024-04-09)
実行環境
- Windows環境
共通
main.rsに下記を追加(オプショナル。実行時にDOS窓が表示されなくなる。他のcrateにも有効)
#![windows_subsystem = "windows"]
rust-toolchain.tomlのtargetに入れておいても良いが
rustup target add x86_64-pc-windows-gnu
dioxus
dioxusはデスクトップ、モバイル、Web、TUI(テキストベースのUI)などをカバーするフレームワークです。React系の設計思想です。クロスプラットフォーム対応です。
フルスタックを謳うフレームワークで機能が充実している分、必要なcrateが多いです。JavaScriptフレームワークのような専用コマンドが用意されています。
導入
sudo apt install -y gcc
sudo apt install -y make
cargo install [email protected]
dx new
✔ 🤷 Which sub-template should be expanded? · Desktop
🤷 Project Name: test01
✔ 🤷 How do you want to create CSS? · Vanilla
✔ 🤷 Should the application use the Dioxus router? · true
cd test01
sudo apt install -y pkg-config
sudo apt install -y librust-gio-sys-dev
sudo apt install -y libgtk-3-dev
sudo apt install -y libsoup-3.0-dev
sudo apt install -y libjavascriptcoregtk-4.1-dev
sudo apt install -y libwebkit2gtk-4.1-dev
sudo apt install -y libxdo-dev
dx serve --platform desktop
下記が場合によって必要かもしれません
sudo apt install -y libglib2.0-dev
クロスコンパイル
フレームワーク提供のコマンドで実行環境向けインストーラーが作成されるらしい。詳しくはこちらを参照。
main.rsに下記を追加(オプショナル。実行時にDOS窓が表示されなくなる。他のcrateにも有効)
#![windows_subsystem = "windows"]
Dioxus.tomlに下記を追加
[bundle]
resources = ["**/main.css", "**/header.svg" ]
dx bundle --release --platform desktop
Failed to bundle project: BundlerError(
Error {
context: "Failed to build data folders and files",
source: BundlerError(
Error {
context: "Failed to copy resource files",
source: IoError(
Os {
code: 36,
kind: InvalidFilename,
message: "File name too long",
},
),
},
),
},
)
結果
成果物はネイティブアプリケーションではありませんでした。ElectronやTauriのような実行環境の中でロジックが動くイメージでした。そのため、リモートに画面を表示することができません。
クロスコンパイルはBundlerErrorが出て先に進みませんでした。distフォルダーにassetsフォルダーの内容がコピーされているので動いてそうですが原因がよくわかりませんでした。
Assetsのドキュメントを見るとmanganisという別の仕組みが必要なようですがまだ不安定な印象です。
floem
floemはLapceというRustで書かれたエディターで使われているUIフレームワークです。クロスプラットフォーム対応でXilemや Leptos等に影響を受けたリアクティブ系のフレームワークのようです。
State管理はSolidJSと同様のアプローチのようです。
エディターというアプリケーションの実需で使用されているので安定度は高そうです。
導入
# Cargo.toml
[dependencies]
floem = "0.1.1"
sudo apt install -y gcc
cargo b
画面を最大化した場合、(X Window側の最大サイズを超えると)落ちる
cargo r
failed to present the surface buffer: PlatformError(Some("Failed to draw image to window"), Some(X11(ConnectionError(MaximumRequestLengthExceeded))))
サンプルプログラム
READMEにあるものを流用。
#![windows_subsystem = "windows"]
use floem::reactive::create_signal;
use floem::view::View;
use floem::views::{h_stack, label, v_stack, Decorators};
use floem::widgets::button;
fn app_view() -> impl View {
// Create a reactive signal with a counter value, defaulting to 0
let (counter, set_counter) = create_signal(0);
// Create a vertical layout
v_stack((
// The counter value updates automatically, thanks to reactivity
label(move || format!("Value: {}", counter.get())),
// Create a horizontal layout
h_stack((
button(|| "Increment").on_click_stop(move |_| {
set_counter.update(|value| *value += 1);
}),
button(|| "Decrement").on_click_stop(move |_| {
set_counter.update(|value| *value -= 1);
}),
)),
))
}
fn main() {
floem::launch(app_view);
}
クロスコンパイル
sudo apt install -y mingw-w64
cargo build --target x86_64-pc-windows-gnu
結果
コードがシンプルで良さそうですが、X Window上で画面を最大化するだけで落ちてしまうのは不便だし安定度が疑わしくなってしまいます。クロスコンパイルしてWindows環境で実行した際には最大化しても問題ありませんでした。
まだ知名度は低いので日本語の情報は少ないです。
追記(2025/02)
v0.2.0がリリースされたので試してみました。rustcのミニマムバージョンが1.80.1になっているのでアップデート。
error: package `image-webp v0.2.1` cannot be built because it requires rustc 1.80.1 or newer, while the currently active rustc version is 1.77.2
Either upgrade to rustc 1.80.1 or newer, or use
cargo update [email protected] --precise ver
where `ver` is the latest version of `image-webp` supporting rustc 1.77.2
あまりチェックできていませんがIntoView への変更、buttonのタイトルからクロージャーを削除して、useをpreludeに変更することで動くようになりました。
v_stack()やh_stack()も要らなくなったようなのでコレよりも記述量は減らすことができそうです。
# Cargo.toml
[dependencies]
floem = "0.2.0"
#![windows_subsystem = "windows"]
// // use floem 0.1.1
// use floem::peniko::Color;
// use floem::reactive::{create_rw_signal, create_signal};
// use floem::view::View;
// use floem::views::{h_stack, label, stack, v_stack, Decorators};
// use floem::widgets::button;
// use floem::widgets::slider;
// use floem 0.2.0
use floem::prelude::*;
fn app_view() -> impl IntoView {
// Create a reactive signal with a counter value, defaulting to 0
let (counter, set_counter) = create_signal(0);
// Create a vertical layout
v_stack((
// The counter value updates automatically, thanks to reactivity
label(move || format!("Value: {}", counter.get())),
// Create a horizontal layout
h_stack((
button("Increment").on_click_stop(move |_| {
set_counter.update(|value| *value += 1);
}),
button("Decrement").on_click_stop(move |_| {
set_counter.update(|value| *value -= 1);
}),
)),
))
}
fn main() {
floem::launch(app_view);
}
iced
icedはElmの設計思想に影響を受けた型安全なクロスプラットフォームのUIフレームワークです。Webまでカバーしているようですが、詳細は不明です。
導入
# Cargo.toml
[dependencies]
iced = "0.12.1"
sudo apt install -y gcc
cargo b
サンプルプログラム
Exampleより流用。
#![windows_subsystem = "windows"]
use iced::widget::{button, column, text};
use iced::{Alignment, Element, Sandbox, Settings};
pub fn main() -> iced::Result {
Counter::run(Settings::default())
}
struct Counter {
value: i32,
}
#[derive(Debug, Clone, Copy)]
enum Message {
IncrementPressed,
DecrementPressed,
}
impl Sandbox for Counter {
type Message = Message;
fn new() -> Self {
Self { value: 0 }
}
fn title(&self) -> String {
String::from("Counter - Iced")
}
fn update(&mut self, message: Message) {
match message {
Message::IncrementPressed => {
self.value += 1;
}
Message::DecrementPressed => {
self.value -= 1;
}
}
}
fn view(&self) -> Element<Message> {
column![
button("Increment").on_press(Message::IncrementPressed),
text(self.value).size(50),
button("Decrement").on_press(Message::DecrementPressed)
]
.padding(20)
.align_items(Alignment::Center)
.into()
}
}
クロスコンパイル
sudo apt install -y mingw-w64
cargo build --target x86_64-pc-windows-gnu
結果
コードがシンプルで良さそうです。クロスコンパイルも動作も問題ないようです。
ボタンの見た目がボタンらしくないのですが、サンプルを見るとちゃんとしているのでそのあたりの研究が必要かもしれません。レイアウト系がシンプルな仕組みのみで弱いかもしれません。
日本語の情報を多めです。ただし初心者向けのものが多いようです。
Vizia
Viziaは宣言的でリアクティブなクロスプラットフォーム対応のUIフレームワークです。アニメーションやGPUアクセラレーター対応のようです。
導入
# Cargo.toml
[dependencies]
#vizia = "0.1.0"
vizia = {git = "https://github.com/vizia/vizia"}
sudo apt install -y gcc
cargo b
サンプルプログラム
Bookより流用。
#![windows_subsystem = "windows"]
use vizia::prelude::*;
#[derive(Lens)]
pub struct AppData {
count: i32,
}
pub enum AppEvent {
Increment,
Decrement,
}
impl Model for AppData {
fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
event.map(|app_event, _meta| match app_event {
AppEvent::Decrement => self.count -= 1,
AppEvent::Increment => self.count += 1,
});
}
}
fn main() {
let _ = Application::new(|cx| {
AppData { count: 0 }.build(cx);
HStack::new(cx, |cx| {
Button::new(cx, |cx| Label::new(cx, "Decrement"))
.on_press(|ex| ex.emit(AppEvent::Decrement))
.class("dec");
Button::new(cx, |cx| Label::new(cx, "Increment"))
.on_press(|ex| ex.emit(AppEvent::Increment))
.class("inc");
Label::new(cx, AppData::count);
})
.child_space(Stretch(1.0))
.col_between(Pixels(20.0));
})
.title("Counter")
.inner_size((400, 100))
.run();
}
クロスコンパイル
sudo apt install -y mingw-w64
cargo build --target x86_64-pc-windows-gnu
結果
0.1.0ではコンパイルできませんでした。それ以外の部分では問題がありませんでした。
バージョンがまだ若いので今後大きな変化が起きる恐れがあります。
追記(2025/02)
v0.2.0がリリースされたので試してみました。
# Cargo.toml
[dependencies]
vizia = "0.2.0"
# 一旦 Linux環境向けにビルドをトライ
cargo build
error: rustc 1.77.0 is not supported by the following package:
[email protected] requires rustc 1.82
Either upgrade rustc or select compatible dependency versions with
`cargo update <name>@<current-ver> --precise <compatible-ver>`
where `<compatible-ver>` is the latest version supporting rustc 1.77.0
ミニマムのrustcバージョンが1.82以上必要なのでrust-toolchain.tomlを作成。
# rust-toolchain.toml
[toolchain]
channel = "1.84"
profile = "minimal"
targets = ["x86_64-pc-windows-gnu"]
ビルド時に下記エラーが発生。
= note: /usr/bin/ld: cannot find -lstdc++: No such file or directory
/usr/bin/ld: cannot find -lfontconfig: No such file or directory
/usr/bin/ld: cannot find -lfreetype: No such file or directory
/usr/bin/ld: cannot find -lEGL: No such file or directory
/usr/bin/ld: cannot find -lGL: No such file or directory
/usr/bin/ld: cannot find -lwayland-egl: No such file or directory
/usr/bin/ld: cannot find -lGLESv2: No such file or directory
collect2: error: ld returned 1 exit status
ライブラリファイルを確認してみると、
ldconfig -p | grep stdc++
libstdc++.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libstdc++.so.6
libstdc++.soファイルが無いことが原因らしい。シンボリックリンクを作成してみる。
cd /lib/x86_64-linux-gnu/
ln -s libstdc++.so.6 libstdc++.so
エラーになっている各ライブラリファイルに対して同様手順でリンク作成後に再びビルドするとエラーなくコンパイル完了。
しかし実行すると、
// thread 'main' panicked at /home/xxxxx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/vizia_winit-0.2.0/src/window.rs:90:22:
// called `Option::unwrap()` on a `None` value
// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
GitHubの最新のソースコードを見るとアップデートされていたので最新のコードを使ってみる。
# Cargo.toml
[dependencies]
# vizia = "0.2.0"
vizia = {git = "https://github.com/vizia/vizia"}
再びビルドをトライ、
error[E0599]: no method named `child_space` found for struct `vizia::view::Handle` in the current scope
--> src/main.rs:37:10
child_space()やcol_between()がないといわれるので最新のサンプルを元に修正。
})
.alignment(Alignment::Center) // Apply style and layout modifiers
.horizontal_gap(Pixels(50.0));
// .child_space(Stretch(1.0))
// .col_between(Pixels(20.0));
ビルドは成功。しかし実行すると、
// thread 'main' panicked at /home/xxxxx/.cargo/git/checkouts/vizia-a7ac1d316660c1f9/6108f71/crates/vizia_winit/src/window.rs:285:18:
// called `Option::unwrap()` on a `None` value
// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
また、ビルドができるようになったのでクロスコンパイルを試すと別のエラーが出た。これはrust-skiaがx86_64-pc-windows-msvcをtargetにしているためと思われる。cargo-xwin などを使えばクロスコンパイルできそうですがここで断念。
Xilem (2025/02追加)
XilemはFlutter, SwiftUI, Elmに影響を受けたUIフレームワークです。クロスプラットフォーム対応みたいですが詳細は不明。まだ実験的なUIとの位置づけ。こちらの記事で動いているようなので試してみました。
導入
# Cargo.toml
[dependencies]
xilem = "0.1.0"
ミニマムのrustcバージョンが1.82以上必要なのでrust-toolchain.tomlを作成。
# rust-toolchain.toml
[toolchain]
channel = "1.84"
profile = "minimal"
targets = ["x86_64-pc-windows-gnu"]
その他、clangなど必要なパッケージをインストールしようとしたらUbuntu Lunar LobsterがEOLで素直にインストールできなくなっていたのでこちらやこちらの記事を参考に対処。
# 環境依存、コレの実施は基本的に必要ないはず
sudo sed -i -e 's#http://archive.ubuntu.com/ubuntu#http://old-releases.ubuntu.com/ubuntu/#g' /etc/apt/sources.list
sudo apt update
sudo apt install -y clang libwayland-dev libxkbcommon-x11-dev libvulkan-dev
cargo b
サンプルプログラム
#![windows_subsystem = "windows"]
use xilem::view::{button, flex, label};
use xilem::{MasonryView, Xilem};
#[derive(Default)]
struct Counter {
value: i32,
}
fn app_logic(counter: &mut Counter) -> impl MasonryView<Counter> {
flex((
button("Decrement", |counter: &mut Counter| counter.value -= 1),
label(format!("Value: {}", counter.value)),
button("Increment", |counter: &mut Counter| counter.value += 1),
))
}
fn main() {
let app = Xilem::new(Counter::default(), app_logic);
app.run_windowed("Counter app".into()).unwrap();
}
クロスコンパイル
sudo apt install -y mingw-w64
cargo build --target x86_64-pc-windows-gnu
結果
コードがシンプルで良さそうです。クロスコンパイルも動作も問題ないようです。
ただし、公式サイトにも古い情報が多くサンプルプログラムを書くことも苦労した。日本語の情報を殆ど無いです。まだまだ実験的。
しかし、おかしなエラーにもほとんど遭遇することなく動いたので意外と好感。Elm的な書き方も好きです。
まとめ
各crateはほぼ何らかのJavaScriptフレームワークの影響を受けたものになっているので過去に使用したことがある場合は学習コストを抑えて使っていける可能性があります。
dioxusはエコシステムが充実しているので今後の期待度が高いですが、覚えることも多そうです。また、リモートに画面を表示することができなかったのが惜しいところです。
floemはシンプルに書けそうですが、最大化するだけで落ちるといった品質面に不安が残る結果となりました。またカッコが多くなりそうです。
icedはシンプルに書けそうですが、今回試した中でボタンの見た目が一番ネイティブ表示から遠いのでカスタマイズの可能性をもう少し調べる必要がありそうです。
Viziaはビルドはできますが、まだ公式バージョンが安定しておらず、バージョンも若いため今後大きな変化が起こる可能性があり、現時点で使用していくには勇気が必要です。
ただ、この記事を書いている最中もアップデートが進んでおり、上記紹介したサンプルも次のリビジョンで書き方が異なっているものもあります。これらのcrateを採用するにしても、まだプロトタイプレベルの使用に抑えておいたほうがいいかもしれません。
追記(2025/02)
floem 0.2.0は意味不明なクロージャーを書かなくてすむようになったらしく、よりシンプルに書けそうですが、最大化するだけで落ちるといった問題は品質面に不安が残る結果となりました。公式のサンプルプログラムを見るとカッコが大幅に減った書き方になっていました。
Vizia 0.2.0はビルドはできますが、まだ公式バージョンが安定しておらず、バージョンも若いため今後大きな変化が起こる可能性があり、現時点で使用していくには勇気が必要です。実行時エラーが出て動作確認まではできませんでした。また、x86_64-pc-windows-gnuに対応していないのが残念な点です。
Xilemはシンプルに書けそうですが、まだ実験的UIという位置づけでこれからも変化していく可能性があり、現時点で使用していくには勇気が必要です。情報が少ない為、ドキュメントの整備を待ちたいです。
floemに期待していますがアップデートが遅いのが残念な点です。