WSLでRustのクロスコンパイル

# はじめに

備忘用。
Rustで記述されたHello Worldを出力するだけのコードを、WSLでコンパイルし、Windows向けのバイナリを生成する手順を記します。

# 手順

## 前提

環境はWSL2（Ubuntu 22.04）を使用しました。

## rustupのインストール

公式[^1]より、WSL内で以下を実行します。

```
> curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

以下が通れば、インストール成功です。
```
> rustup -v
（省略）
rustup 1.27.1 (54dd3d00f 2024-04-24)
（省略）
```

## Hello Worldプロジェクトの作成

ここでは、`test_rust`ディレクトリにプロジェクトを新規作成します。

```
> mkdir test_rust
> cd test_rust
> cargo init
```

上記の実行によって生成される`test_rust/src/main.rs`の内容は以下の通りです。（既にHello Worldを出力するようなコードとなっているため、特に修正しません。）

```rust
fn main() {
    println!("Hello, world!");
}
```

## crossのインストール

クロスコンパイルには、cross[^2]を利用します。
以下のようにして、インストールをします。

```
> cargo install cross
```

## dockerのインストール

crossを使うためには、コンテナエンジン（DockerかPodman）をインストールしておく必要があるとのこと。
今回利用しているディストリビューションはUbuntuなので、Dockerの公式docのUbuntuへのインストール手順[^3]を参照しインストールをしました。

なお、自分の環境では、Dockerデーモンが起動していなかったので、以下で起動しておきました。

```
> sudo service docker start
```

## Windows用のバイナリを生成

crossを使えば、Cargoプロジェクト配下（今回でいう`test_rust/`配下）で以下を実行するだけで、Windows用のバイナリを生成できます。
（具体的には、`test_rust/target/x86_64-pc-windows-gnu/debug/test_rust.exe`が生成されます。）

```
> cross build --target x86_64-pc-windows-gnu
```

`--target`オプションには、デフォルトで利用可能だった`x86_64-pc-windows-gnu`を指定しました。他にも、`x86_64-pc-windows-msvc`などが指定可能だったりします（`rustup target list`でtargetに指定可能なリストを確認できます）。

`cargo build`と同様に、`--release`オプションも指定可能です。以下を実行することで、`test_rust/target/x86_64-pc-windows-gnu/release/test_rust.exe`が生成されます。

```
> cross build --target x86_64-pc-windows-gnu --release
```

## （参考）ターゲットにx86_64-pc-windows-msvcを指定する

`cross build`の際、`--target`に`x86_64-pc-windows-msvc`を指定すると、エラーが発生します。以下に、エラーメッセージの抜粋を示します。

```
  = note: the `x86_64-pc-windows-msvc` target may not be installed
  = help: consider downloading the target with `rustup target add x86_64-pc-windows-msvc`
```
要は、インストールされていないとのこと。メッセージにある`rustup target add x86_64-pc-windows-msvc`を実行した後、再度`cross build`を実行してもエラーとなります。そのエラーメッセージには以下が書かれていました。

```
[cross] warning: `cross` does not provide a Docker image for target x86_64-pc-windows-msvc, specify a custom image in `Cross.toml`.
```

つまり、`x86_64-pc-windows-msvc`用のDockerイメージが無いとのことなので、イメージを作成する必要がありそうです。

そこで、crossのREADME[^4]を確認すると、以下のような記載がありました。

>Additional Dockerfiles for other targets can be found in cross-toolchains. These include MSVC and Apple Darwin targets, which we cannot ship pre-built images of.

そこで、cross-toolchains[^5]を使って、イメージをビルドします。READMEに従って、イメージを作成します。具体的なコマンドは以下の通り。

```
# 適当なディレクトリに移動
> cd ~/workspace

# クローン＆サブモジュール化
> git clone https://github.com/cross-rs/cross
> cd cross
> git submodule update --init --remote

# crosstoolイメージ用の設定
> cargo xtask configure-crosstool

# イメージのビルド
> cargo build-docker-image x86_64-pc-windows-msvc-cross --tag local
```

なお、自分が実行した際、ビルド時に以下のようなエラーが出ましたが、同様の事象を扱った記事[^6]を参考にさせていただき、`~/.docker/config.json`を修正して、解決しました（謎）。

```
ERROR: failed to solve: ubuntu:20.04: failed to resolve source metadata for docker.io/library/ubuntu:20.04: error getting credentials - err: exec: "docker-credential-desktop.exe": executable file not found in $PATH, out: ``
```

次に、`test_rust`配下に`Cross.toml`を作成し、以下を記述します。

```toml
[target.x86_64-pc-windows-msvc]
image = "ghcr.io/cross-rs/x86_64-pc-windows-msvc-cross:local"
```

そして、以下を実行することで、`test_rust/target/x86_64-pc-windows-msvc/debug/test_rust.exe`が生成されます。

```
> cross build --target x86_64-pc-windows-msvc
```

なお、`x86_64-pc-windows-msvc`と`x86_64-pc-windows-gnu`の違いは、いくつかの記事やスレッド[^7]で触れられたりしています。

[^1]:https://www.rust-lang.org/ja/tools/install
[^2]:https://github.com/cross-rs/cross
[^3]:https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
[^4]:https://github.com/cross-rs/cross?tab=readme-ov-file#supported-targets
[^5]:https://github.com/cross-rs/cross-toolchains
[^6]:https://qiita.com/rasuk/items/a36b29b8c79d02fc551a
[^7]:https://www.reddit.com/r/rust/comments/a63dlt/comment/ebrbi8d/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button によると、ビルドにMinGWを利用するのが`gnu`、Visual Studio Build Toolsを使うのが`msvc`とのこと。他にも、https://github.com/sharkdp/fd/issues/726 や https://users.rust-lang.org/t/x86-64-pc-windows-gnu-and-x86-64-pc-windows-msvc-abi-compatibility/117236 などで両者の違いについて触れられている。