busyboxのKbuildについて

Linuxカーネル、busybox、buildrootではKbuildというコンフィグ設定のフレームワークが使用されています。

今回はbusyboxのkbuildの使い方について記載します。

 

1. Kbuildのメリット

Linuxカーネル、busybox、buildrootは大量に設定項目が存在します。その設定項目に沿って、どのファイルをビルドするか、マクロの値はどうなるかが変わっていきます。その結果、生成されるバイナリが変わってきます。

Kbuildを使わなかった場合はMakefileが複雑になりがちです。 例えば以下のファイルがあるとします。

$ ls
bye.c  hello.c  Makefile  print.c  print.h

print.cの内容は以下の通りです。 print関数を定義しており、DEBUGというマクロが定義されているかいないかでプレフィックスに<debug>をつけて文字列を出力する場合とつけないで文字列 を出力する場合に切り替えます。

#include <stdio.h>
 
#ifdef DEBUG
void print(const char *text)
{
  printf("<debug> %s\n", text);
}
#else
void print(const char *text)
{
  puts(text);
}
#endif

print.hの内容は以下の通りです。print.cで定義した関数を参照できるようにします。

#ifndef __PRINT_H
#define __PRINT_H
 
void print(const char *text);
 
#endif /** __PRINT_H */

hello.cの内容は以下の通りです。print関数にhelloという文字列を渡します。

#include "print.h"
 
int main(void)
{
  print("hello");
  return 0;
}

bye.cの内容は以下の通りです。print関数にbyeという文字列を渡します。

#include "print.h"
 
int main(void)
{
  print("bye");
  return 0;
}

Makefileの内容は以下の通りです。hello.cとprint.cを用いたプログラムとbye.cとprint.cを用いたプログラムを生成する為にhelloというターゲットとbyeというターゲットを作成します。

hello:
        $(CC) $(CFLAGS) hello.c print.c -o hello
 
bye:
        $(CC) $(CFLAGS) bye.c print.c -o bye
 
clean:
        rm -rf hello bye

DEBUGを無効にする場合には以下のようにします。

$ make hello
$ ./hello
hello
$ make bye
$ ./bye
bye

DEBUGというマクロを有効にする場合は以下のようにします。

$ make hello CFLAGS=-DDEBUG
$ ./hello
<debug> hello
$ make bye CFLAGS=-DDEBUG
$ ./bye
<debug> bye

hello.cとbye.cの切り替え、冗長なprint.cの記述、CFLAGSのDEBUGの設定と、単純な場合でも複雑になりがちです。大量の設定項目がある場合はMakefileが膨大になります。

Kbuildはこれらのファイルの取捨選択とマクロの設定方法を提供するフレーム ワークです。Kbuildを用いることでMakefileがコンパクトになり、ビルドする際にどの設定が有効になるかが理解がしやすくなります。

2. 使い方

Kbuildはmakeコマンドにターゲット名を指定することで使用します。busyboxで利用可能な主なターゲットは以下の通りです。

Target Abstract
make config CUIベースの設定。make menuconfigの方が良い。
make xxx_defconfig デフォルトコンフィグ。後述。
make menuconfig Ncursesベースの設定。後述。
make oldconfig CUIベースの設定。後述。

その他のターゲットはmake helpで確認できます。

2.1. .configとinclude/autoconf.h

.configはmake %configでの結果を保存するファイルです。さらにinclude/autoconf.hに.configの内容が転写されます。 include/autoconf.hは$(CC) -include include/autoconf.hのようにコンパイルコマンドと一緒にインクルード指定されます。

2.3. make xxx_defconfig

configsディレクトリ配下のxxx_defconfigを.configに反映します。例えば、 configs/freebsd_defconfigの場合、make freebsd_defconfigで反映できます。 make freebsd_defconfigとcp configs/freebsd_defconfig .configはほぼ等価です。'ほぼ'というのは、xxx_defconfigにて指定されるべき設定項目が指定されていない場合にmake xxx_defconfigを実行した場合は自動的に設定される のに対し、cp configs/freebsd_defconfigの場合は自動的に設定されません。

ソースツリーが更新された際に、xxx_defconfigの内容が、実際の設定項目とマッチしないことで、指定されるべき設定が指定されていないケースが発生します。

busybox-1.22.1では以下のデフォルトコンフィグが存在します。

android_defconfig
android2_defconfig
android_ndk_defconfig
freebsd_defconfig
cygwin_defconfig
TEST_nommu_defconfig
TEST_noprintf_defconfig
TEST_rh9_defconfig

2.4. make menuconfig

Ncursesベースのインターフェースを提供する設定です。.configが既にある場合はそれに乗っ取って設定項目を表示します。NcursesなのでSSH経由でも利用可能です。以下はSSHで接続したLinux上でmake menuconfigを実行した画面です。

make menuconfig
make menuconfig

2.4.1. 操作方法

make menuconfigでは以下のキーを使います。

Key Abstract
ARROW UP 設定項目のカーソルを上へ移動
ARROW DOWN  設定項目のカーソルを下へ移動
ARROW RIGHT <Select> <Exit> <Help>のカーソルを右へ移動
ARROW LEFT <Select> <Exit> <Help>のカーソルを左へ移動
SPACE コンフィグのON/OFF
ENTER 設定項目グループへ移動
ESC ESC 元の設定項目グループへ移動、またはセーブへ。<Exit>と等価。
h 設定項目の詳細を表示
/ 設定項目のキーワード検索

'h'キーの詳細画面は以下の通りです。

make menuconfig detail
make menuconfig detail

セーブ画面は以下の通りです。トップの設定画面でESCを2回押す、あるいは<Exit>を選択すると表示されます。

2.5. make oldconfig

アップデートされたソースツリー(あるいは逆に版数が古いもの)に対して、 以前のソースツリー用の.configを用いる場合、設定項目の違いによる不整合が起こる場合があります。
make oldconfigは設定項目で不整合があるものを一つずつ確認し、設定し直すことが可能なターゲットです。

また、不整合がある.configでmake menuconfigを実行した場合、自動的に設定が反映されます。

3. コンフィグのカスタマイズ方法

実際にdefconfigにエラーがあった場合の修正手順を示します。 busybox-1.22.1のandroid_ndk_defconfigを用いた場合、以下のエラーがあります。

  CC      coreutils/touch.o
coreutils/touch.c: In function 'touch_main':
coreutils/touch.c:171:21: error: 'lutimes' undeclared (first use in
this function)
    (opts & OPT_h) ? lutimes :
                     ^

ソースコードの該当箇所は以下です。ENABLE_FEATURE_TOUCH_NODEREFという設定が有効な場合に実行されるコードのようです。

#if ENABLE_FEATURE_TOUCH_NODEREF
                        (opts & OPT_h) ? lutimes :
#endif

make menuconfigの'/'キーでFEATURE_TOUCH_NODEREFを検索してみます(ENABLE_というプレフィックスはFEATURE_TOUCH_NODEREFが有効な場合につくプレフィックスです)。

以下の設定を無効にしました。

結果、coreutils/touch.oはビルドできるようになりました。

  CC      coreutils/touch.o
  CC      coreutils/tr.o

4. まとめ

busyboxのkbuildについて簡単にまとめてみました。Linuxカーネルや buildrootについても若干の違いはあるものの、同様の手順でカスタマイズで きるかと思います。