Open1

(失敗)Rustのクロスコンパイルcross用のdockerを自前で用意する(glibcバージョン対策)

yunayuna

結論

※現在、ほしいGlibcのバージョンのubuntu(21.10)はサポート外のため、断念しました。
 素直にdocker hubでほしいコンテナ探して、そこでビルドしました。

要件

Rustのビルドを、 x86-64_linux_unknown_gnu ターゲットで行うとき、
その環境のglibcバージョンでバイナリが作成される。
cross の自動ビルドを
このとき、バイナリ実行に必要な条件として、
ビルド環境のglibcバージョン <= バイナリを実行する環境のglibc

である必要があるため、
開発環境のビルド環境が新しすぎたりすると、古い環境でバイナリ実行できないことがある。
また、利用しているcrateによっては、glibcのバージョンに制約がある場合があり、
ビルド環境のglibcバージョンを、明示的にセットしたいということがある。

方法として、
・dockerでその環境を作ってビルド
・クロスコンパイルツール"cross" 用に、docker imageを準備してそれを利用してビルドする

がある。
crossで用意されているバイナリは、一昔前のものが多いので、
例えばx86_64-unknown-linux-gnu は、libcバージョンは 2.31 となっている。
(このバージョンで良ければ、すでに用意されているものが使われるので、何もせずcross buildすればOK)
https://github.com/cross-rs/cross?tab=readme-ov-file#supported-targets

今回、libcのバージョン2.34が必要なので、
それを作るまでをメモしていきます。

参考記事
https://github.com/cross-rs/cross/tree/main/docker
https://www.kabegiwablog.com/entry/2022/07/02/155522

方針

crossで用意されているdocker fileを元に、glibcのバージョンを2.34のubuntuバージョンに書き換える

docker fileをチェック

crossが用意しているx86_64-unknown-linux-gnuのDockerfile
https://github.com/cross-rs/cross/blob/main/docker/Dockerfile.x86_64-unknown-linux-gnu

ubuntu21.10が、glibcのバージョン2.34なので、
ここを書き換える

FROM ubuntu:20.04 as cross-base
ENV DEBIAN_FRONTEND=noninteractive

FROM ubuntu:21.10 as cross-base
ENV DEBIAN_FRONTEND=noninteractive

このファイルを保存する。
また、DockerFile内で利用しているファイルがいくつかあるので、あらかじめcrossのgithub上から
落としておく

https://github.com/cross-rs/cross/blob/main/docker/toolchain.cmake

Crossの設定をCross.tomlに記述

Cargo.tomlと同じ階層に、Cross.tomlを作成し、ターゲット別のビルドルールを記述する。
ここで、上記で保存したDockerFileのパスを指定

Cargo.toml
[target.x86_64-unknown-linux-gnu]
dockerfile = "./shells/DockerFile_glibc2.34.x86_64-unknown-linux-gnu"

dockerkitを入れる

crossは、Docker Buildx を使ってるので、環境にDocker buildkitが入ってない場合は事前に入れておく
https://gist.github.com/jniltinho/bcb28a99aef33dcb5f35c297bf71e4ae

#!/bin/bash
#
# https://docs.docker.com/build/buildkit/
# https://github.com/docker/buildx/releases/
# https://github.com/docker/buildx

## docker builder prune --all
## docker buildx du --verbose

## For Ubuntu 24.04 try: sudo apt install docker-buildx
## Or run the commands below.

#VERSION=v0.14.1
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/docker/buildx/releases/latest)
VERSION=${VERSION##*/}

mkdir -p $HOME/.docker/cli-plugins
wget https://github.com/docker/buildx/releases/download/$VERSION/buildx-$VERSION.linux-amd64 -O $HOME/.docker/cli-plugins/docker-buildx
chmod +x $HOME/.docker/cli-plugins/docker-buildx

export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1

echo 'export DOCKER_BUILDKIT=1' >> $HOME/.profile
echo 'export COMPOSE_DOCKER_CLI_BUILD=1' >> $HOME/.profile

crossのdockerから、一連のファイルを持ってきて、ローカルでbuildする

git clone --filter=blob:none --sparse https://github.com/cross-rs/cross.git
cd cross
git sparse-checkout set docker
# 結果、cross/docker ディレクトリだけがチェックアウトされる

# cross-toolchains も同様に(全体を取得したい場合は sparse-checkout は不要です)
cd docker
git clone --filter=blob:none https://github.com/cross-rs/cross-toolchains.git

#作成しておいたdockerFileをコピーし、それをビルド
cp ../../DockerFile_glibc2.34.x86_64-unknown-linux-gnu ./

docker build -t glibc2.34.x86_64-unknown-linux-gnu -f DockerFile_glibc2.34.x86_64-unknown-linux-gnu .

ここで、すでにサポートが切れていたubuntu:21.10は、apt-get apdateやautoconfでエラーが発生し、
進まなくなってしまった。。。

その前の20.04LTS は使えるのだが、Glibcのバージョンが古すぎて合わず・・・
この方法は断念。