Rustでクロスコンパイルしてみた

ふとLinuxでもWindowsでも遊べるゲームを作ってみたいと思ったので、Rustをやってみることにしました。 Ubuntu 16.04からWindows向けのバイナリの出力をします。

環境の準備

まずはRustのコンパイラ(rustc)、ビルドツール(cargo)、ツールチェーンインストーラ(rustup)をインストールします。これらすべて、$ curl https://sh.rustup.rs -sSf | sh を実行し、1番(Proceed with installation (default))を選択すると一度にインストールすることができます。 インストールされるディレクトリにパスを通さなくてはならないので、 [[ -s source $HOME/.cargo/env ]] && source $HOME/.cargo/env を私は ~/.zshrc に追記しました。

プロジェクトの作成

次にCargoを使ってプロジェクトを作成します。

cargo new hello_world --bin

これでhello_worldディレクトリと、その中にビルドに必要なものが生成されます。

まずはUbuntu向けにビルド

すでに src/main.rs にHello Worldプログラムが生成されています。

$ cat src/main.rs

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

Cargoプロジェクトになっているので、 $ cargo run を実行するだけで、コンパイルと生成されたバイナリの実行ができます。

$ cargo run

    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_world`
Hello, world!

Windows向けにビルド

Windowsをビルド対象にするときの名前が分からないので調べます。

rustup target list | grep windows

i586-pc-windows-msvc
i686-pc-windows-gnu
i686-pc-windows-msvc
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc

今回は x86_64-pc-windows-gnu を対象にします。

WindowsのGCCでWindows向けのビルドをするためのライブラリ、 MinGW をインストールします。 :code: sudo apt install -y mingw-w64

さらにRustのために、 x86_64-pc-windows-gnu のコンポーネントをインストールします。

$ rustup target add x86_64-pc-windows-gnu

これで $ cargo build --target x86_64-pc-windows-gnu でWindows向けにビルドができるはずでしたが、このようなエラーが出てしまいました。

   Compiling hello_world v0.1.0 (file:///home/motoki/workspace/rust-cross-compile/hello_world)
error: linking with `gcc` failed: exit code: 1
  |
  = note: "gcc" "-Wl,--enable-long-section-names" "-fno-use-linker-plugin" "-Wl,--nxcompat" "-nostdlib" "-m64" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/rsbegin.o" "-L" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib" "/home/motoki/workspace/rust-cross-compile/hello_world/target/x86_64-pc-windows-gnu/debug/deps/hello_world-3d24a34e7df170fb.0.o" "-o" "/home/motoki/workspace/rust-cross-compile/hello_world/target/x86_64-pc-windows-gnu/debug/deps/hello_world-3d24a34e7df170fb.exe" "-Wl,--gc-sections" "-nodefaultlibs" "-L" "/home/motoki/workspace/rust-cross-compile/hello_world/target/x86_64-pc-windows-gnu/debug/deps" "-L" "/home/motoki/workspace/rust-cross-compile/hello_world/target/debug/deps" "-L" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-2552e7df15c9fb68.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/librand-922f14c6c06fa38e.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libcollections-fa763888bb715af8.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd_unicode-425480962e0d0404.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libpanic_unwind-6a1e0d1dbeafd6e2.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libunwind-f68e43a1e89bc0f9.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/liblibc-72343f2c6d58d279.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/liballoc-3ac1800e55dc88aa.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/liballoc_system-95d71b27db0ba72f.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libcore-a0bb2439f0343129.rlib" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libcompiler_builtins-558a6da79faba1ce.rlib" "-l" "advapi32" "-l" "ws2_32" "-l" "userenv" "-l" "shell32" "-l" "gcc_eh" "-lmingwex" "-lmingw32" "-lgcc" "-lmsvcrt" "-luser32" "-lkernel32" "/home/motoki/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/rsend.o"
  = note: /usr/bin/ld: unrecognized option '--enable-long-section-names'
/usr/bin/ld: use the --help option for usage information
collect2: error: ld returned 1 exit status


error: aborting due to previous error

error: Could not compile `hello_world`.

To learn more, run the command again with --verbose.

幸運なことに4日前にGitHubの Issue に解答がついていました。これに従い、このコマンドを実行します。

cat << EOS > ~/.cargo/config
[target.x86_64-pc-windows-gnu]
linker = "/usr/bin/x86_64-w64-mingw32-gcc"

[target.i686-pc-windows-gnu]
linker = "/usr/bin/i686-w64-mingw32-gcc"
rustflags = "-C panic=abort"
EOS

これで再度ビルドします。 $ cargo build --target x86_64-pc-windows-gnu

Compiling hello_world v0.1.0 (file:///home/motoki/workspace/rust-cross-compile/hello_world)
 Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs

今度はエラーになりませんでした。そしてexeファイルが生成されていました。

$ ls target/x86_64-pc-windows-gnu/debug/

build  deps  examples  hello_world.exe  native

Windowsに hello_world.exe をコピーして実行します。

Windows PowerShellで hello_world.exe のあるディレクトリに移動し、 > ./hello_world.exe を実行すると Hello World! が出力されました。

これで完了です。

コメント

2015 - 2017 (c) 成瀬基樹