GitHub ActionsではARM64ランナーも公開されつつありますが、ここでは gcc を使ったクロスコンパイルを説明します。この記事ではホスト*1のアーキテクチャを x86_64、ターゲット*2のアーキテクチャを arm64 としていますが、他のターゲットでも同様の手順となるでしょう。また、C言語を前提に書いていますが、他の言語でもライブラリをリンクする場合は参考になるんじゃないかなと思います。
aptリポジトリの準備
まずはターゲットとなるアーキテクチャをパッケージ管理システムに追加します。
sudo dpkg --add-architecture arm64
GitHub Actionsのubuntuランナーにはx86パッケージのリポジトリしか設定されていないので、ARMパッケージがあるaptリポジトリのURLを/etc/apt/sources.list.d/arm64.listに設定します。
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted
また、GitHub Actionsランナーの /etc/apt/sources.list はアーキテクチャを制限していないので、このままだと arm64 パッケージも探してしまって警告が出力されます。どのみちデフォルトのリポジトリに arm64 パッケージは用意されていないので、探さないよう arch= オプションを設定しておきます。
sudo sed -i -E '/^deb(-src)? ([^[])/s/ / [arch=amd64,i386] /' /etc/apt/sources.list
sources.list の各項目がどんな意味なのかは以下の記事が分かりやすいと思います。
コンパイラとライブラリのインストール
ここまで終われば、コンパイラと必要なライブラリをインストールしましょう。
sudo apt update sudo apt install -y gcc-aarch64-linux-gnu sudo apt install -y libsystemd-dev libsystemd-dev:arm64 # libsystemdをリンクしたい場合の例
このとき、 gcc では aarch64 の部分がターゲーットのアーキテクチャ名になります。また、リンクするライブラリはパッケージ名の後ろに :arm64 のようにアーキテクチャ名を追加します。
arm64とaarch64の関係
ここまでで、 arm64 や aarch64 といった名称を使いましたが、何が違うのでしょうか。
これらの名前は、aarch64 は命令セットの名前に、arm64 はARMプロセッサの64bitアーキテクチャに由来します。クロスコンパイルする状況においては結局どちらも64bit ARMを意味していますが、歴史的な事情によって使っている名称が異なります。
以下は各システムがどちらの表記を使っているかまとめた表です。せっかくなのでx86の表記も加えてみました。
システム | x86 | ARM |
---|---|---|
GCC | x86_64 | aarch64 |
Clang | x86_64 | aarch64 1 |
GNU | x86_64 | arm64 |
Debian/Ubuntu | amd64 | arm64 |
RHEL系 | x86_64 | aarch64 |
Plan 9 | amd64 | arm64 |
Go | amd64 | arm64 |
Windows | x64 2 | arm64 |
なので、gccパッケージのターゲット名は aarch64 となっているし、ライブラリのアーキテクチャ名はDebian/Ubuntuの命名に沿うので libsystemd:arm64 表記が使われているわけですね*3。
ソースコードをビルドする
ビルドするときはターゲット用の gcc を使えばいいだけです。 make を使っている場合は CC 変数にセットします。
make CC=aarch64-linux-gnu-gcc
ライブラリのリンク等は、ターゲット用の gcc がターゲット用のライブラリを探してくれるので、開発者が意識することはありません。
ワークフロー
ここまでのワークフローをまとめます。
steps: - name: Add an architecture to install packages run: | sudo dpkg --add-architecture arm64 sudo sed -i -E '/^deb(-src)? ([^[])/s/ / [arch=amd64,i386] /' /etc/apt/sources.list source /etc/lsb-release o="$(mktemp)" url='http://ports.ubuntu.com/ubuntu-ports' echo "deb [arch=arm64] $url $DISTRIB_CODENAME main restricted" >>"$o" echo "deb [arch=arm64] $url $DISTRIB_CODENAME-security main restricted" >>"$o" echo "deb [arch=arm64] $url $DISTRIB_CODENAME-updates main restricted" >>"$o" sudo install -m 644 "$o" /etc/apt/sources.list.d/arm64.list - name: Build sources run: | sudo apt update sudo apt install -y gcc-aarch64-linux-gnu sudo apt install -y libsystemd-dev libsystemd-dev:arm64 make CC=aarch64-linux-gnu-gcc
リポジトリの設定部分はlufia/workflows/.github.actions/setup-multiarchとして複合ワークフローにしておいたので、よければ使ってください。
steps: - uses: lufia/workflows/.github/actions/setup-multiarch@v0.5.0 with: arch: arm64
- AppleバックエンドのことをARM64と呼んでいたがAArch64に統合された↩
- x86-64 表記もあるが、x64 の方が多いと思う↩