2018年11月07日

Ubuntu(x86_64)上でAArch64 Linuxターゲットのcompiler-rtライブラリをビルドする方法

LLVM/Clang/compiler-rt は 3 つがセットになって初めて動作します。LLVM/Clang はマルチアーキテクチャ(例:ARM/AArch64/X86)、マルチターゲット(例:arm-eabi、arm-linux-gnueabi、arm-linux-gnueabihf、aarch64-elf、aarch64-linux-gnu)のコード生成が可能なのですが、ライブラリの compiler-rt だけは、3 つを 1 度にビルドしようとした場合に、1 ターゲットぶんしかビルドできないという問題があります。

そこでこの記事では、先に Ubuntu Linux 上で AArch64 ターゲットのクロス LLVM/Clang コンパイラをビルドした後、それを使用して AArch64 Linux ターゲットの compiler-rt をビルドする手順を説明します。他のターゲットも同様の手順で可能と思われます。



混乱するので、まずは用語を整理します。Autotools でパッケージ化されている GCC/Binutils(Clang/LLVM に相当)には以下のような概念が存在し、configure 時に指定することができます。

build GCC をビルドする環境
host ビルドした GCC が動く環境(build と host が異なる場合はカナディアンクロスと呼ばれる。)
target GCC が生成するコードが動く環境(host と同じ場合はネイティブ、異なる場合はクロスと呼ばれる。)

また、libgcc(compiler-rt に相当)等の GCC 付属ライブラリも、自動的に target のものがビルドされます。(カナディアンクロスの場合は、ビルドした GCC が build で動作しないので、当然ライブラリはビルドできないので、build で動作するクロスコンパイラを最初にビルドしてライブラリを作る手順が増えますが、慣れればシンプルで迷うことはありません。)

しかし LLVM/Clang は本質的にクロスコンパイラなので(デフォルト target は存在しますが)、コードは生成できるがライブラリが無いという状況が生まれます。この性質は GCC よりも優れている所もあるのですが、複雑さを生み、全ての設定が正しくないとすぐにおかしなことになってしまうという難しさもあります。

cmake 自体はクロスビルドも考慮されていますが、LLVM/Clang の CMakeLists.txt の設定は、基本的には build = host = target を前提にしているように思えますし、実際公式で配布されているバイナリは全て host = target のパターン(ネイティブコンパイラ)だと思います。(Bare Metal や x86 以外の Linux ターゲットは、おそらく x86 の Linux 上でビルドされていると思うので、カナディアンクロスもできるのだとは思いますが。)

せっかくマルチアーキテクチャマルチターゲットサポートなのですから、GCC のように 1 ターゲット固定の専用コンパイラ(1 アーキテクチャの範囲で複数のターゲット用ライブラリを持つ multilib は可能ですが、やはり複雑になります)で、新たなターゲットが増えるたびに新規ビルドするというやり方ではもったいなく感じます。ライブラリだけビルドしてインストールできた方が、ビルド時の設定もシンプルになりますし、効率的ではないでしょうか。

そのため、これまでは、Windows 上で VisualStudio を使い(MSYS2 の GCC 7.3 にはどうもコード生成バグがあるようで、ビルドした QEMU や Clang が正常動作しません)、Windows 上で動作するクロスコンパイラだけをビルドし、compiler-rt を一緒に cmake でビルドすることを諦め、必要最小限の builtins ライブラリだけを CMakeList.txt を参考にしつつ自分で手書きした Makefile でビルド(これを自動的にやってくれるのが cmake です)していました。

しかしこの間、業務で AArch64 Linux のフルセットの compiler-rt が必要となり、その Makefile を全部手書きはとても無理となったので、改めていろいろ苦労して調べた成果が、今回の記事となります。(ライブラリが欲しいだけならば、公式で配布されている AArch64 Linux 向けのネイティブツールチェーンからコピーするという作戦もありますが、自前でビルドできる環境を整えないと改造ができないためです。)

非常に参考になったのは、以下の公式ドキュメントです。少なくともできる、ということはわかったので、とても助かりました。(できるのかできないのかすら当初は見当が付かなかった。)

How to Cross Compile Compiler-rt Builtins For Arm

当初は、Windows MSYS2 上で、AArch64 Linux の compiler-rt をビルドしようと試行錯誤したのですが、どうもさっぱり上手くいきません。そこで公式ドキュメントに従い Ubuntu 上で試行錯誤した所、なんとか成功することができました。予想ですが、おそらく「build」と「host」が同じ「Linux」なので、もろもろの cmake の設定が(たまたま?)上手く噛み合い、ビルドできている感触があります。(Windows 上で同じことを行おうとすると、その時点でコンパイラの設定等がどうも GCC や Clang ではなくデフォルト?の VisualStudio になってしまい、様々な所がおかしくなっている感じがします。膨大な変数をちゃんと指定すればおそらくできるのでしょうが……。)

前置きが長くなってしまいましたが、具体的な手順は、以下のようなシェルスクリプトを動かすだけです。ビルドは LLVM/Clang だけでは完結せず、Linux 向けの GCC ツールチェーンとセットの sysroot が必要です。今回は Linaro のツールを使用しました。

(0) 今回の環境

Ubuntu 18.04 x86_64

LLVM/Clang がビルドできる環境を apt-get で準備してください。

私の場合は、今回の記事だけなら無駄なものも多いと思いますが、開発用 Ubuntu 機には以下のようなパッケージを入れています。(Windows 用 GCC がビルドできる環境ができます。)
$ sudo apt-get install build-essential gitk mingw-w64 g++-mingw-w64-i686 autoconf autopoint flex bison gettext texinfo texlive dejagnu ruby zip libxml2-utils dblatex doxygen libncurses5-dev qemu-user-static groff zlib1g-dev autogen cmake
$ sudo apt-get build-dep mingw-w64

(1) 必要なファイルをダウンロード

今回はワーキングディレクトリに /home/kmc/test/libcompiler_rt を使用します。
そこに LLVM/Clang/compiler-rt の 7.0.0 のソースと、Linaro の AArch64 Linux クロスツールチェーンをダウンロードして展開します。ライブラリのビルドだけならばツールチェーンのみで可能ですが、テストのために sysroot もダウンロードします。
$ wget http://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz
$ tar xvf llvm-7.0.0.src.tar.xz
$ wget http://releases.llvm.org/7.0.0/cfe-7.0.0.src.tar.xz
$ tar xvf cfe-7.0.0.src.tar.xz
$ mv cfe-7.0.0.src llvm-7.0.0.src/tools/clang
$ wget http://releases.llvm.org/7.0.0/compiler-rt-7.0.0.src.tar.xz
$ tar xvf compiler-rt-7.0.0.src.tar.xz

$ wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
$ tar xvf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz

$ wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu.tar.xz
$ tar xvf sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu.tar.xz

(2) LLVM/Clang をビルド(compiler-rt はできない。)

以下のスクリプトを実行するとビルドディレクトリを掘ってビルドします。できた LLVM/Clang は ARM と AArch64 ターゲットをサポートし、デフォルトターゲットは aarch64-linux-gnu になります。(今回だけなら ARM は不要ですが、後々のことを考えて。)
#!/bin/sh
set -x -e

[ -z $LLVM_VERSION ] && LLVM_VERSION=7.0.0
[ -z $BUILD ] && BUILD=Release

ROOT=/home/kmc/test/libcompiler_rt
WORK=${ROOT}/${BUILD}-AArch64-${LLVM_VERSION}.obj.$$

mkdir ${WORK}
cd ${WORK}
mkdir build crosstools
cd build
cmake -G "Unix Makefiles" \
    ${ROOT}/llvm-${LLVM_VERSION}.src \
    -DCMAKE_INSTALL_PREFIX=../crosstools \
    -DCMAKE_BUILD_TYPE=${BUILD} \
    -DLLVM_TARGETS_TO_BUILD="AArch64;ARM" \
    -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-linux-gnu \
    -DLLVM_BUILD_EXAMPLES=OFF \
    -DLLVM_INCLUDE_EXAMPLES=OFF \
    -DLLVM_INCLUDE_TESTS=OFF \
    -DBUILD_SHARED_LIBS=OFF
time make -j8 > make.log 2>&1
make install
# copy FileCheck e.t.c. for testing.
cp bin/* ../crosstools/bin
できた $WORK/crosstools というディレクトリの中にツール一式がインストールされます。($WORK は PID で名付けられるのでビルドごとに名前が変わります。)カレントディレクトリにコピーか移動してください。

(3) compiler-rt のビルド

ここが今回のメインとなります。公式ドキュメントでは builtins のみビルドしていますが、試行錯誤して全ライブラリのビルドに成功しました。テストは、どうも builtins 以外はネイティブ環境以外を想定していないような印象です。なぜ C++ 時のオプションやリンク時のオプションを指定できないのかも謎です。
#!/bin/bash
set -x -e

# LLVM/Clang/compiler-rt must be same version.
[ -z $LLVM_VERSION ] && LLVM_VERSION=7.0.0
[ -z $BUILD ] && BUILD=Release

# for build

ROOT=/home/kmc/test/libcompiler_rt
SRCDIR="$ROOT/compiler-rt-${LLVM_VERSION}.src"
TOOLDIR="$ROOT/crosstools/bin"
export CC="$TOOLDIR/clang"
export CXX="$TOOLDIR/clang++"
export AR="$TOOLDIR/llvm-ar"
export NM="$TOOLDIR/llvm-nm"
export RANLIB="$TOOLDIR/llvm-ranlib"
export LLVM_CONFIG="$TOOLDIR/llvm-config"

# tool specific

TARGET=aarch64-linux-gnu
GCCDIR="$ROOT/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu"
GCC_VERSION=7.3.1
BUILD_SYSROOT="$GCCDIR/$TARGET/libc"

export COMPILER_PATH="$GCCDIR/bin/:$GCCDIR/libexec/gcc/$TARGET/$GCC_VERSION/"
export PATH=$COMPILER_PATH:$PATH

TARGET_CFLAGS=" --target=$TARGET --sysroot=${BUILD_SYSROOT} -B$GCCDIR/lib/gcc/$TARGET/$GCC_VERSION"
TARGET_CXXFLAGS="-I$GCCDIR/$TARGET/include/c++/$GCC_VERSION -I$GCCDIR/$TARGET/include/c++/$GCC_VERSION/$TARGET -I$GCCDIR/$TARGET/include/c++/$GCC_VERSION/backward $TARGET_CFLAGS"
TARGET_LDFLAGS="-L$GCCDIR/lib/gcc/$TARGET/$GCC_VERSION"

WORK=${ROOT}/${BUILD}-${TARGET}-libcompiler_rt-${LLVM_VERSION}.obj.$$

# for test

SYSROOT="$ROOT/sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu/"

# configure & make

mkdir ${WORK}
cd ${WORK}
mkdir build
cd build
cmake -G "Unix Makefiles" ${SRCDIR} \
    -DCMAKE_INSTALL_PREFIX=$TOOLDIR/../lib/clang/$LLVM_VERSION/ \
    -DCMAKE_BUILD_TYPE=$BUILD \
    -DCOMPILER_RT_BUILD_BUILTINS=ON \
    -DCOMPILER_RT_BUILD_SANITIZERS=ON \
    -DCOMPILER_RT_BUILD_XRAY=ON \
    -DCOMPILER_RT_BUILD_LIBFUZZER=ON \
    -DCOMPILER_RT_BUILD_PROFILE=ON \
    -DCMAKE_C_COMPILER=$CC \
    -DCMAKE_CXX_COMPILER=$CXX \
    -DCMAKE_AR=$AR \
    -DCMAKE_NM=$NM \
    -DCMAKE_RANLIB=$RANLIB \
    -DLLVM_CONFIG_PATH=$LLVM_CONFIG \
    -DCMAKE_C_COMPILER_TARGET=$TARGET \
    -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
    -DCMAKE_C_FLAGS="${TARGET_CFLAGS}" \
    -DCMAKE_CXX_FLAGS="${TARGET_CXXFLAGS}" \
    -DCMAKE_EXE_LINKER_FLAGS="${TARGET_LDFLAGS}" \
    \
    -DCOMPILER_RT_EMULATOR="qemu-aarch64 -L $SYSROOT" \
    -DCOMPILER_RT_INCLUDE_TESTS=ON \
    -DCOMPILER_RT_TEST_COMPILER=$CC \
    -DCOMPILER_RT_TEST_COMPILER_CFLAGS="${TARGET_CFLAGS}"

time make -j8 > make.log 2>&1
make install
make check-builtins
builtins ライブラリのテストは QEMU の Usermode emulation とツールチェーンの sysroot を使用して行っています。結果は以下のように 100% PASS したので、正しくビルドできていると思われます。(実際に raspi3 でも動作を確認しました。)
[100%] Running the Builtins tests
Testing Time: 2.91s
  Expected Passes    : 165
  Expected Failures  : 1
  Unsupported Tests  : 28
[100%] Built target check-builtins

これでできたライブラリ crosstools/lib/clang/7.0.0/ 以下を Windows に同様のディレクトリ構成でコピーしてきて使えば、とりあえず当面の用は足せます。

今後の課題

- 非 Linux 環境(Windows MSYS2 等)での同様のビルドは可能なのか?
- builtins 以外の、非ネイティブ環境でのテストは可能なのか?
(一応テストの実行自体はできるが、どうも途中でコンパイラオプションの設定等がおかしいようで、大量のエラーが出てしまいまともなテストにならなかった。)

kmckk at 15:04コメント(0)LLVM | 若槻 

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード