各種アーキテクチャのクロスコンパイラ環境を構築する
Docker上に作成したDebian 8環境にてbinutils、gcc、glibcをソースコードからビルドし、さまざまなアーキテクチャのクロスコンパイラ環境を構築してみる。 なお、構築した環境は次のDocker imageとして公開してある(イメージサイズが2.8GBと大きいことに注意)。
環境
Ubuntu 14.04.3 LTS 64bit版、Docker 1.9.1
$ uname -a Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.3 LTS Release: 14.04 Codename: trusty $ sudo docker version Client: Version: 1.9.1 API version: 1.21 Go version: go1.4.2 Git commit: a34a1d5 Built: Fri Nov 20 13:12:04 UTC 2015 OS/Arch: linux/amd64 Server: Version: 1.9.1 API version: 1.21 Go version: go1.4.2 Git commit: a34a1d5 Built: Fri Nov 20 13:12:04 UTC 2015 OS/Arch: linux/amd64
クロスコンパイラをビルドしてみる
DockerでDebian 8のコンテナを起動し、ビルドに必要なパッケージをインストールする。
$ sudo docker run --name debian-crossbuild -i -t debian:jessie /bin/bash root@8ad669f3b939:/# apt-get update root@8ad669f3b939:/# apt-get upgrade root@8ad669f3b939:/# apt-get install build-essential texinfo gawk root@8ad669f3b939:/# apt-get install vim-tiny less wget
次のページを参考に、各ソースコードをダウンロードするシェルスクリプトを作成する。
ここでは、gccのコンパイルに必要なライブラリ群のソースコードも./contrib/download_prerequisites
を実行することで準備している。
#!/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 wget -nc http://ftpmirror.gnu.org/binutils/$BINUTILS_VERSION.tar.gz wget -nc http://ftpmirror.gnu.org/gcc/gcc-5.2.0/$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 for f in *.tar*; do tar xfk $f done cd $GCC_VERSION ./contrib/download_prerequisites
続けて、ビルドスクリプトを作成する。
PARALLEL_MAKE
はビルドするマシンのCPU数に合わせて調整する。
なお、コメントアウトしているアーキテクチャは途中でエラーが発生しビルドできなかった。
#!/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
ついでに、次のページで紹介されている、全アーキテクチャに対応したbinutilsのビルドスクリプトも作成する。
#!/bin/bash # build-binutils-all.sh set -e PREFIX=/usr/local PARALLEL_MAKE=-j4 CONFIGURATION_OPTIONS="--disable-multilib --disable-nls" BINUTILS_VERSION=binutils-2.25 mkdir -p build-binutils-all cd build-binutils-all ../$BINUTILS_VERSION/configure --prefix=$PREFIX --enable-targets=all --enable-64-bit-bfd --program-prefix=all- $CONFIGURATION_OPTIONS make $PARALLEL_MAKE make install cd .. rm -rf build-binutils-all
/tmp
に移動し、それぞれのスクリプトを実行する。
かなりの時間とディスク容量を要するので注意。
root@8ad669f3b939:/# cd /tmp root@8ad669f3b939:/tmp# bash download.sh root@8ad669f3b939:/tmp# nohup bash build.sh & root@8ad669f3b939:/tmp# nohup bash build-binutils-all.sh &
ビルドが完了すると、以下のコンパイラ群が生成されていることが確認できる。
root@8ad669f3b939:/tmp# ls /usr/local/bin aarch64-linux-gnu-addr2line alpha-linux-gnu-g++ arm-linux-gnueabihf-gcc-ranlib m68k-linux-gnu-ld.bfd mips64el-linux-gnuabi64-readelf powerpc64le-linux-gnu-addr2line aarch64-linux-gnu-ar alpha-linux-gnu-gcc arm-linux-gnueabihf-gcov m68k-linux-gnu-nm mips64el-linux-gnuabi64-size powerpc64le-linux-gnu-ar aarch64-linux-gnu-as alpha-linux-gnu-gcc-5.2.0 arm-linux-gnueabihf-gcov-tool m68k-linux-gnu-objcopy mips64el-linux-gnuabi64-strings powerpc64le-linux-gnu-as aarch64-linux-gnu-c++ alpha-linux-gnu-gcc-ar arm-linux-gnueabihf-gprof m68k-linux-gnu-objdump mips64el-linux-gnuabi64-strip powerpc64le-linux-gnu-c++ aarch64-linux-gnu-c++filt alpha-linux-gnu-gcc-nm arm-linux-gnueabihf-ld m68k-linux-gnu-ranlib mipsel-linux-gnu-addr2line powerpc64le-linux-gnu-c++filt aarch64-linux-gnu-cpp alpha-linux-gnu-gcc-ranlib arm-linux-gnueabihf-ld.bfd m68k-linux-gnu-readelf mipsel-linux-gnu-ar powerpc64le-linux-gnu-cpp aarch64-linux-gnu-elfedit alpha-linux-gnu-gcov arm-linux-gnueabihf-nm m68k-linux-gnu-size mipsel-linux-gnu-as powerpc64le-linux-gnu-elfedit aarch64-linux-gnu-g++ alpha-linux-gnu-gcov-tool arm-linux-gnueabihf-objcopy m68k-linux-gnu-strings mipsel-linux-gnu-c++ powerpc64le-linux-gnu-embedspu aarch64-linux-gnu-gcc alpha-linux-gnu-gprof arm-linux-gnueabihf-objdump m68k-linux-gnu-strip mipsel-linux-gnu-c++filt powerpc64le-linux-gnu-g++ aarch64-linux-gnu-gcc-5.2.0 alpha-linux-gnu-ld arm-linux-gnueabihf-ranlib mips-linux-gnu-addr2line mipsel-linux-gnu-cpp powerpc64le-linux-gnu-gcc aarch64-linux-gnu-gcc-ar alpha-linux-gnu-ld.bfd arm-linux-gnueabihf-readelf mips-linux-gnu-ar mipsel-linux-gnu-elfedit powerpc64le-linux-gnu-gcc-5.2.0 aarch64-linux-gnu-gcc-nm alpha-linux-gnu-nm arm-linux-gnueabihf-size mips-linux-gnu-as mipsel-linux-gnu-g++ powerpc64le-linux-gnu-gcc-ar aarch64-linux-gnu-gcc-ranlib alpha-linux-gnu-objcopy arm-linux-gnueabihf-strings mips-linux-gnu-c++ mipsel-linux-gnu-gcc powerpc64le-linux-gnu-gcc-nm aarch64-linux-gnu-gcov alpha-linux-gnu-objdump arm-linux-gnueabihf-strip mips-linux-gnu-c++filt mipsel-linux-gnu-gcc-5.2.0 powerpc64le-linux-gnu-gcc-ranlib aarch64-linux-gnu-gcov-tool alpha-linux-gnu-ranlib i686-linux-gnu-addr2line mips-linux-gnu-cpp mipsel-linux-gnu-gcc-ar powerpc64le-linux-gnu-gcov aarch64-linux-gnu-gprof alpha-linux-gnu-readelf i686-linux-gnu-ar mips-linux-gnu-elfedit mipsel-linux-gnu-gcc-nm powerpc64le-linux-gnu-gcov-tool aarch64-linux-gnu-ld alpha-linux-gnu-size i686-linux-gnu-as mips-linux-gnu-g++ mipsel-linux-gnu-gcc-ranlib powerpc64le-linux-gnu-gprof aarch64-linux-gnu-ld.bfd alpha-linux-gnu-strings i686-linux-gnu-c++ mips-linux-gnu-gcc mipsel-linux-gnu-gcov powerpc64le-linux-gnu-ld aarch64-linux-gnu-nm alpha-linux-gnu-strip i686-linux-gnu-c++filt mips-linux-gnu-gcc-5.2.0 mipsel-linux-gnu-gcov-tool powerpc64le-linux-gnu-ld.bfd aarch64-linux-gnu-objcopy arm-linux-gnueabi-addr2line i686-linux-gnu-cpp mips-linux-gnu-gcc-ar mipsel-linux-gnu-gprof powerpc64le-linux-gnu-nm aarch64-linux-gnu-objdump arm-linux-gnueabi-ar i686-linux-gnu-elfedit mips-linux-gnu-gcc-nm mipsel-linux-gnu-ld powerpc64le-linux-gnu-objcopy aarch64-linux-gnu-ranlib arm-linux-gnueabi-as i686-linux-gnu-g++ mips-linux-gnu-gcc-ranlib mipsel-linux-gnu-ld.bfd powerpc64le-linux-gnu-objdump aarch64-linux-gnu-readelf arm-linux-gnueabi-c++ i686-linux-gnu-gcc mips-linux-gnu-gcov mipsel-linux-gnu-nm powerpc64le-linux-gnu-ranlib aarch64-linux-gnu-size arm-linux-gnueabi-c++filt i686-linux-gnu-gcc-5.2.0 mips-linux-gnu-gcov-tool mipsel-linux-gnu-objcopy powerpc64le-linux-gnu-readelf aarch64-linux-gnu-strings arm-linux-gnueabi-cpp i686-linux-gnu-gcc-ar mips-linux-gnu-gprof mipsel-linux-gnu-objdump powerpc64le-linux-gnu-size aarch64-linux-gnu-strip arm-linux-gnueabi-elfedit i686-linux-gnu-gcc-nm mips-linux-gnu-ld mipsel-linux-gnu-ranlib powerpc64le-linux-gnu-strings all-addr2line arm-linux-gnueabi-g++ i686-linux-gnu-gcc-ranlib mips-linux-gnu-ld.bfd mipsel-linux-gnu-readelf powerpc64le-linux-gnu-strip all-ar arm-linux-gnueabi-gcc i686-linux-gnu-gcov mips-linux-gnu-nm mipsel-linux-gnu-size s390x-linux-gnu-addr2line all-as arm-linux-gnueabi-gcc-5.2.0 i686-linux-gnu-gcov-tool mips-linux-gnu-objcopy mipsel-linux-gnu-strings s390x-linux-gnu-ar all-c++filt arm-linux-gnueabi-gcc-ar i686-linux-gnu-gprof mips-linux-gnu-objdump mipsel-linux-gnu-strip s390x-linux-gnu-as all-coffdump arm-linux-gnueabi-gcc-nm i686-linux-gnu-ld mips-linux-gnu-ranlib powerpc-linux-gnu-addr2line s390x-linux-gnu-c++ all-dlltool arm-linux-gnueabi-gcc-ranlib i686-linux-gnu-ld.bfd mips-linux-gnu-readelf powerpc-linux-gnu-ar s390x-linux-gnu-c++filt all-dllwrap arm-linux-gnueabi-gcov i686-linux-gnu-nm mips-linux-gnu-size powerpc-linux-gnu-as s390x-linux-gnu-cpp all-elfedit arm-linux-gnueabi-gcov-tool i686-linux-gnu-objcopy mips-linux-gnu-strings powerpc-linux-gnu-c++ s390x-linux-gnu-elfedit all-gprof arm-linux-gnueabi-gprof i686-linux-gnu-objdump mips-linux-gnu-strip powerpc-linux-gnu-c++filt s390x-linux-gnu-g++ all-ld arm-linux-gnueabi-ld i686-linux-gnu-ranlib mips64el-linux-gnuabi64-addr2line powerpc-linux-gnu-cpp s390x-linux-gnu-gcc all-ld.bfd arm-linux-gnueabi-ld.bfd i686-linux-gnu-readelf mips64el-linux-gnuabi64-ar powerpc-linux-gnu-elfedit s390x-linux-gnu-gcc-5.2.0 all-nlmconv arm-linux-gnueabi-nm i686-linux-gnu-size mips64el-linux-gnuabi64-as powerpc-linux-gnu-embedspu s390x-linux-gnu-gcc-ar all-nm arm-linux-gnueabi-objcopy i686-linux-gnu-strings mips64el-linux-gnuabi64-c++ powerpc-linux-gnu-g++ s390x-linux-gnu-gcc-nm all-objcopy arm-linux-gnueabi-objdump i686-linux-gnu-strip mips64el-linux-gnuabi64-c++filt powerpc-linux-gnu-gcc s390x-linux-gnu-gcc-ranlib all-objdump arm-linux-gnueabi-ranlib m68k-linux-gnu-addr2line mips64el-linux-gnuabi64-cpp powerpc-linux-gnu-gcc-5.2.0 s390x-linux-gnu-gcov all-ranlib arm-linux-gnueabi-readelf m68k-linux-gnu-ar mips64el-linux-gnuabi64-elfedit powerpc-linux-gnu-gcc-ar s390x-linux-gnu-gcov-tool all-readelf arm-linux-gnueabi-size m68k-linux-gnu-as mips64el-linux-gnuabi64-g++ powerpc-linux-gnu-gcc-nm s390x-linux-gnu-gprof all-size arm-linux-gnueabi-strings m68k-linux-gnu-c++ mips64el-linux-gnuabi64-gcc powerpc-linux-gnu-gcc-ranlib s390x-linux-gnu-ld all-srconv arm-linux-gnueabi-strip m68k-linux-gnu-c++filt mips64el-linux-gnuabi64-gcc-5.2.0 powerpc-linux-gnu-gcov s390x-linux-gnu-ld.bfd all-strings arm-linux-gnueabihf-addr2line m68k-linux-gnu-cpp mips64el-linux-gnuabi64-gcc-ar powerpc-linux-gnu-gcov-tool s390x-linux-gnu-nm all-strip arm-linux-gnueabihf-ar m68k-linux-gnu-elfedit mips64el-linux-gnuabi64-gcc-nm powerpc-linux-gnu-gprof s390x-linux-gnu-objcopy all-sysdump arm-linux-gnueabihf-as m68k-linux-gnu-g++ mips64el-linux-gnuabi64-gcc-ranlib powerpc-linux-gnu-ld s390x-linux-gnu-objdump all-windmc arm-linux-gnueabihf-c++ m68k-linux-gnu-gcc mips64el-linux-gnuabi64-gcov powerpc-linux-gnu-ld.bfd s390x-linux-gnu-ranlib all-windres arm-linux-gnueabihf-c++filt m68k-linux-gnu-gcc-5.2.0 mips64el-linux-gnuabi64-gcov-tool powerpc-linux-gnu-nm s390x-linux-gnu-readelf alpha-linux-gnu-addr2line arm-linux-gnueabihf-cpp m68k-linux-gnu-gcc-ar mips64el-linux-gnuabi64-gprof powerpc-linux-gnu-objcopy s390x-linux-gnu-size alpha-linux-gnu-ar arm-linux-gnueabihf-elfedit m68k-linux-gnu-gcc-nm mips64el-linux-gnuabi64-ld powerpc-linux-gnu-objdump s390x-linux-gnu-strings alpha-linux-gnu-as arm-linux-gnueabihf-g++ m68k-linux-gnu-gcc-ranlib mips64el-linux-gnuabi64-ld.bfd powerpc-linux-gnu-ranlib s390x-linux-gnu-strip alpha-linux-gnu-c++ arm-linux-gnueabihf-gcc m68k-linux-gnu-gcov mips64el-linux-gnuabi64-nm powerpc-linux-gnu-readelf alpha-linux-gnu-c++filt arm-linux-gnueabihf-gcc-5.2.0 m68k-linux-gnu-gcov-tool mips64el-linux-gnuabi64-objcopy powerpc-linux-gnu-size alpha-linux-gnu-cpp arm-linux-gnueabihf-gcc-ar m68k-linux-gnu-gprof mips64el-linux-gnuabi64-objdump powerpc-linux-gnu-strings alpha-linux-gnu-elfedit arm-linux-gnueabihf-gcc-nm m68k-linux-gnu-ld mips64el-linux-gnuabi64-ranlib powerpc-linux-gnu-strip
ユーザモードQEMUを使って実行してみる
各アーキテクチャをエミュレーション実行するために、qemu-user-staticパッケージをインストールする。 また、合わせてよく使うパッケージもインストールしておく。
root@8ad669f3b939:/tmp# apt-get install qemu-user-static root@8ad669f3b939:/tmp# apt-get install man file
ここで、次のようなHello worldコードを用意する。
/* hello.c */ #include <stdio.h> int main() { printf("Hello, world!\n"); return 0; }
例として、MIPS用の実行ファイルをコンパイルし、ユーザモードQEMUで実行してみると次のようになる。 さらに、全アーキテクチャ対応のobjdumpでディスアセンブルした結果も確認してみる。
root@8ad669f3b939:/tmp# mips-linux-gnu-gcc hello.c -o hello-mips root@8ad669f3b939:/tmp# qemu-mips-static -L /usr/local/mips-linux-gnu/ ./hello-mips Hello, world! root@8ad669f3b939:/tmp# all-objdump -d ./hello-mips | head ./hello-mips: file format elf32-bigmips Disassembly of section .init: 004004c8 <_init>: 4004c8: 3c1c0002 lui gp,0x2 4004cc: 279c84e8 addiu gp,gp,-31512 4004d0: 0399e021 addu gp,gp,t9
実行結果とディスアセンブル結果から、MIPS用の実行ファイルがコンパイルできていることがわかる。