PQI Air Pen向けにmips-linux-gnu-gccをソースビルドした話
事の発端
年末にNTT-XストアでPQI Air Penが破格の値段でした。
これ、有線/無線でFTPサーバーになるWi-Fiアダプタなのですが、なにより、弄り倒し甲斐のあるLinuxが入ったMIPSマイコンボードな訳です。
nttxstore.jp
そして心強いmoyashi兄さんのブログ
hitoriblog.com
もう買うしかない。正月休みに遊ぶネタが出来たわけです。
飽きてもこれだったら部屋のWiFiルータにはなります。
で、クロスコンパイラはSourcery CodeBench Lite Edition for MIPS GNU/Linuxがあるので別に必要ないのですが、
Ubuntu xenial(16.04LTS)はgcc-5-mips-linux-gnuが提供されているのでこれでビルドし、PQI Air Penで動作させようとすると、
~ #./a.out FATAL: kernel too old Bus error ~ #
致命的エラー:カーネルおじさんめっちゃ老けてるぞ
よーし、一人だけgcc野良ビルドする苦行2017選手権やるか
正月休みにおすすめしたいとても有益な時間の浪費方法です。絶対やめた方がいい。おすすめです。
Rなんとか社のRXマイコンの時は会社でも家でも散々野良rx-gccビルド大会してましたね。このブログのアクセス解析が某軽子坂からのアクセスだらけになってたのはいい思い出です。あんな共用体地獄ライブラリ付きうんこマイコン金輪際ビルドしてやらねぇ。
息をするように野良ビルドするのも考え物ですがカーネルバージョンに合わせて自分でビルドできるので、時には必要な事もあるのかも。
まず、PQI Air Pen(ファームウェアはv0.1.24に変更済み)のカーネルを確認します
~ # cat /proc/version Linux version 2.6.31.AirPen_V0.1.22-g5eca71a (dio@dio) (gcc version 4.3.3 (GCC) ) #324 Thu Feb 7 17:36:23 CST 2013 ~ #
mips-linux-gnuのビルド
ホスト
ビルドおよび動作確認したのは以下の環境です
- Ubuntu trusty (14.04LTS) 仮想化環境(VMware 12) / デュアルブート の両環境
- Ubuntu xenial (16.04LTS) 仮想化環境(VMware 12) / デュアルブート の両環境
ubuntuはメインで使っている14.04で動くことを目指しました。(結局16.04でもビルドできた。詳細後述)
16.04LTSいろいろ難しい…
どちらも前もってインストールしておくパッケージ
$ sudo apt-get update $ sudo apt-get install build-essential m4 gawk g++ make
GCCビルド成功した組み合わせ
GMP,MPC,MPFRを別個にwgetしてもいいのですがGCCフォルダ内の
contrib/download_prerequisites
を起動して自動取得しています。
Ubuntu 16.04LTSがbinutilsのビルドからこけやがる件
本当は根本的な解決をするべきなのでしょうが、よくわからないところで警告出してエラー終了しているので-Wno-errorで回避していまいます。
CFLAGS=-Wno-error binutils-${BINUTILSVERSION}/configure (中略) --disable-warnings-as-errors
スクリプトかいた
出来てしまうと大したことはないのですが、すごくめんどくさいのと大したことないのは別問題なので(?)スクリプト書きました。めっちゃ適当に書いてるので、詳しい人書き直して。
ビルド前にmips-linux-gnuをすでにインストールしている場合はアンインストールするか、$PATHをunsetしておきましょう
#!/bin/bash -ev # see https://www.linux-mips.org/wiki/Toolchains#Roll-your-own # see http://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ # see also http://www.hs-augsburg.de/~beckmanf/dokuwiki/doku.php?id=mips_cross_compiler export WDIR=$HOME/tmp export TARGET=mips-linux-gnu export PREFIX=$HOME/mips-cross export TARCH=mips export PATH="${PATH}":${PREFIX}/bin # ------------------------------ # enviroments # ------------------------------ echo ${WDIR} echo ${TARGET} echo ${PREFIX} echo ${PATH} # ------------------------------ mkdir -p ${PREFIX} mkdir -p $WDIR cd $WDIR mkdir -p ${TARGET}-toolchain cd ${TARGET}-toolchain # version BINUTILSVERSION="2.24" GCCVERSION="4.9.2" #GDBVERSION="7.7" ISLVERSION="0.12.2" CLOOGVERSION="0.18.1" #GLIBCVERSION="2.20" #PORTSVERSION="2.20" GLIBCVERSION="2.19" PORTSVERSION="2.19" #KERNELVERSION="3.17.2" #KERNELVERSION="2.6.27.62" #KERNELVERSION="2.6.32.60" KERNELVERSION="2.6.30" # wget if [ ! -e "binutils-${BINUTILSVERSION}.tar.bz2" ] ; then wget http://ftp.gnu.org/gnu/binutils/binutils-${BINUTILSVERSION}.tar.bz2 fi if [ ! -e "gcc-${GCCVERSION}.tar.bz2" ] ; then wget http://ftp.gnu.org/gnu/gcc/gcc-${GCCVERSION}/gcc-${GCCVERSION}.tar.bz2 fi << COMMENTOUT if [ ! -e "gdb-${GDBVERSION}.tar.bz2" ] ; then wget http://ftp.gnu.org/gnu/gdb/gdb-${GDBVERSION}.tar.bz2 fi COMMENTOUT if [ ! -e "linux-${KERNELVERSION}.tar.xz" ] ; then # wget https://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.27/linux-${KERNELVERSION}.tar.xz # wget https://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-${KERNELVERSION}.tar.xz # wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-${KERNELVERSION}.tar.xz wget https://www.kernel.org/pub/linux/kernel/v2.6/linux-${KERNELVERSION}.tar.xz fi # ---------------------- # wget kernel-headers # ---------------------- if [ ! -d "linux-${KERNELVERSION}" ] ; then tar -Jxvf linux-${KERNELVERSION}.tar.xz fi # ---------------------- # binutils # ---------------------- if [ ! -d "binutils-${BINUTILSVERSION}" ] ; then tar xjf binutils-${BINUTILSVERSION}.tar.bz2 fi # ---------------------- # gcc # ---------------------- if [ ! -d "gcc-${GCCVERSION}" ] ; then tar xjf gcc-${GCCVERSION}.tar.bz2 fi #----------------------- # get infrastructure # gmp, mpfr, gmp #----------------------- if [ ! -d "gmp" ] ; then gcc-${GCCVERSION}/contrib/download_prerequisites fi # get isl if [ ! -e "isl-${ISLVERSION}.tar.bz2" ] ; then wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-${ISLVERSION}.tar.bz2 fi if [ ! -d "isl-${ISLVERSION}" ] ; then tar -xvjf isl-${ISLVERSION}.tar.bz2 fi # get cloog if [ ! -e "cloog-${CLOOGVERSION}.tar.gz" ] ; then wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-${CLOOGVERSION}.tar.gz fi if [ ! -d "cloog-${CLOOGVERSION}" ] ; then tar -xvf cloog-${CLOOGVERSION}.tar.gz fi # get glibc if [ ! -e "glibc-${GLIBCVERSION}.tar.xz" ] ; then wget ftp://ftp.gnu.org/gnu/glibc/glibc-${GLIBCVERSION}.tar.xz fi if [ ! -d "glibc-${GLIBCVERSION}" ] ; then tar -Jxvf glibc-${GLIBCVERSION}.tar.xz fi << COMMENTOUT # get glibc-ports if [ ! -e "glibc-ports-${PORTSVERSION}.tar.bz2" ] ; then wget http://ftp.gnu.org/gnu/libc/glibc-ports-${PORTSVERSION}.tar.bz2 fi if [ ! -d "glibc-ports-${PORTSVERSION}" ] ; then tar -xvjf glibc-ports-${PORTSVERSION}.tar.bz2 fi COMMENTOUT #ln -sf glibc-ports-${PORTSVERSION} glibc-${GLIBCVERSION}/ports # cd glibc-${GLIBCVERSION} # ln -sf ../glibc-ports-${GLIBCVERSION} ports # cd .. # -------------------------------------------------------- # Build step 0: make symbolic link # mpfr, gmp, mpc, mpfr, isl, cloog # -------------------------------------------------------- cd gcc-${GCCVERSION} ln -sf ../mpfr mpfr ln -sf ../gmp gmp ln -sf ../mpc mpc ln -sf ../isl-${ISLVERSION} isl ln -sf ../cloog-${CLOOGVERSION} cloog cd .. # -------------------------------------------------------- # Build step 1: make Binutils # configure & make & install # -------------------------------------------------------- mkdir -p build-binutils cd build-binutils if [ ! -e "config.status" ] ; then CFLAGS=-Wno-error ../binutils-${BINUTILSVERSION}/configure --target=${TARGET} --prefix=${PREFIX} --disable-warnings-as-errors fi if [ ! -e "${PREFIX}/bin/${TARGET}-ld" ] ; then make make install fi cd .. # -------------------------------------------------------- # Build step 2: make Linux Kernel Headers # make headers_install # -------------------------------------------------------- cd linux-${KERNELVERSION} make ARCH=${TARCH} INSTALL_HDR_PATH=${PREFIX}/${TARGET} headers_install cd .. # -------------------------------------------------------- # Build step 3: Build GCC but libraries # make all-gcc && make install-gcc # -------------------------------------------------------- mkdir -p build-gcc cd build-gcc ../gcc-${GCCVERSION}/configure --prefix=${PREFIX} --target=${TARGET} --enable-languages=c,c++ --disable-multilib make all-gcc make install-gcc cd .. # -------------------------------------------------------- # Build step 4: Standard C library Headers and Startup Files # make (removed --enable-add-ons=ports, --disable-sanity-checks--with-tls --disable-versioning --disable-profile) # -------------------------------------------------------- mkdir -p build-glibc cd build-glibc ../glibc-${GLIBCVERSION}/configure --prefix=${PREFIX}/${TARGET} --build=${MACHTYPE} --host=${TARGET} --target=${TARGET} --with-headers=${PREFIX}/${TARGET}/include --disable-multilib libc_cv_forced_unwind=yes make install-bootstrap-headers=yes install-headers 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 .. # -------------------------------------------------------- # Build step 5: Compiler Support library # make # -------------------------------------------------------- cd build-gcc make all-target-libgcc make install-target-libgcc cd .. # -------------------------------------------------------- # Build step 6: Standard C library # make # -------------------------------------------------------- cd build-glibc make make install cd .. # -------------------------------------------------------- # Build step 7: Standard C++ library # make # -------------------------------------------------------- cd build-gcc make make install cd ..
ビルドが無事終わったら忘れないうちに.bashrcにPATHを通しておいた方がいいと思います。PCはCore-i5 5200Uが乗っているWindows7ノートでやったのですが、
ビルド時間はubuntuのパッケージバージョンには関係なく
VMware環境 2時間半
デュアル環境 40分
でした。仮想環境結構遅いんだね。
#include <stdio.h> int main(int argc, char *argv[]){ printf("hello world.\nThis is PQI Air Pen.\n"); return 0; }
という何の変哲もないコードをhello.cなどと保存し、
$ mips-linux-gnu-gcc -g -O2 -Wall -pedantic -march=24kc -static -o hello hello.c
とすれば、3MB以上もある巨大バイナリが完成する。(staticビルドだからしかたない)
これをmicroSDにコピーするか、FTP経由でPQI Air Penにアップロードする。
telnetでPQI Air Penにログイン
hoge@ubuntu:~$ telnet 192.168.200.1 Trying 192.168.200.1... Connected to 192.168.200.1. Escape character is '^]'. (none) login: root Password: (パスワード:pqiap) BusyBox v1.01 (2013.02.07-09:36+0000) Built-in shell (ash) Enter 'help' for a list of built-in commands. ~ # cd /tmp/www/ftp/sda1/ /tmp/www/ftp/sda1 # ./hello hello world. This is PQI Air Pen. /tmp/www/ftp #
ncursesをtelnet使ってパイプする方法がわかればslコマンドでも、と思ったのですが、いかんせんよくわからず…
また時間のあるときに、Luaでもビルドしてみよう。
おしまい。
参考サイト
https://www.linux-mips.org/wiki/Toolchains#Roll-your-own MIPSクロスコンパイラをビルドするのに最低限必要な内容
http://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ Linux上で動作するクロスコンパイラをビルドのするのに必要な知識
http://www.hs-augsburg.de/~beckmanf/dokuwiki/doku.php?id=mips_cross_compiler bare-metalなMIPSコンパイラを作る時に必要な知識