2013/11/28(Thu)
○[386BSD(の子孫)ソースコードシリーズ (334)][な阪関無] sys/cdefs.hとは何ですか? (その13)
@前回まで
そりゃ*BSDみたいな世界で3人しか興味ない話で長文書くより、Linusが中指立てた話をちょこっと書く方がウケるよね
笛吹おじさん「おっ、次は俺の出番かな」
一つだけ笛吹おじさんネタをしておくと、POSIXの名付け親はストールマンなんだよね(ほんとにどうでもいい) *1。
@__KERNEL_RCSID(), __KERNEL_SCCSID(), __KERNEL_COPYRIGHT() マクロ
こいつはNetBSD-1.4で導入されました。えーっと今1.1~1.3までの変更を取り上げてるんですが 現在の実装は、前回までに説明した__RCSID(), __SCCSID(), __COPYRIGHT() マクロと実装は identicalなので先に説明しときます。
128 #define __KERNEL_RCSID(_n, _s) __RCSID(_s)
129 #define __KERNEL_SCCSID(_n, _s)
130 #define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s)
__KERNEL_({R,SC}CSID|COPYRIGHT)()はそのまんま__({R,SC}CSID|COPYRIGHT)()を呼んでるだけです。
まぁ名前からして __KERNEL_* は kernel つまり src/sys の下で使うんだろうなというとこは判りますが、マクロの第一引数 _n が使われることなく捨てられてます、ナンデ!?ニンジャナンデ!?
これはですね、前々回 __RCSID()の説明でしたrcsidが多重定義エラーになる問題と関連しています。
これの解決法として、FreeBSDでは __FBSID()マクロの中で、事前定義マクロ __LINE__ *2を使うことで
static const char __rcsid_行番号[] = "$FreeBSD: メタデータ $";
とマクロを展開させて、シンボルに行番号を含めることで重複を避けてたのも前々回説明しました。
まーFreeBSDも力技やなとは思うんですが、NetBSDはただのアホでした。
さっきの謎の引数、_n に自分で番号入れてシンボルの重複を避けてたわけだ。
#ifndef HOGE_H_
#define HOGE_H_
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hoge.h,v $");
#include <stdio.h>
static __inline void
hello()
{
puts("hello");
}
#endif /*HOGE_H*/
インクルードされる側の _n = 0
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: fuga.c,v $");
# include "hoge.h"
int
main(void)
{
hello();
return 0;
}
する側の _n = 1 にしておけば
static const char rcsid1 = "$NetBSD: hoge.h,v $";
static const char rcsid0 = "$NetBSD: fuga.c,v $";
みたいにマクロ展開されて重複避けられるわけですが、この番号をワザワザ手動ふってくとかもうねアボガド…
…わかった この話はやめよう ハイ!! やめやめ、__pure2/__dead2 マクロに続いて __KERNEL_* も FreeBSD と比べて クソザコナメクジな実装だったね(ゲッソリ)。
ということでもはや__KERNEL_({R,SC}CSID|COPYRIGHT)() には存在理由ないので消せばいいと思うよ。そもそも src/commonを導入して、kernelとuserlandのコードを共有してるんだし
#include <sys/cdefs.h>
#if !defined(_KERNEL) && !defined(_STANDALONE)
__RCSID("$NetBSD: ... $");
#else
__KERNEL_RCSID(0, "$NetBSD: ... $");
#endif
とかいちいちifdef増やして「汚いコードだなアッー」ってのは止めましょうよ。
@__RENAME() マクロ
これも過去の チラシの裏で詳しく説明していますので割愛しますね。
ちなみに最近のNetBSDでは nonaka@さんのおかげで ELF symbol versioningをサポートするようになりましたので、将来的には __RENAME() マクロも deprecated になるはずです。
…ですがもう2年経っても libc の build system がそれに対応する兆候すらないわけで。まぁ スローロリスの歩みのようなNetBSD時間なので、JR横浜駅工事とどっちが早く完成するかは知らん。
どーでもいいこと補足しておくなら__RENAME()の実装は
#ifdef __lint__
#define __RENAME(a) __symbolrename(a)
#else
lint(1)の場合、__RENAME(a) → __symbolrename(a)にしてますが、これは別にそういう名前の関数があるのではなくscan.lの中でCの キーワード扱いになってます。
/*
* Keywords.
* During initialisation they are written to the symbol table.
*/
static struct kwtab {
const char *kw_name; /* keyword */
int kw_token; /* token returned by yylex() */
scl_t kw_scl; /* storage class if kw_token T_SCLASS */
tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */
tqual_t kw_tqual; /* type qual. fi kw_token T_QUAL */
u_int kw_stdc : 1; /* STDC keyword */
u_int kw_gcc : 1; /* GCC keyword */
} kwtab[] = {
...
{ "__symbolrename", T_SYMBOLRENAME, 0, 0, 0, 0, 0 },
...
};
__ではじまる実装依存のキーワードとはいえ、これまでコンパイラやツールの違いを吸収する役目だったsys/cdefs.hのはずなのに、 逆に今度はsys/cdefs.hが定義するマクロの為にツール側を改造するってもう支離滅裂だよね、ugly hack以上の何物でもない。
立浪「(NetBSDの)そういうとこがあかんねん(ボコー」
@そもそもsys/cdefs.hとは何ですか?がコロコロ変わるんですが…
すでに4.3BSD Net/2 から NetBSD1.3 になるまでに
- K&R vs ANSI/ISO-C の文法の差を吸収するラッパー
- → pcc vs gcc のコンパイラの差を吸収するラッパー
- → sccs vs rcs/cvs のソースコード管理の差を吸収するラッパー
- → ABI(アプリケーションバイナリインタフェース)において後方互換性を維持するトリックを提供する
のように節操なく役割が増やされています。 おかしい、こんなことは許されない。
最初にも書いたようにsys/cdefs.hには移植性はありません、ですのでここに機能を増やしてくのはデザインとして下の下ゲゲゲゲッワイ(加齢臭)下策なんだけどねぇ…
なもんで
- すでに時代的に意味が失われ不要になってるマクロはさっさと消して身軽になる
- せめてバージョン管理の話だけでも別のヘッダにした方が…
- ABI周りもなぁ…
という感じ。
@次回予告
NetBSD 1.3までの話が終わったので、次回はどこまでにしましょうかねぇ。zzz