#2016/9/11追記
この記事の情報は古くなってしまったので「RustのLinux/Windows/OS X向けバイナリをCIで生成する(更新版)」をどうぞ。
はじめに
RustはLinux/Windows/OS Xをサポートしていますが、Goのように簡単にクロスコンパイルできるわけではありません。(いろいろ設定すると最終的に出来るようにはなるのですが、かなり面倒な印象です)
手元でできないならCIでやればいい、ということで今回はCI環境で以下の6つのバイナリを生成できるようにしました。
- Linux 64bit
- Linux 32bit
- Windows 64bit
- Windows 32bit
- OS X 64bit
- OS X 32bit
前提
この情報は2016/1/24時点のものです。各CIサービスの状況や、Rustが提供するstd-libのURLなどが今後変わった場合にうまくいかなくなるかもしれません。
使うCIサービスは以下の2つです
Travis-CIでLinux/OS X向けビルドを、AppVeyorでWindows向けビルドを行います。(当初Travis-CIでmingwを使ったWindows向けクロスコンパイルも試みたのですが、うまくいかなかったためAppVeyorに切り替えました)
Travis-CIによるLinux/OS X向けビルド
language: rust
os:
- linux
- osx
rust: stable
before_install:
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then sudo apt-get -qq update; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then sudo apt-get install -y gcc-multilib g++-multilib; fi
before_script:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then curl -O https://static.rust-lang.org/dist/rust-std-1.6.0-i686-apple-darwin.tar.gz; fi
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then tar xf rust-std-1.6.0-i686-apple-darwin.tar.gz; fi
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then mv rust-std-1.6.0-i686-apple-darwin/rust-std-i686-apple-darwin/lib/rustlib/i686-apple-darwin ~/rust/lib/rustlib/; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then curl -O https://static.rust-lang.org/dist/rust-std-1.6.0-i686-unknown-linux-gnu.tar.gz; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then tar xf rust-std-1.6.0-i686-unknown-linux-gnu.tar.gz; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then mv rust-std-1.6.0-i686-unknown-linux-gnu/rust-std-i686-unknown-linux-gnu/lib/rustlib/i686-unknown-linux-gnu ~/rust/lib/rustlib/; fi
script:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then cargo build --release --target=x86_64-apple-darwin; fi
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then cargo build --release --target=i686-apple-darwin; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then cargo build --release --target=x86_64-unknown-linux-gnu; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then cargo build --release --target=i686-unknown-linux-gnu; fi
Travis-CIのOSは$TRAVIS_OS_NAME
で取れるので、それに応じて動作を切り替えます。
before_install
で32bitビルド用のmultilibを、before_script
で32bitのrustlibを展開します。Travis-CIのlanguage: rust
指定におけるRustのバスは~/rust
なので展開先は~/rust/lib/rustlib
になります。
また、rustlibのバージョンは直接書いていますが、stable前提なら$(rustc --version | awk '{print $2}')
などとしてもよいかもしれません。(動作は未確認です)
Travis-CIによるWindows向けビルド(失敗)
language: rust
os:
- linux
rust: stable
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y binutils-mingw-w64 mingw-w64
before_script:
- curl -O https://static.rust-lang.org/dist/rust-std-1.6.0-x86_64-pc-windows-gnu.tar.gz
- tar xf rust-std-1.6.0-x86_64-pc-windows-gnu.tar.gz
- mv rust-std-1.6.0-x86_64-pc-windows-gnu/rust-std-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu ~/rust/lib/rustlib/
script:
- cargo build --release --target=x86_64-pc-windows-gnu
基本的にLinux/OS X向けビルドと同様ですが、before_install
でmingwのインストールをしています。
また、インストールするだけでは使ってくれないので、Cargo.toml
などがあるディレクトリに.cargo
ディレクトリを作成し、.cargo/config
に以下のように書きます。
これで特定targetの時のみ指定したlinker/arを使ってくれるようになります。
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-ar"
手元のCentOS7.2環境ではこれでビルドが通ったのですが、Travis-CIのUbuntu上ではリンク時にundefined reference
になってしまいます。
(念のためtrustyも試しましたが、同様に失敗しました)
AppVeyorによるWindows向けビルド
platform:
- x64
environment:
RUST_INSTALL_DIR: C:\Rust
matrix:
- RUST_INSTALL_TRIPLE: i686-pc-windows-msvc
RUST_VERSION: 1.6.0
- RUST_INSTALL_TRIPLE: x86_64-pc-windows-msvc
RUST_VERSION: 1.6.0
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:RUST_VERSION}-${env:RUST_INSTALL_TRIPLE}.exe"
- cmd: rust-%RUST_VERSION%-%RUST_INSTALL_TRIPLE%.exe /VERYSILENT /NORESTART /DIR="%RUST_INSTALL_DIR%"
- cmd: SET PATH=%PATH%;%RUST_INSTALL_DIR%\bin
build_script:
- cmd: cargo build --release --target=%RUST_INSTALL_TRIPLE%
AppVeyorの設定はこちらの記事を参考に(というかほぼコピペ)させていただきました。
当然ですが普通のWindows環境なので特筆すべきことはありません。
opensslを含む場合(2016/2/21追記)
依存関係上opensslを含むライブラリ(例えばhyperなど)を使う場合に問題がありましたので追記します。
まず、Travis-CIのLinuxビルドですが、現在デフォルトのUbuntu12.04はopensslのmultiarch対応にバグがあるらしく、32bitビルドが通りません。そのためUbuntu14.04(trusty)を使う必要があります。また、libssl-dev:i386
はlibssl-dev
とコンフリクトするので32bitビルドと64bitビルドを同時に出来ないようです。(Debian系のパッケージはよくわからないので使い方が間違ってるかもしれませんが)
というわけで、以下のようにtrusty
を指定、32bitビルドと64bitビルドを分ければいけました。
dist: trusty
env:
- ARCH=i686
- ARCH=x86_64
before_install:
- if [[ $TRAVIS_OS_NAME == "linux" && $ARCH == "i686" ]]; then sudo apt-get -qq update; fi
- if [[ $TRAVIS_OS_NAME == "linux" && $ARCH == "i686" ]]; then sudo apt-get install -y gcc-multilib g++-multilib libssl-dev:i386; fi
また、WindowsはそもそもOpenSSLが入っていないので入れるところからになります。64bit版と32bit版でインストーラやライブラリのパスが違うのでそれぞれ設定します。(環境変数の設定はここを参考にしました)
以下に差分だけ書いておきます。
environment:
matrix:
- OPENSSL_ARCH: Win32
OPENSSL_LIB_DIR: C:\OpenSSL-Win32\lib\VC
OPENSSL_LIBS: ssleay32MT:libeay32MT
OPENSSL_INCLUDE_DIR: C:\OpenSSL-Win32\include
DEP_OPENSSL_INCLUDE_DIR: C:\OpenSSL-Win32\include
- OPENSSL_ARCH: Win64
OPENSSL_LIB_DIR: C:\OpenSSL-Win64\lib\VC
OPENSSL_LIBS: ssleay32MT:libeay32MT
OPENSSL_INCLUDE_DIR: C:\OpenSSL-Win64\include
DEP_OPENSSL_INCLUDE_DIR: C:\OpenSSL-Win64\include
install:
- ps: Start-FileDownload "http://slproweb.com/download/${env:OPENSSL_ARCH}OpenSSL-1_0_2f.exe"
- ps: Start-Process "${env:OPENSSL_ARCH}OpenSSL-1_0_2f.exe" -ArgumentList "/silent /verysilent /sp- /suppressmsgboxes" -Wait
まとめ
RustのLinux/Windows/OS X向けバイナリ計6種をCIで生成してみました。Travis-Ci上でWindowsコンパイルは時間の関係で早々にあきらめましたが、うまくいっている方がいらっしゃいましたら教えてください。