LoginSignup
10

More than 5 years have passed since last update.

RustのLinux/Windows/OS X向けバイナリをCIで生成する

Last updated at Posted at 2016-01-24

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向けビルド

travis.yml
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向けビルド(失敗)

travis.yml
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向けビルド

appveyor.yml
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:i386libssl-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コンパイルは時間の関係で早々にあきらめましたが、うまくいっている方がいらっしゃいましたら教えてください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10