ルギア君の戯言

雑多な記事。

ARM のクロスコンパイラをビルドする

Parallella (16-core) が面倒な方法を使わなくても日本でも買えるようになってたので頼んでみたのだが、発送が 9 月になるってどういうこと?

来なかったりして。まあいいや。

別に本当はこんなことはしなくても良いのです (Adapteva で配布している Ubuntu の中に開発ツールは一式揃っているため)。でも、Momonga でクロスコンパイルできたらいいかなと思ってメモ。

Rasberry Pi にも応用できると思いますが、詳しいことはわかりません。

メタ情報

項目 内容
インストール先 /opt/parallella
ARM SYSROOT (Little) /opt/parallella/arm-lemomonga-linux-gnueabihf
ARM SYSROOT (Big) /opt/parallella/arm-bemomonga-linux-gnueabihf
ビルドディレクトリ ~/Build

今は Big は使わないけども。ARM だと Little のほうが速いのかな。/opt/parallella 以下は手を入れるので自分で書き換えられるようにしておきます。

ソースの準備

用意するソースは、binutils, gcc, cloog, isl, mpfr, mpc, gmp, glibc と、Parallella の Linux カーネルのソースの 9 個。cloog と isl はなくても良いが、その場合 gcc での最適化に少し影響がある (と思われる)。

$ cd
$ mkdir Build/src
$ cd Build/src
$ wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.23.2.tar.bz2
$ wget ftp://ftp.gnu.org/gnu/gcc/gcc-4.9.0/gcc-4.9.0.tar.bz2
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.12.2.tar.bz2
$ wget ftp://ftp.gnu.org/gnu/mpfr/mpfr-3.1.2.tar.xz
$ wget ftp://ftp.gnu.org/gnu/mpc/mpc-1.0.2.tar.gz
$ wget ftp://ftp.gnu.org/gnu/gmp/gmp-5.1.3.tar.xz
$ wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.19.tar.xz
$ cd ..
$ tar jxvf src/binutils-2.23.2.tar.bz2
$ tar jxvf src/gcc-4.9.0.tar.bz2
   (省略)
$ tar Jxvf src/glibc-2.19.tar.xz
$ git clone https://github.com/parallella/parallella-linux-adi.git

あとからビルドするのは面倒なので、gcc で必要なライブラリをすべて中へ放り込む。

$ cd gcc-4.9.0
$ cp -R ../cloog-0.18.1 cloog
$ cp -R ../gmp-5.1.3 gmp
$ cp -R ../mpfr-3.1.2 mpfr
$ cp -R ../mpc-1.0.2 mpc
$ cp -R ../isl-0.12.2 isl

ネイティブ GCC のビルド

現時点の development では 4.6.4 で、やや古いので、新しいバージョンをビルドしてインストールします。

$ pushd gcc-4.9.0
$ mkdir x86_64-momonga-linux-gnu
$ cd x86_64-momonga-linux-gnu
$ ../configure --prefix=/opt/parallella
$ make
$ make install
$ popd
$ export PATH=/opt/parallella/bin:$PATH
$ export LD_LIBRARY_PATH=/opt/parallella/lib64:$LD_LIBRARY_PATH

(32bit の場合は /opt/parallella/lib64 ではなく /opt/parallella/lib)

ちなみに、このままビルドすると、gcj もビルドしてしまいます。基本的に使うことはないと思いますので、

--enable-languages=c,c++,fortran,lto,objc

と除いてもよいでしょう。ちなみに、gcj をビルドするには gtk や jack などが必要です (64bit かつ --disable-multilib を指定していない場合はこれらのライブラリの 32bit 版も必要です)。更にいうと以下のビルドでは fortran も使いません。

binutils のビルド

まずはネイティブ版から。

$ pushd binutils-2.23.2
$ mkdir x86_64-momonga-linux-gnu
$ cd x86_64-momonga-linux-gnu
$ ../configure \
>   --prefix=/opt/parallella \
>   --disable-werror
$ make
$ make install

次に ARM 用。

$ cd ..
$ mkdir arm-lemomonga-linux-gnueabihf
$ cd arm-lemomonga-linux-gnueabihf
$ ../configure \
>   --prefix=/opt/parallella \
>   --disable-werror \
>   --with-sysroot=/opt/parallella/arm-lemomonga-linux-gnueabihf \
>   --target=arm-lemomonga-linux-gnueabihf
$ make
$ make install

UsrMove をしておきます。include は UsrMove には含まれていませんが、クロスコンパイラはここしか検索しないので、これもリンクを作っておきます。

なぜか glibc の一部のファイルが lib64 以下にインストールされていたので、その回避も。

$ pushd /opt/parallella/arm-lemomonga-linux-gnueabihf
$ mkdir usr
$ mv bin lib usr
$ ln -s usr/bin bin
$ ln -s usr/lib lib
$ ln -s usr/lib64 lib64
$ ln -s usr/sbin sbin
$ ln -s usr/include include
$ cd usr
$ ln -s lib lib64
$ popd
$ popd

カーネルヘッダのインストール

$ pushd parallella-linux-adi
$ make mrproper
$ make ARCH=arm parallella_defconfig
$ make ARCH=arm headers_check
$ make ARCH=arm INSTALL_HDR_PATH=/opt/parallella/arm-lemomonga-linux-gnueabihf/usr headers_install
$ popd

C ヘッダのインストール

といってもまだコンパイラがないので、ダミーでインストールします。

$ cd glibc-2.19
$ mkdir install-headers
$ cd install-headers
$ echo "libc_cv_forced_unwind=yes" > config.cache
$ echo "libc_cv_c_cleanup=yes" >> config.cache
$ ../configure \
>    --prefix=/opt/parallella/arm-lemomonga-linux-gnueabihf/usr \
>    --with-headers=/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/include \
>    --config-cache
$ make -k cross_compiling=yes install-headers
$ cp ../include/gnu/stubs.h /opt/parallella/arm-lemomonga-linux-gnueabihf/usr/include/gnu

gcc のビルド (1 回目)

まずはスレッドと共有ライブラリを無効化し、C だけビルドします。Parallella の Zynq 7010 (Cortex-A9) には neon が付いているようなので、neon-vfpv4 でビルドしちゃいます。なお、汎用的には neon ではないほうが良いようです (References 参照)。

$ pushd gcc-4.9.0
$ mkdir arm-lemomonga-linux-gnueabihf
$ cd arm-lemomonga-linux-gnueabihf
$ ../configure \
>    --prefix=/opt/parallella \
>    --disable-werror \
>    --target=arm-lemomonga-linux-gnueabihf \
>    --with-sysroot=/opt/parallella/arm-lemomonga-linux-gnueabihf \
>    --enable-languages=c \
>    --disable-threads \
>    --disable-shared \
>    --disable-libssp \
>    --enable-__cxa_atexit \
>    --disable-libmudflap \
>    --disable-libgomp \
>    --disable-nls \
>    --disable-libstdcxx \
>    --disable-libatomic \
>    --disable-libquadmath \
>    --disable-cloog \
>    --without-headers \
>    --with-float=hard \
>    --with-fpu=neon-vfpv4 \
>    --with-mode=thumb \
>    --with-arch=armv7-a
$ make
$ make install
$ popd

glibc のビルド (1回目)

さっきインストールしたダミーのヘッダはすべて上書きされます。config.cache の強制はなくても良いかもしれない。 次の libgcc のビルド中、libc.so.6 のパスに SYROOT (/opt/parallella/arm-lemomonga-gnueabihf) が付かないので、まずは SYSROOT のパス付きでインストールします。

$ pushd glibc-2.19
$ mkdir arm-lemomonga-linux-gnueabihf
$ cd arm-lemomonga-linux-gnueabihf
$ echo "libc_cv_forced_unwind=yes" > config.cache
$ echo "libc_cv_c_cleanup=yes" >> config.cache
$ ../configure \
>    --disable-werror \
>    --build=x86_64-momonga-linux-gnu \
>    --host=arm-lemomonga-linux-gnueabihf \
>    --prefix=/opt/parallella/arm-lemomonga-linux-gnueabihf/usr \
>    --disable-multilib \
>    --with-fp \
>    --disable-sjlj-exceptions \
>    --enable-threads=posix \
>    --disable-nscd \
>    --config-cache
$ make -k install-headers cross_compiling=yes
$ make
$ make install
$ popd

gcc のビルド (2 回目)

$ pushd gcc-4.9.0
$ mkdir arm-lemomonga-linux-gnueabihf-r2
$ cd arm-lemomonga-linux-gnueabihf-r2
$ ../configure \
>    --prefix=/opt/parallella \
>    --disable-werror \
>    --target=arm-lemomonga-linux-gnueabihf \
>    --with-sysroot=/opt/parallella/arm-lemomonga-linux-gnueabihf \
>    --enable-languages=c,c++,fortran,lto,objc,obj-c++ \
>    --enable-__cxa_atexit \
>    --with-float=hard \
>    --with-fpu=neon-vfpv4 \
>    --with-mode=thumb \
>    --with-arch=armv7-a \
>    --disable-multilib
$ make
$ make install
$ popd

glibc のビルド (2回目)

普段のコンパイルではライブラリを SYSROOT 付きで検索するので prefix から SYSROOT をとってビルドし直します。gcc のバグな気もしなくもないが。

$ pushd glibc-2.19
$ mkdir arm-lemomonga-linux-gnueabihf-r2
$ cd arm-lemomonga-linux-gnueabihf-r2
$ echo "libc_cv_forced_unwind=yes" > config.cache
$ echo "libc_cv_c_cleanup=yes" >> config.cache
$ ../configure \
>    --disable-werror \
>    --build=x86_64-momonga-linux-gnu \
>    --host=arm-lemomonga-linux-gnueabihf \
>    --prefix=/usr \
>    --disable-multilib \
>    --with-fp \
>    --disable-sjlj-exceptions \
>    --enable-threads=posix \
>    --disable-nscd \
>    --config-cache
$ make
$ make install install_root=/opt/parallella/arm-lemomonga-linux-gnueabihf
$ popd

テスト

[lunastra@teostra sandbox]% cat a.c                                     [12:13]
#include <stdio.h>

float b(float);

int main()
{
  printf("Hello, World, %f\n", b(2.2));
  return 0;
}
[lunastra@teostra sandbox]% cat b.c                                     [12:16]
float b(float u)
{
  return u * 1.2;
}
[lunastra@teostra sandbox]% arm-lemomonga-linux-gnueabihf-gcc --verbose a.c b.c
組み込み spec を使用しています。
COLLECT_GCC=arm-lemomonga-linux-gnueabihf-gcc
COLLECT_LTO_WRAPPER=/opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/lto-wrapper
ターゲット: arm-lemomonga-linux-gnueabihf
configure 設定: ../configure --prefix=/opt/parallella --disable-werror 
--target=arm-lemomonga-linux-gnueabihf 
--with-sysroot=/opt/parallella/arm-lemomonga-linux-gnueabihf 
--enable-languages=c,c++,fortran,lto,objc,obj-c++ 
--enable-__cxa_atexit --with-float=hard 
--with-fpu=neon-vfpv4 --with-mode=thumb 
--with-arch=armv7-a --disable-multilib
スレッドモデル: posix
gcc バージョン 4.9.0 (GCC) 
COLLECT_GCC_OPTIONS='-v' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=neon-vfpv4' '-mthumb' '-mtls-dialect=gnu'
 /opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/cc1 -quiet -v a.c -quiet -dumpbase a.c -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 -mthumb -mtls-dialect=gnu -auxbase a -version -o /tmp/ccpd0RRc.s
GNU C (GCC) version 4.9.0 (arm-lemomonga-linux-gnueabihf)
        compiled by GNU C version 4.9.0, GMP version 5.1.3, MPFR version 3.1.2, MPC version 1.0.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
存在しないディレクトリ "/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/local/include" を無視します
重複したディレクトリ "/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/include" を無視します
#include "..." の探索はここから始まります:
#include <...> の探索はここから始まります:
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/include
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/include-fixed
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/include
探索リストの終わりです。
GNU C (GCC) version 4.9.0 (arm-lemomonga-linux-gnueabihf)
        compiled by GNU C version 4.9.0, GMP version 5.1.3, MPFR version 3.1.2, MPC version 1.0.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 28eb21db3a3ac98e105c2e964d186c02
COLLECT_GCC_OPTIONS='-v' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=neon-vfpv4' '-mthumb' '-mtls-dialect=gnu'
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/bin/as -v -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 -meabi=5 -o /tmp/ccxP6G8x.o /tmp/ccpd0RRc.s
GNU アセンブラ バージョン 2.23.2 (arm-lemomonga-linux-gnueabihf)、BFD バージョン (GNU Binutils) 2.23.2 を使用
COLLECT_GCC_OPTIONS='-v' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=neon-vfpv4' '-mthumb' '-mtls-dialect=gnu'
 /opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/cc1 -quiet -v b.c -quiet -dumpbase b.c -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 -mthumb -mtls-dialect=gnu -auxbase b -version -o /tmp/ccpd0RRc.s
GNU C (GCC) version 4.9.0 (arm-lemomonga-linux-gnueabihf)
        compiled by GNU C version 4.9.0, GMP version 5.1.3, MPFR version 3.1.2, MPC version 1.0.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
存在しないディレクトリ "/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/local/include" を無視します
重複したディレクトリ "/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/include" を無視します
#include "..." の探索はここから始まります:
#include <...> の探索はここから始まります:
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/include
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/include-fixed
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/include
探索リストの終わりです。
GNU C (GCC) version 4.9.0 (arm-lemomonga-linux-gnueabihf)
        compiled by GNU C version 4.9.0, GMP version 5.1.3, MPFR version 3.1.2, MPC version 1.0.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 28eb21db3a3ac98e105c2e964d186c02
COLLECT_GCC_OPTIONS='-v' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=neon-vfpv4' '-mthumb' '-mtls-dialect=gnu'
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/bin/as -v -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 -meabi=5 -o /tmp/cckiRjvT.o /tmp/ccpd0RRc.s
GNU アセンブラ バージョン 2.23.2 (arm-lemomonga-linux-gnueabihf)、BFD バージョン (GNU Binutils) 2.23.2 を使用
COMPILER_PATH=/opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/:/opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/:/opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/:/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/:/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/:/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/bin/
LIBRARY_PATH=/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/:/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/lib/:/opt/parallella/arm-lemomonga-linux-gnueabihf/lib/:/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=neon-vfpv4' '-mthumb' '-mtls-dialect=gnu'
 /opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/collect2
 -plugin /opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/liblto_plugin.so
 -plugin-opt=/opt/parallella/libexec/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/lto-wrapper
 -plugin-opt=-fresolution=/tmp/ccu376Te.res -plugin-opt=-pass-through=-lgcc
 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc
 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s
 --sysroot=/opt/parallella/arm-lemomonga-linux-gnueabihf
 --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X
 -m armelf_linux_eabi /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/lib/crt1.o
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/lib/crti.o
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/crtbegin.o
 -L/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0
 -L/opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/lib
 -L/opt/parallella/arm-lemomonga-linux-gnueabihf/lib
 -L/opt/parallella/arm-lemomonga-linux-gnueabihf/usr/lib
 /tmp/ccxP6G8x.o /tmp/cckiRjvT.o
 -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed
 -lgcc_s --no-as-needed /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/crtend.o
 /opt/parallella/lib/gcc/arm-lemomonga-linux-gnueabihf/4.9.0/../../../../arm-lemomonga-linux-gnueabihf/lib/crtn.o
[lunastra@teostra sandbox]% arm-lemomonga-linux-gnueabihf-objdump -d a.out     

a.out:     ファイル形式 elf32-littlearm

(略)

セクション .text の逆アセンブル:
(略)

000083b4 <main>:
    83b4:       b580            push    {r7, lr}
    83b6:       af00            add     r7, sp, #0
    83b8:       ed9f 0a09       vldr    s0, [pc, #36]   ; 83e0 <main+0x2c>
    83bc:       f000 f814       bl      83e8 <b>
    83c0:       eef0 7a40       vmov.f32        s15, s0
    83c4:       eef7 0ae7       vcvt.f64.f32    d16, s15
    83c8:       f248 4070       movw    r0, #33904      ; 0x8470
    83cc:       f2c0 0000       movt    r0, #0
    83d0:       ec53 2b30       vmov    r2, r3, d16
    83d4:       f7ff ef64       blx     82a0 <_init+0x20>
    83d8:       2300            movs    r3, #0
    83da:       4618            mov     r0, r3
    83dc:       bd80            pop     {r7, pc}
    83de:       bf00            nop
    83e0:       400ccccd        .word   0x400ccccd
    83e4:       00000000        .word   0x00000000

000083e8 <b>:
    83e8:       b480            push    {r7}
    83ea:       b083            sub     sp, #12
    83ec:       af00            add     r7, sp, #0
    83ee:       ed87 0a01       vstr    s0, [r7, #4]
    83f2:       edd7 7a01       vldr    s15, [r7, #4]
    83f6:       eef7 1ae7       vcvt.f64.f32    d17, s15
    83fa:       eddf 0b07       vldr    d16, [pc, #28]  ; 8418 <b+0x30>
    83fe:       ee61 0ba0       vmul.f64        d16, d17, d16
    8402:       eef7 7be0       vcvt.f32.f64    s15, d16
    8406:       eeb0 0a67       vmov.f32        s0, s15
    840a:       370c            adds    r7, #12
    840c:       46bd            mov     sp, r7
    840e:       f85d 7b04       ldr.w   r7, [sp], #4
    8412:       4770            bx      lr
    8414:       f3af 8000       nop.w
    8418:       33333333        .word   0x33333333
    841c:       3ff33333        .word   0x3ff33333

まとめ

gmp や mpfr などを shared にしたかったけど、パス。

References