まぁタイトルの通りなのだけれども、macOS で LLVM じゃない普通の gcc をビルドした後で他のプロセッサ向けのクロスコンパイラ gcc をビルドする方法についてメモしておく. 今回は i386 の Linux 向けのクロスコンパイラをビルドすることにする.

まずは作業用のディレクトリを作成する. 今回はホームディレクトリ中に cross というディレクトリを作り、そこで作業することにした.

$ mkdir ~/cross
$ cd ~/cross

さて、最初からいきなりクロスコンパイラをビルドできるわけではない. macOS 標準の gcc は実体は clang であるが、クロスコンパイラのビルドにはネイティブの gcc が必要となるためまずはホスト環境のためのネイティブ gcc を用意する必要がある.

今回は gcc 7.3.0 を使うことにするので、このネイティブ gcc は N-gcc-7.3.0 というディレクトリに配置することにする.

$ mkdir N-gcc-7.3.0
$ cd N-gcc-7.3.0

はじめに、GNU の公式 から必要となるソフトウェア郡を FTP 経由でダウンロードする必要がある. GNU の FTP は国ごとにたくさんのミラーが存在しているが、今回は JAIST の FTP ミラー を利用することにした. gcc のビルドには以下のソフトウェアのソースが必要である.

  • GNU Compiler Collection (gcc): tar.gz
  • GNU Multi-Precision Library (gmp): tar.bz2
  • GNU MPFR (multiple-precision floating point computations with correct rounding) Libary (mpfr): tar.gz
  • GNU MPC (mpc): tar.gz
  • GNU libiconv (libiconv): tar.gz

面倒なので、以下のようなシェルスクリプトを用意してまとめてダウンロードおよび展開してしまうことにする.

  • fetch_native.sh
#!/bin/bash

curl -O http://ftp.jaist.ac.jp/pub/GNU/gcc/gcc-7.3.0/gcc-7.3.0.tar.gz
curl -O http://ftp.jaist.ac.jp/pub/GNU/gmp/gmp-6.1.2.tar.bz2
curl -O http://ftp.jaist.ac.jp/pub/GNU/mpfr/mpfr-4.0.0.tar.gz
curl -O http://ftp.jaist.ac.jp/pub/GNU/mpc/mpc-1.1.0.tar.gz
curl -O http://ftp.jaist.ac.jp/pub/GNU/libiconv/libiconv-1.15.tar.gz

tar zxvf gcc-7.3.0.tar.gz
tar jxvf gmp-6.1.2.tar.bz2
tar zxvf mpfr-4.0.0.tar.gz
tar zxvf mpc-1.1.0.tar.gz
tar zxvf libiconv-1.15.tar.gz

rm -rf *.gz
rm -rf *.bz2

このスクリプトを実行することで、N-gcc-7.3.0 ディレクトリ中に必要となるツールが全て展開されることになる.

さて、後は各ソフトウェアを順番にビルドしていくことになる. この中で、mpfr は gmp に、mpc は gmp と mpfr に依存しているため、ビルドする順番が結構重要となっている. したがって、やはりビルド処理もシェルスクリプトを使って自動化することにする.

  • build_native.sh
#!/bin/bash

DIR=$PWD

GMP=gmp-6.1.2
MPFR=mpfr-4.0.0
MPC=mpc-1.1.0
LIBICONV=libiconv-1.15
GCC=gcc-7.3.0

# gmp
mkdir gmp-build
cd gmp-build
../${GMP}/configure \
  --prefix=${DIR}
make -j4
make install
cd ..

# mpfr
mkdir mpfr-build
cd mpfr-build
../${MPFR}/configure \
  --prefix=${DIR} \
  --with-gmp=${DIR}
make -j4
make install
cd ..

# mpc
mkdir mpc-build
cd mpc-build
../${MPC}/configure \
  --prefix=${DIR} \
  --with-gmp=${DIR} \
  --with-mpfr=${DIR}
make -j4
make install
cd ..

# libiconv
mkdir libiconv-build
cd libiconv-build
../${LIBICONV}/configure \
  --prefix=${DIR}
make -j4
make install
cd ..

# gcc
mkdir gcc-build
cd gcc-build
../${GCC}/configure\
 --prefix=${DIR} \
 --with-gmp=${DIR} \
 --with-mpfr=${DIR} \
 --with-mpc=${DIR} \
 --program-suffix=7.3.0 \
 --enable-languages=c,c++ \
 --with-system-zlib \
 --enable-stage1-checking \
 --enable-plugin \
 --enable-lto \
 --disable-multilib \
 --with-libiconv-prefix=${DIR}
make bootstrap
make install

echo "Finished."

このビルドは MBPr 2015 で行ったが、大体 2 時間半程度の時間がかかった. CPU も全力でぶんまわる. のんびり待つしか無い.

ビルドが終わったら N-gcc-7.3.0 ディレクトリ中に新たに bin というディレクトリが生成され、その中にネイティブの gcc が生成されるはずである. 以下のように、たしかに動作することが確認できる.

$ cd bin
$ ./gcc7.3.0
gcc7.3.0: fatal error: no input files
compilation terminated.

ここまででホスト環境におけるネイティブな gcc を用意することができた. これは クロスコンパイラをビルドするのに必要となるコンパイラ である. もう一度 ~/cross にディレクトリ移動しておく.

$ cd ~/cross

さてここからが本題. 用意したネイティブな gcc を使って、クロスコンパイラのビルドをしてみる. まず、クロスコンパイラ用のディレクトリを作成し、その中に移動しておく. 今回は i386 の Linux 向けのクロスコンパイラをビルドするため、ディレクトリ名を i386-elf-gcc-7.3.0 とした.

$ mkdir i386-elf-gcc-7.3.0
$ cd i386-elf-gcc-7.3.0

クロスコンパイラのビルドでは先程ネイティブの gcc をビルドした際に生成した各種バイナリが必要となる. まず、各バイナリが保存されたディレクトリへのシンボリックリンクをこのディレクトリ内に作っておくことにする.

$ ln -s ../N-gcc-7.3.0/gcc-7.3.0 ./
$ ln -s ../N-gcc-7.3.0/gmp-6.1.2 ./
$ ln -s ../N-gcc-7.3.0/mpfr-4.0.0 ./
$ ln -s ../N-gcc-7.3.0/mpc-1.1.0 ./
$ ln -s ../N-gcc-7.3.0/libiconv-1.15 ./

さて、クロスコンパイラの作成には binutils と呼ばれるツールが必要となるため、今度はこのツールのソースをダウンロードする. このツールも JAIST の FTP ミラー からダウンロードすることにしよう. 一応、以下のようなダウンロードスクリプトを用意し、これを実行することでダウンロードおよび展開を行った. (面倒でも各種手続きをスクリプトとして残しておくと、後から確認が楽に行えるので便利だ.)

  • build_cross.sh
#!/bin/bash

curl -O http://ftp.jaist.ac.jp/pub/GNU/binutils/binutils-2.30.tar.gz
tar xjvf binutils-2.30.tar.gz

rm -rf *.gz

後は binutils とクロスコンパイラ gcc をビルドするだけである. 以下のようなビルドスクリプトを実行する.

  • build_cross.sh
#!/bin/bash

DIR=$PWD

# binutils
mkdir binutils-build
cd binutils-build
../binutils-2.30/configure \
    --prefix=${DIR} \
    --target=i386-elf
make -j4
make install
cd ../

mkdir gcc-build
cd gcc-build
../gcc-7.3.0/configure \
    --prefix=${DIR} \
    --target=i386-elf \
    --enable-languages=c,c++ \
    --without-headers
make -j4 all-gcc
make install-gcc

echo "Finished."

クロスコンパイラ gcc は最初にまとめてダウンロードした gcc のソースコードに対して --target オプションを指定することでビルドできるらしい. ここでは i386-elf を指定したことで、i386 の Linux 向けの gcc がビルドできた. 以下のように、たしかに macOS 上で正しく認識できる i386 Linux 向けの gcc が動作するようになった.

$ ~/cross/i386-elf-gcc-7.3.0/bin/i386-elf-gcc
i386-elf-gcc: fatal error: no input files
compilation terminated.

このクロスコンパイラのビルド方法については以下の記事に大変助けられ、大いに参考にさせていただいた. 大変感謝.

とても勉強になった.