2012年8月4日土曜日

インライン関数まとめ

2012年8月1日水曜日

Linux のコードが FreeBSDに

FreeBSD のことはよく知らないのですが、FreeBSDのソースをダウンロードしてくると、Linuxと同じようなファイルが含まれています。


ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/9.0-RELEASE


からsrc.txzを取ってきて、解凍すると、
usr/src/sys/ofed/include/linux 以下に
Linux Kernel の include/linux とそっくりなファイル群があります。


ディレクトリ名からして、Linux の方が本家だと想像します。
Linux は GPLライセンス, FreeBSD は BSDライセンスなので、こんなことできるんですかね?

FreeBSDが勝手にLinuxをコピーしているのか、それともLinux Communityに許可もらったのか、事情はよくわかりません。

include/linux/ 以下には他のソフトにもそのまま転用できそうな部品になるコードが結構ある。

たとえば、
include/linux/kernel.h に含まれる container_of マクロ。
include/linux/list.h の連結リストの関数群などなど。

自前のソフト開発で、Linux からコードをコピーするとGPL汚染すると思いますが、FreeBSDに入っている同等コードをコピーすれば、BSDライセンスとして扱ってよいということでしょうか。
企業なんかだと、コピー開示義務があるかどうかの違いは結構大きいと思います。

Linux ライクな autoconf.h を簡単に作る

Linux の Makefile においては、.config ファイルの内容から
include/config/auto.conf

include/generated/autoconf.h
が作られる。

前者はすべての Makefile から include され、
後者は -include include/generated/autoconf.h としてすべてのCのソースに渡される。

Makefile でも Cのソースでも、同じ設定内容を参照できるようにするというアイデアは素晴らしいと思う。

自前のソフトでも同様のことをしたいが、Linux の scripts/kconfig/conf を使うほどでもないという場合、以下のように make の簡単なコードでほぼ同等のことをできる。


Makefile の実装例:

include .config


auto.conf: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo $v='$($v)';))) > $@


autoconf.h: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo \#define $v $(if $(filter y,$($v)),1,'$($v)');))) > $@





例えば、
CONFIG_FOO=y
CONFIG_BAR="abcdef"
CONFIG_BUZ=0x100
# CONFIG_QUX is not set.

という内容の .config を食わせてみる。

実行結果は以下の通り。

$ make auto.conf
$ make autoconf.h
$ cat auto.conf
CONFIG_FOO=y
CONFIG_BUZ=0x100
CONFIG_BAR="abcdef"
$ cat autoconf.h 
#define CONFIG_FOO 1
#define CONFIG_BUZ 0x100
#define CONFIG_BAR "abcdef"



sed などで、 .config を parse してもよいのだが、make の .VARIABLES に定義済み変数が全部入っているので、そこから CONFIG_ で始まるものを抽出すれば簡単である。

.config 中で =y のものは、 autoconf.h では 1 に define される。

本家 Linux では =m のものは autoconf.h の方では (変数名)_MODULE が定義されるが、今回のサンプルには実装していない。

make の ifdef はわかりにくい

シェルにおいて
$ FOO=
とすると、シェル変数 FOO は空ではあるが、定義はされている。
変数 FOO を未定義にするには
$ unset FOO
としなければならない。
つまり、シェルスクリプトで、「変数が空」であることと、「変数が未定義」であることは明確に違う。

一方、make においてはこのあたりが紛らわしいというか、非常にわかりにくいと思うので、整理しておきたい。



make には ifdef という構文があるが、これの挙動を見てみる。

(実験1)
以下の内容の Makefile を用意する。


FOO=

all:
ifdef
@echo FOO is defined.
else
@echo FOO is NOT defined.
endif




実行すると以下のようになる。

$ make
FOO is NOT defined.



FOO=
のように、空文字を代入した場合、 ifdefFOO を未定義だと判定した。

なるほど〜、makeにおいては
空の変数は未定義の扱いになる。
そして、make には unset がないから、変数を未定義に戻すには、空文字を代入すればいいんだ、と理解したくなるかもしれない。
だが、これは違う。


(実行2)
次の内容の Makefile を用意する。


FOO=


FOO ?= 1
BAR ?= 1


all:
@echo FOO = $(FOO)
@echo BAR = $(BAR)

この実行結果は以下のようになる。
$ make

FOO =
BAR = 1


?= というのは、変数が未定義の時のみ、右辺の値を代入してくれる。
実験結果を見ると、
?=BAR は未定義と判定したが、FOO は定義済みと判定したことになる。


(実験3)
以下の内容の Makefile を用意する。

FOO=

all:
@echo $(filter FOO, $(.VARIABLES))

実行結果は
$ make
FOO

となる。
.VARIABLES という makeの変数には、使用中の変数が全部入っている。
大量の変数が入っているのだが、その中に FOO も含まれていることがわかる。
つまり、 .VARIABLES には中身が空の変数も含めて、定義済みの変数がリストされている。


(実験1)〜(実験3)からわかることは、
makeにおいても、「変数が空」であることと「変数が未定義」であることは区別している。
(ただ、シェルと違って、いったん定義された変数を未定義に戻すことはできない。)
?= は変数が「未定義」であれば右辺値が代入される。
注意しておきたいことは、(実験1)からわかるように、 ifdef は「定義されているか」を判定するのではなく、「空でないかどうか」を判定するものだ。
これは、ひじょーーーーーに紛らわしい。
この ifdef の仕様は失敗じゃないの?と思う。

つまり
ifdef FOO
ifndef ($(FOO),)
と同じなのだ。

だから、 ifdef 自体、別になくても構わないし、私は使わない。
ifndef ($(FOO),)
を使うほうが、誤解がないから。