keropoの備忘録

しらべたことをメモるブログ

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

コンパイル

アーカイブを解凍
  $tar jxvf busybox-1.21.0.tar.bz2
  $cd  busybox-1.21.0
デフォルトのコンパイル設定を適用
  $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形式になっている
ことを確認したときの画面。
f:id:keropo:20130417230327j:plain

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ボード用にコンパイルする。

環境変数設定

ロスコンパイラのプレフィックスを環境変数に設定

  $export CCPREFIX=${CROSS}/bin/arm-unknown-linux-gnueabi-
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
コンパイル実行
 $make ARCH=arm CROSS_COMPILE=$CCPREFIX

コンパイルが成功すれば、arch/arm/bootフォルダにzImageが出力される。

とりあえず、qemuで実行してみる。

作成されたzImageを適当なフォルダにコピーして、以下を実行

  $qemu-system-arm -M versatilepb -m 256 -kernl zImage

こんな感じで実行された。
まだルートファイルシステムがないので、カーネルパニックを起こすけど、とりあえずカーネルが動いた。
f:id:keropo:20130415234746p:plain

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

また、単純にビルドすると、コンパイルエラーが発生するので、以下の部分を修正する。

  •  ./libc/sysdeps/unix/sysv/linux/ifaddrs.c

   #include <linux/if_addr.h>を追加

  •  ./libc/sysdeps/unix/sysv/linux/check_pf.c

   #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クロスコンパイラの完成!