Linux(WSL2)からTauriアプリをWindows向けにクロスコンパイルする(Experimental)
※今回の時点でのTauriのバージョンはv1.5です
※あとTauriそのものの説明は省きます
TL;DR;
Tauriのクロスプラットフォームビルドは2024年1月時点で未サポートであり保証外だが、
rust-crossやcross-rsによるツールを活用することで意外と楽にLinux上でWindows向けクロスコンパイルが可能。
targetがx86_64-pc-windows-msvc
の場合、cargo-xwin
が便利
# Linux上で実行
rustup target add x86_64-pc-windows-msvc
cargo install cargo-xwin
# Windows向けクロスコンパイル用のコマンド:
cargo xwin build --release \
--features custom-protocol \
--target x86_64-pc-windows-msvc
targetがx86_64-pc-windows-gnu
の場合、cross
が便利
# Linux上で実行
cargo install cross
# Windows向けクロスコンパイル用のコマンド:
cross build --release \
--features custom-protocol \
--target x86_64-pc-windows-gnu
はじめに
公式ドキュメント Cross-Platform Compilation冒頭部分:
(...中略), so meaningful cross-compilation is not possible at the current moment.
と記載されているように、
執筆時点(2024年1月25日)でクロスコンパイルは未サポート、というか基本的に不可能とされている。
なので、真面目な用途であれば現時点では本記事の内容は無意味であり、GitHub Actionsなどサポートされているまともなやり方を採用すべきである。
一方で同ページを下までスクロールしていくと、
Experimental: Build Windows apps on Linux and macOSという項目があり、色々とサポート外だが一応方法がある旨が記されている。
が、かなり面倒なのでrust-crossやcross-rsによるツールを活用してなるべく楽にビルドを試みる。
実行
(検証環境)
Windows11のWSL2上で動作しているLinuxで検証を実施した。
詳細情報は以下:
(検証環境詳細)
# OS情報
uname -a
# Linux <My-Machine-Name> 5.15.133.1-microsoft-standard-WSL2 #1 SMP Thu Oct 5 21:02:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
$ head /etc/os-release -n 5
# PRETTY_NAME="Ubuntu 23.10"
# NAME="Ubuntu"
# VERSION_ID="23.10"
# VERSION="23.10 (Mantic Minotaur)"
# VERSION_CODENAME=mantic
# Nodejs
$ node --version
# v20.11.0
$ pnpm --version
# 8.14.3
# Rust
$ cargo --version
# cargo 1.75.0 (1d8b05cdd 2023-11-20)
$ rustup --version
# rustup 1.26.0 (5af9b9484 2023-04-05)
$ apt list --installed | grep build-essential
# build-essential/mantic,now 12.10ubuntu1 amd64 [installed]
$ cargo xwin --version
# cargo-xwin-xwin 0.16.3
$ cross --version
# cross 0.2.5
$ docker --version
# Docker version 25.0.1, build 29cf629
# (↑crossでDockerコンテナを実行するため)
↑上記はUbuntuだが、他にもFedora39などでも同様に動くことは確認済み
(Tauriプロジェクト作成)
公式記載のQuick Startを使う。
割と何でも良いはずだが、今回はvite + Reactベースのものにした。
あとパッケージマネージャーも何でも良いがpnpmにしている。
pnpm create tauri-app
# ↓入力・選択した各項目
✔ Project name · tauri-app
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, bun)
✔ Choose your package manager · pnpm
✔ Choose your UI template · React - (https://reactjs.org/)
✔ Choose your UI flavor · TypeScript
出来上がったプロジェクトの構成はこんな感じ↓
tauri-app ディレクトリ構成
$ tree --gitignore
.
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── tauri.svg
│ └── vite.svg
├── README.md
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── main.tsx
│ ├── styles.css
│ └── vite-env.d.ts
├── src-tauri
│ ├── build.rs
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── icons
│ │ └── (省略, pngファイルなど)
│ ├── src
│ │ └── main.rs
│ └── tauri.conf.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
今回だとnodeプロジェクトの中にrustプロジェクト(src-tauri/
以下)が入っているような構成になっている。
これをLinux上からWindows向けのtargetにコンパイルを行っていく。
1. x86_64-pc-windows-msvc向けコンパイル
targetをx86_64-pc-windows-msvc
にしてコンパイルする。
公式のBuild Windows apps on Linux and macOSもmsvcをtargetにする方を記載しており、
おそらくx86_64-pc-windows-gnu
よりこちらの方がベターと思われる。
なお、それぞれのtargetの違いについてはrustupのドキュメント↓などを参照のこと
ここで、先のBuild Windows apps on Linux and macOSの記載手順はかなり複雑で辛そうなので、冒頭に書いた[rust-cross/cargo-xwin]を使ってビルドする。
必要ツールのセットアップは以下のような感じ:
# targetにx86_64-pc-windows-msvcを追加
rustup target add x86_64-pc-windows-msvc
# cargo-xwinコマンドを使えるようにする:
cargo install cargo-xwin
# バージョン指定してインストールする場合:
cargo install cargo-xwin@0.16.3
ここで、さっき作ったtauriプロジェクトでアプリのビルドを行う際、
普通だったら
# ※npm, yarnを使うひとは適宜読み替えてください(以降も同様)
# ※↓今回(Windows向けクロスコンパイル時)は実行しない
pnpm tauri build
などでビルドを実施する。
これで開発環境と同じプラットフォーム向け(ここではLinux)のビルドが実施されるが、
今回はここでtargetをwindows-msvcに変えて実施したい。
ターゲットオプション--target
を指定して上記コマンドを実行することは可能だが、
そのままだと内部的に普通にcargo build
が走るためさっきのcargo-xwin
などの代替ツールを使うことが出来ないため、途中でビルドが失敗してしまう。
そこで、頑張ってpnpm tauri build
の実行内容を推測してみる。
(ピンポイントで知りたい情報がすぐ見つからなかったので、雰囲気で推測している。)
まずtauri.conf.json
を参照すると、
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devPath": "http://localhost:1420",
"distDir": "../dist"
}
}
などと書いてある。これにより、アプリのビルド時は予めpnpm build
でフロントエンド部分をビルドしておき(beforeBuildCommand)、
アプリに表示するページの中身として../dist
(pnpm build
で生成されたアセット)を指定していることが伺える。
次に、Cargo.toml
の方を見てみる:
[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"]
features
部分を参照することで、
開発用ビルド(pnpm tauri dev
のとき)と本番用ビルド(pnpm tauri build
のとき)の挙動の差に効いていることが伺える。
cargoコマンドを実行する際は、--features
フラグを指定することで指定が可能:
ここで、先ほどのコマンドpnpm tauri build
は下記の内容と大体同じになると考えられる:
# フロントエンド(今回はvite + React)側のビルド・静的アセットの生成
pnpm build
cd tauri-src
cargo build --release \
--features custom-protocol
ここで、cargo build
部分をcargo xwin build
に置き換え、更にtargetをx86_64-pc-windows-msvc
に指定することでビルドができると考えられる。
# クロスコンパイルのために実行するコマンド:
# フロントエンド側のビルド
pnpm build
cd tauri-src
cargo xwin build --release \
--features custom-protocol \
--target x86_64-pc-windows-msvc
これで、src-tauri/target/x86_64-pc-windows-msvc/release
下にビルドされたアプリが置かれる:
ls src-tauri/target/x86_64-pc-windows-msvc/release/
# build/ deps/ examples/ incremental/ tauri-app.d tauri-app.exe* tauri_app.pdb
今回の場合、tauri-app.exe
の単一ファイルさえあればアプリを実行できる:
ミニマルな機能だと5MBくらいで済んでおり、思ったよりだいぶコンパクト。
(例えばElectronなどはChromiumとNodejsを同梱するため機能ゼロでも180MBくらいのサイズになる)
上記のexeファイルを実行すると、
期待通りにちゃんとTauriアプリがWindows上で起動しており、@tauri-apps/api
を使ったフロントエンド側とRust側の連携部分も動いていることが確認できる。
2. x86_64-pc-windows-gnu向けコンパイル(おまけ)
targetをx86_64-pc-windows-gnu
にしてビルドすることも一応できたので参考に書いておく。
今度はcross-rs/cross
を使う。
インストール:
cargo install cross
# バージョン指定
cargo install cross@0.2.5
Dockerコンテナを使ってビルドしてくれるのでホスト側に色々入れたりする必要が無いのだが、
先程のtauri build
の挙動を把握しておかないと詰まる。
すなわち、ビルド時にコンテナにカレントディレクトリをマウントするのだが、
さっき作ったプロジェクトの場合だとフロントエンドのビルドアセットがCargo.tomlが置いてあるsrc-tauri
から見て親ディレクトリに存在するため、コンテナにマウントされておらずビルドが失敗してしまう。
そこで、cross
を使う場合はフロントエンドのビルドアセットが吐き出される場所を少し調整すると良い。
今回はviteを使っているので、
を参考に、
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig(async () => ({
// ...
// 以下: build.outDirを追記
+ build: {
+ outDir: "src-tauri/dist",
+ },
}));
のように追記する。
また、tauriのビルド時に参照するフロントエンドアセットのパスも合わせて調整しておく:
{
"build": {
// ...
- "distDir": "../dist"
+ "distDir": "./dist"
},
// ...
}
これでsrc-tauri
ディレクトリをコンテナにマウントしてもフロントエンドのビルドアセットが見えるようになった。
これで、先ほどのようにフロントエンドのビルドとRust部分のビルドを順に行っていく。
# フロントエンドのビルド
pnpm build
# ↑src-tauri/dist にビルドアセットが格納
cd src-tauri
# crossを使ってTauriアプリ(Rust)をクロスコンパイル
cross build --release \
--features custom-protocol \
--target x86_64-pc-windows-gnu
これで、src-tauri/target/x86_64-pc-windows-gnu/release
下にビルドされたアプリが置かれる:
ls src-tauri/target/x86_64-pc-windows-gnu/release/
# build deps examples incremental tauri-app.d tauri-app.exe WebView2Loader.dll
今回の場合、tauri-app.exe
とWebView2Loader.dll
の2つのファイルがあればアプリを実行できる:
x86_64-pc-windows-msvc
のときは5MBくらいだったのに比べると若干サイズが大きい(20MB以上)←それでもElectronよりはだいぶコンパクト
実行結果:
先ほどの場合と同様のWindowsアプリが立ち上がっており、
ファイルサイズの大きさや追加のdllファイルが必要なこと以外にすぐ分かる差異は無く、問題なく動いていそうな感じ。
まとめ
ここまでで作ったものを一応GitHubに保存しておいた:
今回使ったTauriのバージョンや、その他プロジェクトで使われているパッケージのバージョン詳細も↑を参照のこと。
ビルド用のコマンドが長いので、適当過ぎる感じはあるがnpm-scriptのdist:win-msvc
およびdist:win-gnu
にそれぞれ登録している。
# x86_64-pc-windows-msvc向けビルド
pnpm dist:win-msvc
# x86_64-pc-windows-gnu向けビルド
pnpm dist:win-gnu
これで遊びに動かす程度であれば問題なさそうなセットアップを実現できた。
あくまで保証外なので開発を進めていくとうまく動かなくなる可能性もあるが、
アプリのソースコードは一切変えていないので、それこそ問題が起きたら公式が推奨・サポートしている正規のやり方でビルドするようにすればOKなはず。
Discussion