SH4用クロス環境の作り方

2015年8月25日追記.より新しい情報を「 SH4用クロス環境の作り方(2015年版)」に書きました.詳細は http://d.hatena.ne.jp/pyopyopyo/20150826 をご覧ください.

debian環境で SH4 用のクロス環境を作ったので,手順をメモします

概要としては

  • hostは i386 (amd64でも同様の手順で可)
  • target sh4

で,大まかな手順は

  • 手順1) hostに target用のヘッダファイルやライブラリをインストール
  • 手順2) hostに target用のbinutilsをインストール
  • 手順3) hostに target用のgccをインストール

となります

ここで target がARMであればdebianが正式にサポートしているため作業は簡単です.しかし sh4は正式にサポートされていないので,以下の手順で少々強引に作業しました

手順1) target用のライブラリ類のインストール

sh4 アーキテクチャdebian では正式にサポートされていないので,少々面倒くさい手順が必要です.

まず sh4 を追加します

$ sudo dpkg --add-architecture sh4

次に /etc/apt/sources.list に下記の2行を追加します

deb  [arch=sh4]     http://ftp.debian-ports.org/debian unstable   main
deb  [arch=sh4]     http://ftp.debian-ports.org/debian unreleased main

[arch=hoge] と書いておくと,アーキテクチャhogeの場合だけ,設定が有効になります

これでftp.debian-ports.orgで配布されているsh4のバイナリが流用できるようになります.

一度情報を更新します

$ sudo apt-get update

これで

$ apt-get download libc6:sh4

などとすると, sh4 用のdebパッケージがダウンロードできます.ただし,正式版ではないので,sh4のバイナリは若干バージョンが古かったりもします

次に apt-cross というツールをインストールします

$ sudo apt-get install apt-cross

apt-cross は debパッケージをクロス環境用のパッケージに変換するツールです

たとえば sh4 用の libc6のパッケージ libc6_2.19-13_sh4.deb

$ apt-get download libc6:sh4
$ dpkg-cross -A -M -a sh4 -b libc6_2.19-13_sh4.deb 

で libc6-sh4-cross_2.19-13_all.deb に変換できます.変換後は

$ sudo dpkg -i  libc6-sh4-cross_2.19-13_all.deb

で,インストールできます

xapt をつかうと上記作業が全部自動化できます

$ sudo apt-get install xapt

使い方は,たとえばlibc6-sh4-crossをインストールしたい場合は

$ sudo xapt -M  http://ftp.debian-ports.org/debian -k  -S unstable -a sh4   libc6

です

ちなみに,xaptの内部動作は

  • /var/lib/xapt/archives 以下に libc6_2.19-13_sh4.debをダウンロード
  • dpkg-cross で sh4-cross へ変換
  • /var/lib/xapt/output 以下に変換後のlibc6-sh4-cross_2.19-13_all.deb を保存
  • 最後に dpkg -i

となります.

xapt を使って,GCCのビルドに必要なパッケージ

  • libc6
  • libc6-dev
  • libgcc1
  • libgcc1-dev
  • linux-libc-dev
  • gcc-4.9-base
  • multiarch-support

をインストールします

sh4-corssが提供するファイルは /usr/sh4-linux-gnu ディレクトリ以下に配置されます

重要なファイルは,以下のディレクトリに配置されるヘッダファイルとライブラリです

fileコマンドを使って,バイナリのヘッダを確認すると

$ file /usr/sh4-linux-gnu/lib/crt1.o 
/usr/sh4-linux-gnu/lib/crt1.o: ELF 32-bit LSB relocatable, Renesas SH, version 1 (SYSV), for GNU/Linux 2.6.32, not stripped

という感じで ターゲットの sh4 用のバイナリであることが確認できます

手順2) target用のbinutilsをインストール

$ sudo apt-get build-dep --no-install-recommends binutils

$ apt-get source bintuils

$ cd binutils-*
$ TARGET=sh4 fakeroot dpkg-buildpackage -b -us -uc
$ cd ..

出来上がったdebパッケージの内容を確認してみます

$ dpkg --contents binutils-sh4-linux*.deb

例えば sh4用のリンカは /usr/bin/sh4-linux-gnu-ld,asは/usr/bin/sh4-linux-gnu-asと言う感じで
コマンドの頭に sh4-linux-gnu- が付与されていることが分かります

正しく sh4-linux-gnu-?? なバイナリが生成できていれば,インストールします

$ sudo dpkg -i  binutils-sh4-linux*.deb

手順3) target用のGCCをインストール

sh4 用のGCC をインストールします

ここで

  • debianでは sh4 はあまりメンテされていない
  • 今回,私が必要とするのは Cコンパイラだけで, gcjやobjc++等は不要

という理由から GCCdebパッケージを用いず,自前でビルドすることにしました

インストール先は念の為 /opt とします.つまり configure 時には --prefix=/opt をつけ,
アンイストール時は /opt 以下を消せばOK,ということになります

$ sudo mkdir -p /opt

MultiArch のルールでは クロスコンパイル用のライブラリやヘッダは /usr/sh4-linux-gnu 以下に配置します. --prefix=/opt をつけると /opt/sh4-linux-gnu を見ることになるので,シンボリックリンクを貼ります

$ sudo ln -s /usr/sh4-linux-gnu /opt

次に GCCソースコードをダウンロードします.GCC 4.9.2 を使いました

$ tar xfj gcc-4.9.2.tar.bz2
$ cd gcc-4.9.2

作業用ディレクトリを作成します

$ mkdir build
$ cd build

念の為,不具合を起こしそうな環境変数達をリセットします

unset CC
unset CXX
unset FC
unset CCACHE_DIR
../configure --prefix=/opt --enable-languages=c  --target=sh4-linux-gnu --disable-libssp --disable-libgomp --disable-nls --disable-libatomic --disable-libquadmath --with-cpu=sh4 --with-multilib-list=m4,m4-nofpu --disable-threads 

オプションはそれぞれ

  • --enable-languages=c Cのコンパイラだけビルド
  • --target=sh4-linux-gnu
  • --with-cpu=sh4 ターゲットを sh4 に
  • --with-multilib-list=m4,m4-nofpu FPU有と無版のSH4に対応させるため
  • --disable-??? 不要なものは無効にする

という感じです

ビルドして,インストールします

$ make -j16
$ sudo make install

Cのコンパイラだけなので,ビルドはすぐに終わります

動作確認は

$ export PATH=/opt/bin:$PATH
$ sh4-linux-gnu-gcc -v

です

簡単なコードをコンパイルしてみます

$ cat hoge.c
int main() { return 123; }
$ sh4-linux-gnu-gcc  hoge.c
$ file ./a.out
./a.out: ELF 32-bit LSB executable, Renesas SH, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped

ターゲットに a.out をコピーして,実行してみます.

$ ./a.out
$ echo $?
123

問題なければ,次の段階で printf を試してみます

$ cat hoge.c
#include <stdio.h>
int main() { printf("Hello C\n"); return 0; }
$ sh4-linux-gnu-gcc  hoge.c

ついでに strip コマンドも試してみます

$ sh4-linux-gnu-strip a.out 

sh4-linux-gnu- をつけるのを忘れずに.

以上で,クロス環境のセットアップは完了です