ARMクロスコンパイラ作成(追加)
下記の記事でクロスコンパイラ作成の手順をつらつら書いたが、いちいちコマンドを打って構築するのは面倒なので、コマンド一発で作成できるようにシェルスクリプトを作成してみた。
ARMクロスコンパイラ作成
バージョンを変えて実験してみたい場合も、変数をちょっと変えれば良いようにしてあるので、ちょっとだけ便利。
mkcc.sh
#!/bin/sh # Create ARM cross compiler toolchain. # # Copyright (C) 2012- for keropo, All rights reserved. # HOME_DIR=`pwd` TARGET=arm-unknown-linux-gnueabi CROSS=${HOME_DIR}/toolchain ROOTDIR=${CROSS}/${TARGET}/sysroot BINUTILS_FILE=binutils-2.23.2 GCC_FILE=gcc-4.5.3 GMP_FILE=gmp-5.1.1 MPFR_FILE=mpfr-3.1.2 MPC_FILE=mpc-0.8.2 GLIBC_FILE=eglibc-2_13 KERNEL_FILE=linux-3.2.35 export PATH=$PATH:${CROSS}/bin cleanup() { if [ -e "${BINUTILS_FILE}" ]; then rm -rf ${BINUTILS_FILE} fi if [ -e "${GCC_FILE}" ]; then rm -rf ${GCC_FILE} fi if [ -e "${GMP_FILE}" ]; then rm -rf ${GMP_FILE} fi if [ -e "${MPFR_FILE}" ]; then rm -rf ${MPFR_FILE} fi if [ -e "${MPC_FILE}" ]; then rm -rf ${MPC_FILE} fi if [ -e "${KERNEL_FILE}" ]; then rm -rf ${KERNEL_FILE} fi if [ -e "${GLIBC_FILE}" ]; then rm -rf ${GLIBC_FILE} fi } download_files() { if [ ! -e "${BINUTILS_FILE}.tar.bz2" ]; then wget http://ftp.gnu.org/gnu/binutils/${BINUTILS_FILE}.tar.bz2 fi if [ ! -e "${GCC_FILE}.tar.bz2" ]; then wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/${GCC_FILE}/${GCC_FILE}.tar.bz2 fi if [ ! -e "${GMP_FILE}.tar.bz2" ]; then wget ftp://ftp.gnu.org/gnu/gmp/${GMP_FILE}.tar.bz2 fi if [ ! -e "${MPFR_FILE}.tar.bz2" ]; then wget http://www.mpfr.org/mpfr-current/${MPFR_FILE}.tar.bz2 fi if [ ! -e "${MPC_FILE}.tar.gz" ]; then wget http://www.multiprecision.org/mpc/download/${MPC_FILE}.tar.gz fi if [ ! -e "${KERNEL_FILE}.tar.bz2" ]; then wget https://www.kernel.org/pub/linux/kernel/v3.x/${KERNEL_FILE}.tar.bz2 fi if [ ! -e "${GLIBC_FILE}.tar.gz" ]; then svn co http://www.eglibc.org/svn/branches/${GLIBC_FILE} ${GLIBC_FILE} tar cvfz ${GLIBC_FILE}.tar.gz ${GLIBC_FILE} fi } unpack() { if [ ! -e "${BINUTILS_FILE}" ]; then tar jxvf ${BINUTILS_FILE}.tar.bz2 fi if [ ! -e "${GCC_FILE}" ]; then tar jxvf ${GCC_FILE}.tar.bz2 fi if [ ! -e "${GMP_FILE}" ]; then tar jxvf ${GMP_FILE}.tar.bz2 fi if [ ! -e "${MPFR_FILE}" ]; then tar jxvf ${MPFR_FILE}.tar.bz2 fi if [ ! -e "${MPC_FILE}" ]; then tar xvfz ${MPC_FILE}.tar.gz fi if [ ! -e "${KERNEL_FILE}" ]; then tar jxvf ${KERNEL_FILE}.tar.bz2 fi if [ ! -e "${GLIBC_FILE}" ]; then tar xvfz ${GLIBC_FILE}.tar.gz fi } mkdirectory() { if [ -e "${CROSS}" ]; then rm -rf ${CROSS} fi mkdir -p ${CROSS} } mkbinutils() { cd ${HOME_DIR}/${BINUTILS_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure --target=${TARGET} --prefix=${CROSS} --with-sysroot=${ROOTDIR} if [ "$?" -ne 0 ]; then echo "configure ${BINUTILS_FILE} failure." exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${BINUTILS_FILE} failure." exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${BINUTILS_FILE} failure." exit 1 fi } mkgmp() { cd ${HOME_DIR}/${GMP_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure --prefix=${CROSS} if [ "$?" -ne 0 ]; then echo "configure ${GMP_FILE} failure." exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${GMP_FILE} failure." exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${GMP_FILE} failure." exit 1 fi } mkmpfr() { cd ${HOME_DIR}/${MPFR_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure --prefix=${CROSS} --with-gmp=${CROSS} if [ "$?" -ne 0 ]; then echo "configure ${MPFR_FILE} failure." exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${MPFR_FILE} failure." exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${MPFR_FILE} failure." exit 1 fi } mkmpc() { cd ${HOME_DIR}/${MPC_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure --prefix=${CROSS} --with-gmp=${CROSS} --with-mpfr=${CROSS} if [ "$?" -ne 0 ]; then echo "configure ${MPC_FILE} failure." exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${MPC_FILE} failure." exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${MPC_FILE} failure." exit 1 fi } mkgcc1() { #delete so file of gmp/mpfr/mpc rm -rf ${CROSS}/lib/*.so* rm -rf ${CROSS}/lib/*.la cd ${HOME_DIR}/${GCC_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure \ --target=${TARGET} \ --prefix=${CROSS} \ --without-headers \ --without-ppl \ --with-newlib \ --disable-shared \ --disable-threads \ --disable-libssp \ --disable-libgomp \ --disable-libmudflap \ --disable-nls \ --with-gmp=${CROSS} \ --with-mpfr=${CROSS} \ --with-mpc=${CROSS} \ --enable-languages=c if [ "$?" -ne 0 ]; then echo "configure ${GCC_FILE} failure. (mkgcc1)" exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${GCC_FILE} failure.(mkgcc1)" exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${GCC_FILE} failure.(mkgcc1)" exit 1 fi } mkgcc2() { cd ${HOME_DIR}/${GCC_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure \ --target=${TARGET} \ --prefix=${CROSS} \ --with-sysroot=${ROOTDIR} \ --disable-libssp --disable-libgomp --disable-libmudflap \ --with-gmp=${CROSS} \ --with-mpfr=${CROSS} \ --with-mpc=${CROSS} \ --enable-languages=c if [ "$?" -ne 0 ]; then echo "configure ${GCC_FILE} failure.(mkgcc2)" exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${GCC_FILE} failure.(mkgcc2)" exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${GCC_FILE} failure.(mkgcc2)" exit 1 fi } mkgcc3() { cd ${HOME_DIR}/${GCC_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build ../configure \ --target=${TARGET} \ --prefix=${CROSS} \ --with-sysroot=${ROOTDIR} \ --disable-libssp --disable-libgomp --disable-libmudflap \ --with-gmp=${CROSS} \ --with-mpfr=${CROSS} \ --with-mpc=${CROSS} \ --enable-languages=c,c++ if [ "$?" -ne 0 ]; then echo "configure ${GCC_FILE} failure.(mkgcc3)" exit 1 fi make if [ "$?" -ne 0 ]; then echo "make ${GCC_FILE} failure.(mkgcc3)" exit 1 fi make install if [ "$?" -ne 0 ]; then echo "make install ${GCC_FILE} failure.(mkgcc3)" exit 1 fi } mk_kernel_header() { cd ${HOME_DIR}/${KERNEL_FILE} make mrproper make headers_install ARCH=arm CROSS_COMPILE=${TARGET}- INSTALL_HDR_PATH=${ROOTDIR}/usr if [ "$?" -ne 0 ]; then echo "install headers ${KERNEL_FILE} failure." exit 1 fi } mkglibc_header() { cd ${HOME_DIR}/${GLIBC_FILE} cp -r ports libc if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build BUILD_CC=gcc \ CC=${TARGET}-gcc \ CXX=${TARGET}-g++ \ AR=${TARGET}-ar \ RANLIB=${TARGET}-ranlib \ ../libc/configure \ --prefix=/usr \ --with-headers=${ROOTDIR}/usr/include \ --host=${TARGET} \ --disable-profile \ --without-gd \ --without-cvs \ --enable-add-ons if [ "$?" -ne 0 ]; then echo "configure glibc header ${GLIBC_FILE} failure." exit 1 fi make install-headers install_root=${ROOTDIR} install-bootstrap-headers=yes if [ "$?" -ne 0 ]; then echo "install glibc header ${GLIBC_FILE} failure." exit 1 fi make csu/subdir_lib if [ "$?" -ne 0 ]; then echo "make scu/subdir ${GLIBC_FILE} failure." exit 1 fi mkdir -p ${ROOTDIR}/usr/lib cp csu/crt1.o csu/crti.o csu/crtn.o ${ROOTDIR}/usr/lib ${TARGET}-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o ${ROOTDIR}/usr/lib/libc.so if [ "$?" -ne 0 ]; then echo "make libc.so ${GLIBC_FILE} failure." exit 1 fi } mkglibc() { cd ${HOME_DIR}/${GLIBC_FILE} if [ -e "build" ]; then rm -rf build fi mkdir -p build cd build BUILD_CC=gcc \ CC=${TARGET}-gcc \ CXX=${TARGET}-g++ \ AR=${TARGET}-ar \ RANLIB=${TARGET}-ranlib \ ../libc/configure \ --prefix=/usr \ --with-headers=${ROOTDIR}/usr/include \ --host=${TARGET} \ --disable-profile \ --without-gd \ --without-cvs \ --enable-add-ons if [ "$?" -ne 0 ]; then echo "configure glibc ${GLIBC_FILE} failure." exit 1 fi make if [ "$?" -ne 0 ]; then echo "make glibc ${GLIBC_FILE} failure." exit 1 fi make install install_root=${ROOTDIR} if [ "$?" -ne 0 ]; then echo "install glibc ${GLIBC_FILE} failure." exit 1 fi } cleanup mkdirectory download_files unpack mkbinutils mkgmp mkmpfr mkmpc mkgcc1 mk_kernel_header mkglibc_header mkgcc2 mkglibc mkgcc3 echo "done." exit 0
BusyBoxのコンパイル
ARMクロスコンパイラ作成で作成したクロスコンパイラを利用してBusyBoxをコンパイルする。
BusyBoxは標準Linuxコマンドの機能を1実行ファイルで提供されるので、ディスク
容量を大幅な削減が期待できるため、組込みの世界ではよくお見かけするツール。
環境変数の設定
$export CROSS=${ツールチェーンのルートフォルダ} $export TARGET=arm-unknown-linux-gnueabi $export PATH=$PATH:$CROSS/bin
コンパイル
デフォルトのコンパイル設定を適用
$make ARCH=arm CROSS_COMPILE=$TARGET- defconfig
menuconfigで詳細な設定
$make ARCH=arm CROSS_COMPILE=$TARGET- menuconfig
今回はざっくり以下のようにした。
- staticリンクのバイナリを生成する設定
Build Options -->[*]Build BusyBox as a static binary (no shared libs)
- プリンター系はまるっと不要
- メールユーティリティもまるっと不要
- ネットワーク系は多すぎるので不要そうなコマンドを削除
- アーカイブ系のコマンドも多いので削る
コンパイル実行
$make ARCH=arm CROSS_COMPILE=$TARGET-
インストール
$make ARCH=arm CROSS_COMPILE=$TARGET- install
インストールが成功すれば、__installというフォルダがカレントディレクトリ
に作成され、コマンド一式が生成されているはず。
以下が__install/binフォルダの中身とbusyboxバイナリがARM形式になっている
ことを確認したときの画面。
linuxカーネルのコンパイル
構築したARMクロスコンパイラでカーネルをコンパイルしてみる。
もともとオリジナルの組込みLinuxOSを作成したいと思っているので、ここからが本番。
実行環境のインストール
qemuでクロスコンパイルしたカーネルを実行するため、インストールする。
とりあえず、下記コマンドで、qemuのソースコードを落としてくる。
$wget http://wiki.qemu-project.org/download/qemu-1.4.0.tar.bz2
解凍して、コンパイルを実行。
インストールする時、rootじゃないといけないので、rootで実行。
#./configure #make #make install
インストールが完了したら、とりあえず、$qemuと打って、タブを押すと
「qemu-system-ほげほげ」というのが候補として表示されたらインストールOK。
カーネルのコンパイル
いよいよカーネルのコンパイル。
今回はカーネル3.2.35をARMアーキテクチャでqemuでよくエミュレート方法が
いろいろなサイトで紹介されているversatileボード用にコンパイルする。
versatileデフォルトの設定を反映
$make mrproper $make ARCH=arm CROSS_COMPILE=$CCPREFIX versatile_defconfig
次にmenuconfigで下記のように設定
-BUS Support -->[*]PCI Support -kernel feature -->[*]Use the ARM EABI to compile the kernel -->[*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL) -device driver -->graphic support -->[*]Bootup logo -->SCSI device support --><*>SCSI device support --><*> SCSI disk support --><*> SCSI generic support -->[*] SCSI low-level drivers (NEW) --><*> SYM53C8XX Version 2 SCSI support -File System -->[*] Ext2 extended attributes -->[*] Ext2 execute in place support --><*> Ext3 journalling file system support -->[*] Default to 'data=ordered' in ext3 -->[*] Ext3 extended attributes
ARMクロスコンパイラ作成
ARM上での組込みLinuxをコンパイルする為のARMクロスコンパイラの構築方法メモ
(eglibcのコンパイル時にソース修正が必要だったが、とりあえず構築できた)
(2013.4.17 追記)eglibcとkernelに修正が必要なのは、kernelのバージョンが古すぎることが原因と分かったのでkernel-3.2.35を使用するように修正。
使用したソース
前準備
とりあえず、コンパイルに必要そうなツール類をyumでインストール。
- yum -y install zlib-devel
- yum -y install glib2-devel
- yum -y install SDL-devel
- yum -y install texinfo
- yum -y install libtool
- yum -y install autoconf
- yum -y install ncurses
- yum -y install ncurses-devel
以下の環境変数を設定
$export TARGET=arm-unknown-linux-gnueabi
$export CROSS=~/toolchain
$export ROOTDIR=$CROSS/$TARGET
binutilsのコンパイル
binutilsをダウンロードして、解凍したフォルダ内にビルド用のフォルダ(buildフォルダ)を生成してビルドする。binutilsのコンパイルのときだけに限らず、gccやeglibcなどのコンパイルの時も解凍したフォルダ内にbuildフォルダを作成し、そこでコンパイル作業を行う。
$cd binutils-2.23.2/build
$../configure --target=$TARGET --prefix=$CROSS --with-sysroot=$ROOTDIR
$make
$make install
gmpのコンパイル
$cd gmp-5.1.1/build
$../configure --prefix=$CROSS
$make
$make install
mpfrのコンパイル
$cd mpfr-3.1.2/build
$../configure --prefix=$CROSS --with-gmp=$CROSS
$make
$make install
mpcのコンパイル
$cd mpc-0.8.2/build
$../configure --prefix=$CROSS --with-gmp=$CROSS --with-mpfr=$CROSS
$make
$make install
gccのコンパイル(1回目)
gccをコンパイルする前に、gmp,mpfr, mpcのコンパイルによって作成されたsoファイルがあると、gccコンパイル時のリンク処理で失敗するので削除
$rm -f $CROSS/lib/*.so
soファイルを削除し終わったら、コンパイル実行
$cd gcc-4.5.3/build
$../configure \
--target=$TARGET \
--prefix=$CROSS \
--without-headers \
--without-ppl \
--with-newlib \
--disable-shared \
--disable-threads \
--disable-libssp \
--disable-libgomp \
--disable-libmudflap \
--disable-nls \
--with-gmp=$CROSS \
--with-mpfr=$CROSS \
--with-mpc=$CROSS \
--enable-languages=c
$make
$make install
カーネルヘッダーの作成
$cd linux-2.6.19
$cd linux-3.2.35
$make mrproper
$make headers_install ARCH=arm CROSS_COMPILE=arm-unknown-linux-gnueabi- INSTALL_HDR_PATH=$ROOTDIR/usr
上記を実行した際、「getline」の定義が重複しているエラーになる場合は以下のソースのgetlineをget_lineに置換してやる。
scripts/unifdef.c
eglibcのコンパイル(ヘッダー生成のみ)
$cd eglibc-2_13
$cp -r ports libc
$cd build
$export PATH=$PATH:$CROSS/bin
$BUILD_CC=gcc \
CC=$TARGET-gcc \
CXX=$TARGET-g++ \
AR=$TARGET-ar \
RANLIB=$TARGET-ranlib \
../libc/configure \
--prefix=/usr \
--with-headers=$ROOTDIR/usr/include \
--host=$TARGET \
--disable-profile \
--without-gd \
--without-cvs \
--enable-add-ons
$make install-headers install_root=$ROOTDIR install-bootstrap-headers=yes
下記コマンドで作成されるcrt1.o crti.o crtn.oを$ROOTDIR/usr/libにコピーする。
$make csu/subdir_lib
$mkdir -p $ROOTDIR/usr/lib
$cp csu/crt1.o csu/crti.o csu/crtn.o $ROOTDIR/usr/lib
最後にlibc.soを生成し、 $ROOTDIR/usr/libに出力
$ ${TARGET}-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $ROOTDIR/usr/lib/libc.so
gccのコンパイル(2回目)
$cd gcc-4.5.3/build
$ rm -rf *
$../configure \
--target=$TARGET \
--prefix=$CROSS \
--with-sysroot=$ROOTDIR \
--disable-libssp --disable-libgomp --disable-libmudflap \
--with-gmp=$CROSS \
--with-mpfr=$CROSS \
--with-mpc=$CROSS \
--enable-languages=c
$make
$make install
eglibcのコンパイル
インストール時に必要になるので、以下のツールをインストールする。
#yum -y install gperf
また、単純にビルドすると、コンパイルエラーが発生するので、以下の部分を修正する。
#include <linux/if_addr.h>を追加
#include <linux/if_addr.h>を追加
下記、3ファイルに、define定義を追加
- ./libc/sysdeps/unix/sysv/linux/if_index.c
- ./libc/sysdeps/unix/sysv/linux/ifaddrs.c
- ./libc/sysdeps/unix/sysv/linux/check_pf.c
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
$cd eglibc-2_13/build
$rm -rf *
$BUILD_CC=gcc \
CC=$TARGET-gcc \
CXX=$TARGET-g++ \
AR=$TARGET-ar \
RANLIB=$TARGET-ranlib \
../libc/configure \
--prefix=/usr \
--with-headers=$ROOTDIR/usr/include \
--host=$TARGET \
--disable-profile \
--without-gd \
--without-cvs \
--enable-add-ons
$make
$make install install_root=$ROOTDIR
gccのコンパイル(完成)
$cd gcc-4.5.3/build
$ rm -rf *
$../configure \
--target=$TARGET \
--prefix=$CROSS \
--with-sysroot=$ROOTDIR \
--disable-libssp --disable-libgomp --disable-libmudflap \
--with-gmp=$CROSS \
--with-mpfr=$CROSS \
--with-mpc=$CROSS \
--enable-languages=c,c++
$make
$make install
以上で、ARMクロスコンパイラの完成!
備忘録を開設
いろいろ調べたことを会社から参照したくて備忘録目的で開設。
不定期でいろいろアップしていく予定です。