Rustをクロスコンパイルする際に利用する、crossというツールがあります。
crossには、target別にクロスコンパイル用のtoolchainを揃えたコンテナイメージが用意されており、cargoコマンドの代わりに、crossコマンドを使うことで、クロスコンパイル用のコンテナでビルドを行ってくれます。
クロスコンパイル用のtoolchainが予め導入されているといっても、必要なものが足りないということはありえます。その場合は、カスタムしたdocker imageを利用することで、必要なファイルをコンテナイメージに追加してビルドに利用することができます。
現状、よく問題になっていると思われるのが、OpenSSL用のライブラリが足りずにコンパイルできない、ということです。crossは現在(2020/8)、v0.2.1ですが、2020/2以前のv0.1.16まではOpenSSLのライブラリがコンテナに含まれていました。Remove OpenSSLを見ると、そもそもOpenSSLはcrossが本来サポートするスコープから外れているため、外そうということになったようです。
ただ、OpenSSLがビルドに必要なcrateは多かったようで、上記のissueにもいきなりビルドできなくなったんだけどどうしたらいいの? という質問が多くあります。自分も以前はissue内で紹介されている、crossを以前のバージョンで使用する(cargo install --version 0.1.16 cross)で回避していたのですが、ビルド時にpythonが必要なcrateを使う必要があり、カスタムdocker imageの作成を行ってみたので、その際のメモを残しておきます。
Cross.toml
カスタムdockerイメージを使う場合、Cross.tomlファイルに利用するイメージ名を指定しておきます。↓の例は自分のDocker Hubのイメージを指定していますが、ローカルのみで使う場合はタグがついていれば十分で、特にDocker Hubへpushする必要ありません。自分はtravis ciでのビルドでも利用するため、pushしています。
[target.x86_64-unknown-linux-gnu]
image = "k2da/hrkk-cross-linux-gnu:latest"
イメージの作成
本題のイメージを作成します。targetはx86_64-unknown-linux-gnuです。
最初は「apt-get install libssl-dev」のみで試してビルド自体は通ったのですが、生成されたバイナリがubuntuで動かなかったため、静的リンクに変更してます。
FROM rustembedded/cross:x86_64-unknown-linux-gnu-0.2.1
RUN apt-get update && \
apt-get install python --assume-yes
COPY openssl.sh /
RUN bash /openssl.sh linux-x86_64
ENV OPENSSL_DIR=/openssl \
OPENSSL_INCLUDE_DIR=/openssl/include \
OPENSSL_LIB_DIR=/openssl/lib \
OPENSSL_STATIC=1
ベースとしてcrossの最新のイメージを使用。openssl.shはcrossの0.1.16で使用されていたスクリプトをそのまま持ってきて、同じディレクトリに入れてあります。最後の環境変数は、静的リンクするために必要なもので、これも0.1.16のDockerfileを参考にしてます。
pythonは別の事情で入れてるだけなので、OpenSSLとは関係ありません。
dockerイメージをビルドして、tagをつけておきます。
# イメージビルドしてtagつける
docker build . -t k2da/hrkk-cross-linux-gnu:latest
ビルドする
cargoではなく、crossを使用するだけです。イメージはCross.tomlで指定してあるので、コマンド自体は通常のcrossでのビルドと同じです。
cross build --release --target x86_64-unknown-linux-gnu
これでビルド成功して、自分のubuntu環境では動きました。