OpenWRT Closs Compile メモ

OpenWRTをインストールできたので、OpenWRT上で動くアプリケーションをコンパイルする。
OpenWRTが動いているルータ(TP-Link WDR4300 N750)はディスク容量もメモリもかなり少ないため、ルータ上でプログラムをコンパイルすることができない。 そのため、別のLinuxサーバでクロスコンパイル環境を構築し、ソースコードをビルドする必要がある。
今回はOpenWRT上で最新版のHostapdを動かすことを目標に、クロスコンパイルを実行していく。

OpenWRT SDKの準備

OpenWRT SDKとはOpenWRT用のクロスコンパイル環境が一式そろったものである。 それぞれのバージョン・アーキテクチャごとにSDKが用意されているので、自分のバージョンに合ったものをダウンロードする。
(ファームウェアイメージと同じ場所にある)

linux上でファイルを解凍。   名前が長いので変更しました。

root@ubuntu # tar -xvf OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
    ...
    ...
    ...
root@ubuntu # mv OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2 openwrt
root@ubuntu # ls -al
    drwxr-xr-x 12 root root     4096 Aug 17 14:40 openwrt

実はクロスコンパイル環境はこれで準備完了。
SDKが用意されているのは便利ですね。
本来ならば、自分の環境のSDKはgitのソースから自分でビルドする必要があります。
やり方は公式ページのDeveloper Guideを参照
https://wiki.openwrt.org/doc/playground/developer

"Hello,World!"のコンパイル

まずは簡単なプログラムからビルドする。

root@ubuntu # cd openwrt
root@ubuntu # mkdir helloworld
root@ubuntu # cd helloworld

適当に作業用ディレクトリを作成し、その中にc言語のプログラムを作成

#include <stdio.h>
int main(void)
{
        printf("Hello World\n");
        return 0;
}

このコードをコンパイルするのだが、Host環境のgcc(/usr/bin/gcc)でコンパイルしてはいけない。
今回はSDKの中にあるgccコンパイルを実行する。

root@ubuntu # ../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc -o helloworld.o helloworld.c
root@ubuntu # ls
    helloworld.o helloworld.c 
root@ubuntu # ./helloworld.o
    -su: ./helloworld.o: cannot execute binary file: Exec format error

出来上がったファイルをHost環境で実行するとformat errorで実行できない。 これはOpenWRT環境で動くファイルなので当然である。 出来上がったファイルをOpenWRT化されているルータに移す。

root@ubuntu # scp helloworld.o root@192.168.1.1:

OpenWRTルータ内でファイルを実行

root@OpenWRT # chmod a+x helloworld.o
root@OpenWRT # ./helloworld.o
     Hello World

実行できた。

Hostapdのコンパイル

OpenWRTで使われていたhostapdは最新versionでは無く、hostapd_cliも使えない。
何か開発しようとすると使い勝手が悪いので、今回は最新版のhostapdをOpenWRT上で動かせるようにコンパイルを行う。

hostapdをダウンロードして解凍。わかりやすいようにopenwrtディレクトリ配下に入れておく。

root@ubuntu # wget https://w1.fi/releases/hostapd-2.5.tar.gz
root@ubuntu # tar -zxvf hostapd-2.5.tar.gz
root@ubuntu # mc hostapd-2.5 openwrt/hostapd

ほとんどのMakefile

ifndef CC
CC=/usr/bin/gcc
endif
...
...
...

という感じで、明示的にコンパイラを指定しない限りはHostのコンパイラを使用するようになっている。
したがってMakefileがクロスコンパイル環境のgccを読み込んでくれるようにCCを明示しておく。

root@ubuntu # export OPENWRT_HOME=[openwrt直下のディレクトリ]
root@ubuntu # export CC=$OPENWRT_HOME/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc

さて、
これでmakeを実行すればhostapdのコンパイル完了。
というわけにはいかなかった。
hostapdのmakeopenwrt/hostapd/hostapd/直下で行う。

root@ubuntu # cd hostapd/hostapd/
root@ubuntu # make
mips-openwrt-linux-gcc: warning: environment variable 'STAGING_DIR' not defined

まずこんなエラーがたくさん出てくるので、言われているとおりにSTAGING_DIRを設定する。

root@ubuntu # export STAGING_DIR=$OPENWRT_HOME/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2

再びmake

root@ubuntu # make
....
....
  CC  ../src/drivers/driver_hostap.c
../src/drivers/driver_nl80211.c:17:31: fatal error: netlink/genl/genl.h: No such file or directory
 #include <netlink/genl/genl.h>
                               ^
compilation terminated.
make: *** [../src/drivers/driver_nl80211.o] Error 1

やはりというか、途中でとまりました。 クロスコンパイル環境なので、いろいろとファイルが足りないことがある。 今回のようにヘッダーファイルが無いだけならHost環境の/usr/include/などからひっぱてくればよい。
以下のようにssl系とnetlink系のヘッダファイルが無いというエラーがでたので、これらを引っ張ってくる。

root@ubuntu # cp -r /usr/include/netlink/ ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/include/
root@ubuntu # cp -r /usr/include/openssl/ ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/include/
root@ubutnu # cp /usr/include/x86_64-linux-gnu/openssl/opensslconf.h ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/include/openssl/

問題なのは共有ライブラリが無かった場合。

root@ubuntu # make 
.....
.....
../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/../lib/gcc/mips-openwrt-linux-uclibc/4.8.3/../../../../mips-openwrt-linux-uclibc/bin/ld: cannot find -lnl
../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/../lib/gcc/mips-openwrt-linux-uclibc/4.8.3/../../../../mips-openwrt-linux-uclibc/bin/ld: cannot find -lssl
../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/../lib/gcc/mips-openwrt-linux-uclibc/4.8.3/../../../../mips-openwrt-linux-uclibc/bin/ld: cannot find -lcrypto
collect2: error: ld returned 1 exit status
make: *** [hostapd] Error 1

普通このようなエラーが出た場合はapt-getとかでライブラリをとってくれば解決なのだが、クロスコンパイル環境では頑張ってネットからライブラリを探すか、ソースからビルドする必要がある。
ちなみに共有ライブラリは

  • -lnl => libnl.so
  • -lssl => libssl.so
  • -lcrypto => libcrypto.so

というように読み替える。この.soファイル(バイナリファイル)を参照できるようにする必要がある。   libssl.solibcrypto.soはOpenwrt SDKの中に見つかったので、参照できる場所にコピーする。

root@ubuntu # ls -l ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl*
lrwxrwxrwx 1 root root     15 Jul 25  2015 ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl.so -> libssl.so.1.0.0
-r-xr-xr-x 1 root root 381267 Jul 25  2015 ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl.so.1.0.0
root@ubuntu # ls -l ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto*
lrwxrwxrwx 1 root root      18 Jul 25  2015 ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so -> libcrypto.so.1.0.0
-r-xr-xr-x 1 root root 1765806 Jul 25  2015 ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so.1.0.0
root@ubuntu # cp ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl.so.1.0.0 ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/lib/
root@ubuntu # cp ../../staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so.1.0.0 ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/lib/
root@ubuntu # cd ../../staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/lib/libcrypto.so.1.0.0
root@ubuntu # ln -s libssl.so.1.0.0 libssl.so
root@ubuntu # ln -s libcrypto.so.1.0.0 libcrypto.so

共有ライブラリは新しいバージョンの.soファイルにリンクする形になっているので、ここでも同じ形式で管理するのがよい。

libnl.soは見つからない。調べてみると、OpenWRT自体libnlは以下のライブラリしか扱っていないらしい。 Name Size Description libnl-core 37K Common code for all netlink libraries libnl-genl 8K Generic Netlink Library Functions libnl-nf 25K Netfilter Netlink Library Functions libnl-route 91K Routing Netlink Library Functions

libnl-3を使ってもコンパイルが失敗する。 仕方が無いので、libnlのversion1のソースをダウンロードしてコンパイルすることにする。

root@ubuntu # wget https://www.infradead.org/~tgr/libnl/files/libnl-1.1.4.tar.gz
root@ubuntu # tar -zxvf libnl-1.1.4.tar.gz
root@ubuntu # cd libnl-1.1.4/
root@ubuntu # ./configure
root@ubuntu # make 

これもちゃんとクロスコンパイル環境のgccコンパイルする。 出来上がった.soファイルをその他2つと同じようにSTAGING_DIR/usr/lib/の中に入れて再びmakeをすればOK。
あとは出来上がったhostapdhostapd_cliをOpenWRTルータに移して実行できる。

結構長かったけど、お疲れ様でした。

makeファイルをデバック

makeファイルをデバックしたいときはこんな感じでコンソールに出力できる。
読み込んでいるライブラリとかをまとめて確認したいときは便利。 dummy := $(shell echo 表示したい内容 1>&2)