Linux上に各種クロスコンパイラ環境を構築する


# 初めに

最近、FPGAやCPUの勉強をしておりその過程でクロスコンパイラを導入する機会があったので、その手順などをまとめました。

本記事は、inaz2様の記事をベースにしております。
http://inaz2.hatenablog.com/entry/2015/12/01/204201

今回のクロスコンパイラ構築は、debian:jessieコンテナ内で実行しています。

# 各種依存関係のダウンロード

今回、クロスコンパイラを構築するうえで下記のパッケージを利用します。

- GCC
  - コンパイラー
- BINUTILS
  - オブジェクトファイルを取り扱うツール類(リンカ・アセンブラ等）を提供
- GMP
  - 任意精度算術演算ライブラリ
- MPFR
  - 任意精度の浮動小数点数演算ライブラリ
- MPC
  - 複素数演算ライブラリ


## ダウンロードスクリプト

今回ダウンロードするものが多いので、スクリプト化しています。
※ダウンロード先はリンク切れを起こす可能性があるので、404エラーでたらリンクを修正してください。
※バージョンの組み合わせによっては次ステップのビルド時にエラーでこける場合があります。

```bash

#!/bin/bash
# download.sh

set -e

BINUTILS_VERSION=binutils-2.25
GCC_VERSION=gcc-5.2.0
LINUX_KERNEL_VERSION=linux-3.16
GLIBC_VERSION=glibc-2.22
GMP_VERSION=gmp-6.1.2
MPFR_VERSION=mpfr-4.0.1
MPC_VERSION=mpc-1.1.0

wget -nc http://ftpmirror.gnu.org/binutils/${BINUTILS_VERSION}.tar.gz
wget -nc http://ftpmirror.gnu.org/gcc/${GCC_VERSION}/${GCC_VERSION}.tar.gz
wget -nc https://www.kernel.org/pub/linux/kernel/v3.x/$LINUX_KERNEL_VERSION.tar.xz
wget -nc http://ftpmirror.gnu.org/glibc/$GLIBC_VERSION.tar.xz
wget -nc ftp://ftp.gnu.org/gnu/gmp/${GMP_VERSION}.tar.xz
wget -nc https://www.mpfr.org/mpfr-current/${MPFR_VERSION}.tar.xz
wget -nc https://ftp.gnu.org/gnu/mpc/${MPC_VERSION}.tar.gz

for f in *.tar*; do
    bsdtar xfk $f
done

mv ${GMP_VERSION} ${GCC_VERSION}/gmp
mv ${MPFR_VERSION} ${GCC_VERSION}/mpfr
mv ${MPC_VERSION} ${GCC_VERSION}/mpc

```

gccフォルダ以下に、gmp mpfr mpcフォルダがあるとgccビルド時のconfigureでよしなにやってくれるっぽいです。


# クロスコンパイラのビルド

今回は、x86,arm,arm64,powerpc, mips向けのクロスコンパイラをビルドします。
かなりの時間がかかるので、忍耐が必要です。（筆者環境で数時間かかりました）

```bash

#!/bin/bash
# build.sh

set -e

PREFIX=/usr/local
PARALLEL_MAKE=-j4
CONFIGURATION_OPTIONS="--disable-multilib --disable-nls"

BINUTILS_VERSION=binutils-2.25
GCC_VERSION=gcc-5.2.0
LINUX_KERNEL_VERSION=linux-3.16
GLIBC_VERSION=glibc-2.22

build() {
    local TARGET="$1"
    local LINUX_ARCH="$2"

    # Step 1. Binutils
    mkdir -p build-binutils-$TARGET
    cd build-binutils-$TARGET
    ../$BINUTILS_VERSION/configure --prefix=$PREFIX --target=$TARGET $CONFIGURATION_OPTIONS
    make $PARALLEL_MAKE
    make install
    cd ..

    # Step 2. Linux Kernel Headers
    cd $LINUX_KERNEL_VERSION
    make ARCH=$LINUX_ARCH INSTALL_HDR_PATH=$PREFIX/$TARGET headers_install
    cd ..

    # Step 3. C/C++ Compilers
    mkdir -p build-gcc-$TARGET
    cd build-gcc-$TARGET
    ../$GCC_VERSION/configure --prefix=$PREFIX --target=$TARGET --enable-languages=c,c++ $CONFIGURATION_OPTIONS
    make $PARALLEL_MAKE gcc_cv_libc_provides_ssp=yes all-gcc
    make install-gcc
    cd ..

    # Step 4. Standard C Library Headers and Startup Files
    mkdir -p build-glibc-$TARGET
    cd build-glibc-$TARGET
    ../$GLIBC_VERSION/configure --prefix=$PREFIX/$TARGET --build=$MACHTYPE --host=$TARGET --target=$TARGET --with-headers=$PREFIX/$TARGET/include $CONFIGURATION_OPTIONS libc_cv_forced_unwind=yes
    make install-bootstrap-headers=yes install-headers
    make $PARALLEL_MAKE csu/subdir_lib
    install csu/crt1.o csu/crti.o csu/crtn.o $PREFIX/$TARGET/lib
    $TARGET-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $PREFIX/$TARGET/lib/libc.so
    touch $PREFIX/$TARGET/include/gnu/stubs.h
    cd ..

    # Step 5. Compiler Support Library
    cd build-gcc-$TARGET
    make $PARALLEL_MAKE all-target-libgcc
    make install-target-libgcc
    cd ..

    # Step 6. Standard C Library & the rest of Glibc
    cd build-glibc-$TARGET
    make $PARALLEL_MAKE
    make install
    cd ..

    # Step 7. Standard C++ Library & the rest of GCC
    cd build-gcc-$TARGET
    make $PARALLEL_MAKE all
    make install
    cd ..

    rm -rf build-binutils-$TARGET build-gcc-$TARGET build-glibc-$TARGET
}

build i686-linux-gnu x86
build arm-linux-gnueabi arm
build arm-linux-gnueabihf arm
build aarch64-linux-gnu arm64
build powerpc-linux-gnu powerpc
build powerpc64le-linux-gnu powerpc
build mips-linux-gnu mips
build mipsel-linux-gnu mips
build mips64el-linux-gnuabi64 mips
build alpha-linux-gnu alpha
build s390x-linux-gnu s390
build m68k-linux-gnu m68k

#build x86_64-linux-gnu x86
#build sparc-linux-gnu sparc
#build sparc64-linux-gnu sparc
#build cris-linux-gnu cris
#build sh4-linux-gnu sh

echo "Build Success!!"

```

# 動作テスト

今回はMIPS向けにビルドしたgccを試してみます。
下記の手順でgccを実行するとMIPS向けのアセンブリ出力ができるようになります。
（もちろんバイナリも吐くことができます）

```c
// main.c
int test(int a, int b) {
  return a + b;
}
```

```bash
$ mips-linux-gnu-gcc -S main.c
$ cat main.s
        .file   1 "main.c"
        .section .mdebug.abi32
        .previous
        .nan    legacy
        .module fp=32
        .module nooddspreg
        .abicalls
        .text
        .align  2
        .globl  test
        .set    nomips16
        .set    nomicromips
        .ent    test
        .type   test, @function
test:
        .frame  $fp,8,$31               # vars= 0, regs= 1/0, args= 0, gp= 0
        .mask   0x40000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp
        sw      $4,8($fp)
        sw      $5,12($fp)
        lw      $3,8($fp)
        lw      $2,12($fp)
        nop
        addu    $2,$3,$2
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        j       $31
        nop

        .set    macro
        .set    reorder
        .end    test
        .size   test, .-test
        .ident  "GCC: (GNU) 5.2.0"
```