BitVisorのコーディングスタイル


BitVisorのコーディングスタイルについて、特に文章化されているわけではないですが、なんとなく決まりがあるようです。以下、BitVisorのソースコードを一部抜粋しながら紹介します。

ソースコード全体は以下のサイトで閲覧できます: https://bitbucket.org/bitvisor/bitvisor

Makefile

Makefileについては何かややこしい内容になっていますが、基本はGNU Makeとbmake (NetBSD make)での正常なビルドを目指したものになっているようです。しかしながら、似て非なる両者への対応を目指した代償は大きく、例えばMakefile.configには以下のような奇妙な記述があります。

Makefile.config
gcc_support_64 := \
        $(shell $(CC) --target-help | grep -q x86_64: && /bin/echo -n 1 || /bin/
echo -n 0)
gcc_support_64 != $(CC) --target-help | grep -q x86_64: && /bin/echo -n 1 || /bi
n/echo -n 0

同じコマンドが2回? 実は$(shell command)はGNU Makeが長年対応しているもので、!=はNetBSD makeが長年対応しているもの、しかしながらGNU Makeはバージョン4.0で!=にも対応してしまいました。それでMakefile.buildでは記述を変更しなければならなくなりました。

Makefile.build
-m!=echo b
-m ?= g
+make-detect := b$(shell echo g)
+m-b := b
+m-bg := g
+m := $(m-$(make-detect))

この謎の変数mは、ファイル名を選択する部分で使われています。

Makefile.build
bobjs-1-name := $(bins-1:%=%-objs)
bobjs-1-b := $(bobjs-1-name:%=$(%))
bobjs-1-g := $(foreach i,$(bobjs-1-name),$($(i)))
bobjs-1 := $(bobjs-1-$(m))

GNU Makeはforeachで、NetBSD makeは%を使用... なお、NetBSD makeではあまりテストされていないので、ビルドできない部分もあるかも知れません。FreeBSDではmakeに-jオプションをつけないと (なんと-j1でもよい) 正常にビルドできないというような現象もありました。特に最近の変更ではNetBSD makeが完全に無視されている部分も...

結局コーディングスタイルの話になっていないのでこのくらいにしましょう。

C

Cのコードは大雑把には以下のような感じ?

  • タブは8桁、関数の引数等で折り返しが必要な場合はタブとスペースを組み合わせて位置を合わせる
  • 関数定義は関数名の前で改行 (grep用)
  • 関数定義・関数呼び出しともに関数名の後ろにスペース
  • if文等のキーワードの後ろにもスペース
  • 79桁までで折り返す (守られてないところもある)
  • 関数定義の { は単独の行に、それ以外のif文等で使われる { は同じ行に
  • } は単独の行に
  • 16進数は0xを小文字、その後ろを大文字に
  • switch-caseのインデントはswitchとcaseを同じ深さに、ラベルがある場合はラベルも同様
  • 行末にスペースやタブを置かない
  • if文等の後ろの文が1文なら { } を省略してもいいし、してないところもある (適当)
  • コメントを含めUS-ASCIIのみ使用
  • ,の後ろや演算子の前後には1つ以上のスペース
void
func (int hoge, int foo)
{
        switch (hoge) {
        case 1:
                func (2);
                goto x;
        case 2:
                printf ("a\n");
                break;
        case 0xA:
                break;
        default:
        x:
                printf ("%d %d\n",      /* comment */
                        hoge, foo);
        }
}

どこかFreeBSD風ではありますが、関数名の後ろにスペースが入るのはGNUスタイル風ですね。なお、インデントの深さや、タブとスペースを組み合わせたインデントは、GNU Emacsで"bsd"スタイルを用いるとだいたいぴったりになるようです。79桁の折り返しも、80桁の幅の端末でGNU Emacsを使用している時に折り返しされない桁数みたいです。そういえば行末のスペースやタブも、GNU Emacsでインデント付き改行を入れると自動的に削除されますね。はい。

なお、こんな感じのスタイルになってるっぽいのは、boot, coreやdriversディレクトリー等で、idmanやvpnといったディレクトリーの下には全く異なるスタイルのファイルが大量に入っています。結局書いた人次第で、全体としてあまり統一はされていなさそうです。

シェルスクリプト

boot/loader/install.shにはbashスクリプトが入っています。

  • タブの桁数は何桁にしても読める
  • [コマンドは使わずtestコマンドを使用
  • case文はinの後ろで改行したりしなかったり
  • case文の;;は単独ではなく文末につける
  • ifwhileのコマンドの後ろでも;は使わず改行してthendoを書く
  • 基本的には昔ながらのshを意識した風でローカル変数などは使われていないが、POSIXの$(...)や、計算式の$((...))が積極的に使われていて、8進数を扱う関係でbashスクリプトにしたらしい

他に、作業用のcore/replace.shというシェルスクリプトもあります。こちらは昔ながらのshスクリプトで、edコマンドでソースファイルに編集をかけていくようです。今時はsedでやる内容っぽいです。こっちではfor文のdoの前に;が使われていて、結局スタイルは適当なのでは...

変数名

変数名も特に統一されているわけではなさそうです。以下のような楽しい変数名も。

core/cpu_interpreter.c
        i8 tmp1;
        i16 tmp2;

テンポラリー1と2!

core/keyboard.c
        u8 gomi;

どう見てもゴミです。

core/time.c
        u32 a, b, c, d;

a, b, c, d, 何かと思いますが、CPUID命令が情報を返すレジスターの名前eax, ebx, ecx, edxを表しているようです。

core/uefi.c
uefi_guid_cmp (EFI_GUID *p, EFI_GUID *q)
{
        u64 *pp, *qq;

ポインターp, q, pp, qq, どう見てもポインターです。ま、コンペアですし、この後ろの関数本体は5行しかないですし、別にいいでしょう。

process/lib/lib_mm.c
free (void *m)
{
        int *p, *q, len;

ポインターm, p, q, この後ろに30行ほどの関数があります。どう見ても...