CUJJ#8/'90.5.18 発売号掲載
今年前半の GNU の大きなイベントである (USENIX で開催される)GNU BOF が終わり、ようやく落ちついた。プロジェクト GNU はようやくここに来て、GNU カーネルに取り掛かろうとしている !
今回から GNU の歴史を少しずつ散策してみたい。一般に歴史を紐解くとなると、成熟した分野に限られる。プロジェクト GNU はまだまだ成熟した分野とはいい難い。しかし、プロジェクト GNU が始まって 6 年目、ここでこれまでの歴史を、さまざまな出来事が忘れ去られる前にまとめておくことには意義があるだろう。
以前は、GNU の歴史を調べて紹介しようとは思わなかった。確かにプロジェクト GNU の歴史を調べる上で学ぶことはいくつかあるだろう。しかし、歴史をたどることは、特にコンピュータ科学のような未成熟な分野に関しては、基本的に「後ろ向きの作業」になるであろう。こういったコラム自体もそれほど生産的ではないかもしれない。クヌース先生の本★1 にも (Jeff Ullman の講演の中の引用として) 次のような格言が出ていた。
仕事ができるやつは仕事をする。仕事のできないやつが教師になる。教師にさえなれないやつは芸人になる。
比喩としては非常にきついが、これは一面の真理をついているかもしれない。このコラムを書くことが教師としての役割も担っているとは思わないが……。
さて、なぜ歴史を調べるようになったかというと、ボストンにいた時に「gcc(GNU C コンパイラ) がなぜ作られたのか」「どうしてこういう構造になったのか」を知りたくなったからである。
「果たして、Richard Stallman 1 人で gcc を作成したのだろうか ?」この回答の一部は gcc のソース・コードのコメントを見れば多少わかる。さらにソース・コードと共に提供される ChangeLog というファイルを覗けばある程度、推測がつく。これには誰がどのファイルのどの関数を修正したかが記述されている。
そのために資料を少しずつ集め、帰国してからプロジェクト GNU の紹介のたびごとにその資料をまとめてきた。プロジェクト GNU が開始される前が次に話す「プロジェクト GNU 前夜」である。
ちなみに、この ChangeLog というファイルについて説明しておこう。これは、プロジェクト GNU で一般的に用いられる修正履歴を記録しておくファイルで、GNU のツールには全てこの ChangeLog というファイル名を統一して付け、作成している。
このファイルの作成を支援する GNU Emacs 用のライブラリ (ライブラリを書くための Lisp に似た言語「GNU Emacs Lisp」(通称、elisp[いーりすぷ] で書かれている) が Free Software Foundation からの標準配布テープに入っている。時間と修正者名、括弧の中にはその人のログイン名と修正を行なったホスト名が入る。ここまでは GNU Emacs でサポートし、それに続く修正内容は自分で入れる。以降に示す例は GNU Emacs の C 言語のソース・ディレクトリに入っている ChangeLog である。
Sun Aug 13 14:50:28 1989 Richard Stallman(rms at hobbes.ai.mit.edu) * xfns.c(Fx_proc_mouse_event,Fx_get_mouse_event): Set new var Vx_mouse_abs_pos,for sake of xmenu.c. (syms_of_xfns):Make this a Lisp variable. * x11fins.c(Fx_get_mouse_event):Fix like Fx_proc_mouse_event.
プロジェクト GNU の特に前夜は文字通り rms の個人史である。さらにプロジェクトが立ち上がってからしばらくの間も、rms の個人史とオーバーラップする場面が多い。
「ハッカー英語辞典」2 によると、趣味は国際フォークダンス、フライト (飛行機に乗って空を飛ぶことだろう)、料理、物理学、リコーダ、言葉遊び、SF 小説ファンとのこと。ちなみに飛行機 (シングル・エンジン) のライセンスを持っている。
プロジェクト GNU 歴史年表 * 未確認
年 代 出 来 事 1953(*) Richard M.Stallman がニューヨークのマンハッタンに生まれる。 1970 IBM NY Research Center でアルバイトをする。 1971 MIT の研究員となる (〜'84 まで MIT に勤める '71〜'81 まで PDP-10 を使用していた)。 1974 ハーバード大学の物理学科を卒業。 Teco(拡張性のあるエディタ) の改良と Emacs 開発を開始する。 1975 Emacs/ITCS(Twenex OS) の移植。 Teco の改良をしながら Emacs を保守する。 膝を故障した際にリコーダ演奏コースをハーバード大学で習得する。 1976 Teco を改良 (名前付き関数) する。 Emacs の配布 (最初のバージョン) を開始する。 1977 Twenex(OS の名前) 版 Emacs を作成した。 1979 James Gosling が Unix Emacs を CMU で開発する。 これは Gosling Emacs と呼ばれる。 Unipress Emacs の元にもなった。 1982〜83 Symbolics マシンを調べて LMI 社へ対応する。 1983 MIT で LMI を使わなくなったことと、 LMI が一人立ちしたことから、LMI 対応を打ち切る。 共有精神を取り戻すべく GNU プロジェクトを思い立つ。 1984 前半 MIT を辞める。それまで使っていた MIT の部屋は 使いたかったら使ってよい、とのことで継続して部屋を使用。
Richard が生まれたのは 1953 年であるから、今年 37 才。高校生 (16 才) のころ、IBM の研究所でアルバイトをした時にコンピュータに初めて触れた。★3 10 年間ほど汎用計算機 (DEC PDP-10) をメインに使っていたことがわかる。◆1
Richard が MIT の研究員時代にやった仕事で Emacs 以外に興味深い業績は、Guy Steel Jr.(おそらく Lisp の処理系を作っている Lucid 社から、コネクション・マシンを作っている Thinking Machine 社に移ったという人である)、Sussman 教授らと世界で初めての 1 チップ Lisp マシンを作ったことだ。それらは Scheme 79 と Scheme 81 という名前で、LSI のマスク・パターンの写真が Sussman 教授の MIT の部屋の前にある。それには開発に参加した時の名前が左上すみに書いてある。両方のマスク・パターンに rms の名前があった。★4
最新の GNU ソフトウェアを置いてある MIT の prep マシンに standard.text というファイルが置いてある。これには GNU ソフトウェアを作成する上での注意点やコーディングの規則が書いてある。Unix のバグから移植性をどうとらえているかまでがわかる。その日本語訳をここに示す。◆2
GNU の仕事のために、あるいは GNU の仕事をしている間は、どのような状況でも Unix のソース・コードを参照してはならない (これはあらゆる所有権のあるプログラムに関して当てはまる)。
Unix のプログラムの内部構造の漠然とした知識がある場合、Unix の代替品を作成できない、ということはない。全く異なるソースプログラムを作成実現して、代替品を構成すること。そうすれば最終的に、オリジナルの Unix 版とは無関係の全く異なる部分から構成されるものになる。
例えば、Unix のユーティリティは一般にメモリを極力使わないように設計されている。そうしないで処理速度を上げたいプログラムならば、それは全くその Unix ユーティリティとは異なったものになる。メインメモリ上に全ての入力ファイルを展開して、(stdio 構造を使う代わりに) そのメインメモリ上をスキャンできる。Unix プログラムよりも新しく、もっと賢いアルゴリズムを採用した方法を用いること。中間ファイルを使わないこと。2 回のパスではなく 1 回のパスでそれを実行しなさい (我々はアセンブラの中でこのことを実際に行なった)。
また逆に、処理速度ではなく簡潔さを強調してもよい。幾つかのアプリケーションにとって、今日のコンピュータは、さらに簡潔なアルゴリズムを適用するのに十分な性能を備えている。
あるいは一般性を追求すること。例えば、Unix プログラムでは、よく静的テーブルや決まったサイズの文字列を使っているが、これらはある上限を設けてしまう。入力ファイルに null 文字や変な文字が入ってきても扱えるように注意しなさい。拡張性を高めるためにプログラミング言語を設計して、その言語でプログラムの一部を書きなさい。
あるいは、プログラムの一部を独立した有用なライブラリに追加しなさい。または、空きメモリを正確に管理するのではなく、簡単なガーベージ・コレクタを使ったり、obstack のような新しい GNU の機能を使いなさい。
作業中、そのプログラム向けのソース・コードを誰かが寄付してきた場合、採用するに当たって覚書を入手する必要がある。プログラムを寄付した人ひとりひとりに、ある覚書に署名してもらわなければならない。プログラムのタイトルを明確にするためである。代表の作成者 1 人だけでは不十分である。
従って、他の人々から寄付されたソース・コードを我々のソース・コードに追加する前に、我々にご相談いただきたい。そうすれば、我々はその法的文書 (覚書) を入手する手配をすることができる。それから、実際に寄付されたソース・コードを使う我々が、署名入りの文書を受け取った旨をそちらに伝えるまで待ってほしい。
この手続きは、プログラムをリリースする前でも、した後でも適用される。バグを修正するために差分ファイルを受け取り、それが重要の変更な場合には、我々はそのための法的文書が必要である。
2〜3 行の変更ならば法的文書は不要である。というのは、著作権の目的からこれは重要ではないからである。提示された提案全てがアイデアであった場合も法的文書は不要である。例えば、ある問題を別の方法で解決しているケースである。
このようなことは精神上良くないことはわかっている。我々にとってもつらいことである。しかし、このようにして合法文書を入手しなければ、危険な立場になる。例えば、ボランティアの雇い主が著作権放棄に署名しなかった場合はどうするのか ? おそらくもう一度ソース・コードを書き直さなければならないだろう !
本当に最悪の事態は、共に作成したその他のボランティアのことを忘れてしまったという場合である。最終的に我々は、いつの日にか法廷で立ち往生してしまうであろう。2-
ある例外を除いて、GNU 用のユーティリティ・プログラムやライブラリは Berkeley Unix の中のそれらと上位互換があり、ANSI C の機能を使うのならば ANSI C と上位互換を持たせるべきである。
これらの標準が衝突する時は、各々と互換性のあるモードを作成すると便利である。
ANSI C や POSIX はいろいろな種類の拡張を禁じている。どのような方法でも構わないから拡張は自由に行ない、-ansi や -compatible オプションで切り替えられるようにしなさい。しかし、拡張して元のプログラムやスクリプトを破壊するような重大な可能性がある場合は、その拡張は本当の上位互換ではない。そのインタフェースを再設計しなさい。
ユーザだけ (プログラムやコマンド・ファイルとして使わない場合) が使う機能で、Unix 上でうまく実現されていない場合は、全く異なるもので相対的に何かより良く、完全にしかも自由に置き換えてみなさい (例えば、vi は Emacs に代替できる)。しかし、互換性のある機能をも備えることは良いことである (フリーな vi のクローンがあるから、我々はそれも提供している)。
Berkeley Unix に役に立つ機能がさらにあれば好都合である。Unix にはないプログラムがさらにあれば役に立つかもしれないが、我々が最初に求めることは通常、Unix に既に備わっているものの代替品を作成することである。
重要な点として、まず、C の関数の始まりを表す開き大括弧 { を 1 カラム目に入力し、その他の開き括弧や開き丸括弧 ( を 1 カラム目に入力しないこと。ツールによっては 1 カラム目の開き大括弧を見て C 関数の開始と判断しているものがあり、その方法で清書していないコードに対して正しく動作しないからである。
関数定義は、1 カラム目に関数の名前を与えることも重要である。ctags や etags はこれら以外の関数定義を認識することができない。従って、適切なフォーマットはこのようになる。
static char* concat (s1, s2) /* Name starts in column zero here */ char *s1, *s2; { /* Open brace in column zero here */ ... }
これとは別に、我々は次のようなスタイルを好んで用いている。
if (x < foo (y, z)) haha = bar[4] + 5; else { while (z) { haha += foo (z, z); z--; } return ++x + bar (); }
開き中括弧の前やカンマの後に空白があれば、プログラムの読みやすさを向上させることが知られている。特にカンマの後の場合は。
式を複数行に分割する時は、演算子の後ではなく演算子の前で区切りなさい。その正しいやり方を次に示す。
if (foo_this_is_long && bar > win (x, y, z) && remaining_condition)
異なる優先度の演算子を同じレベルで字下げしてはならない。例えば、このように記述してはいけない。
mode = (inmode[j] == VOIDmode || GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j]) ? outmode[j] : inmode[j]);
この代わりに、字下げは入れ子を表すので余分な括弧を使うこと。
mode = ((inmode[j] == VOIDmode || (GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j]))) ? outmode[j] : inmode[j]);
Emacs(訳者注 C モードという C 言語サポート・ライブラリで) はコードを適切に字下げしてしまうので、中括弧を余分に挿入しなさい。例えば、次の字下げは手操作の場合にはうまく行なえるが、Emacs では乱雑 * にしてしまう。
v = rup->ru_utime.tv_sec * 1000 + rup->ru_utime.tv_usec / 1000 + rup->ru_stime.tv_sec * 1000 + rup->ru_stime.tv_usec / 1000;
しかし、一組の中括弧を追加すれば、この問題を (次のように) 解決することができる。
v = (rup->ru_utime.tv_sec * 1000 + rup->ru_utime.tv_usec / 1000 + rup->ru_stime.tv_sec * 1000 + rup->ru_stime.tv_usec / 1000);
do { a = foo (a); } while (a > 0);
(関数内ではない) 論理的な場所で、プログラムを数ページに分割する場合に、フォーム・フィード (^L) を使いなさい。何ページになろうともこの方法で区切れば、プリンタ出力されたページに合わせる必要はなくなる。フォーム・フィードは 1 行に 1 個だけ与えること。
* 訳者注 これを Emacs で入力すると次のようになって見づらくなるということ。
v = rup->ru_utime.tv_sec * 1000 + rup->ru_utime.tv_usec / 1000 + rup->ru_stime.tv_sec * 1000 + rup->ru_stime.tv_usec / 1000;
どのプログラムも、それが何のためのプログラムであるかを簡単に述べた (英語) 注釈で始まること。例えば"fmt--filter for simple filling of text" など。
関数ごとに次の点を記述しなさい。何を行なうか、どのような種類の引数か、可能な限りの引数の値の意味と使用方法について。C 言語の引数の宣言の意味を別な言葉で繰り返す必要はない。使い方について何か標準的でないものがある (例えば、タイプ char * の引数が実際には、文字列の 1 番目ではなく 2 番目の文字のアドレスである) 場合や、例外事項として動作しない可能性のある値 (例えば、改行を含む文字列) の場合は、その旨を注釈しなさい。
また、戻り値があればその意味を説明しなさい。
Emacs の文章に対するコマンドが機能するように、注釈文の終わりの後に空白を 2 つ入れること。また、完璧な文章を書き、最初の単語は大文字で書くこと。小文字の識別子が文頭に来る場合には、それを大文字にしてはならない ! 綴りを変更することは別の識別子にすることである。小文字で文章が始まることに抵抗を覚えるのならば、分けて文章を書きなさい (例えば"The identifier lower-case is……")。
関数の注釈の中で引数名自体を用いて説明するとわかりやすくなる。変数名自体は小文字にすべきだが、変数よりもその値について説明する場合は大文字で書きなさい。つまり、"an inode" よりも"the inode number NODE_NUM" というふうにである。
関数名の前の注釈で関数名をもう 1 度述べるのは、読めばその場でわかるので一般的に無駄である。関数自体が画面の下から消えてしまう場合の注釈は例外かもしれないが。
各静的変数に関する注釈も次のように書く。
/* Nonzero means truncate lines in the display; zero means continue them. */ int truncate_lines;
それぞれの #endif に 1 つずつ注釈を付ける。ただし、入れ子になっていないような短い条件文のケース (2〜3 行程度) の場合は付けなくてよい。
注釈は、その意味を含めて、条件部の終わりまでについて与えるべきである。#else はその条件と続くプログラムの意味の注釈を付けなさい。例えばこのようになる。
#ifdef foo … #else /*not foo*/ … #endif /*not foo*/
また条件が逆になると、
#ifndef foo … #else /*foo*/ … #endif /*foo*/
関数に対する全ての引数を明示的に宣言しなさい。int だからという理由で引数を省いてはいけない。
ソース・ファイルの後ろに出てくる関数や外部関数の宣言を全てファイルの冒頭付近に置くか、あるいはヘッダ・ファイルに置くこと。関数内で外部宣言をしてはならない。
複数行にまたがる 1 つの宣言文で、複数の変数を宣言してはならない。1 行に 1 つずつ新しい宣言を記述しなさい。
int foo, bar;
例えば、上の宣言は次のようにしなさい。
int foo, bar;
あるいはこのように書くこともできる。
int foo; int bar;
(宣言が広域変数ならば、とにかくそれぞれに注釈を付けてから宣言しなさい。)
if 文の中に別の if-else 文がある場合は常に、if-else 文を大括弧で囲みなさい。従って、決してこのように書いてはならない。
if (foo) if (bar) win (); else lose ();
常に、次のように書きなさい。
if (foo) { if (bar) win (); else lose (); }
構造型のタグや変数、あるいは型宣言の両方に同じ名前で宣言してはならない。その代わりに、個々に構造型のタグを宣言し、それを使って変数かまたは型宣言を宣言しなさい。
if 文の条件内で代入文の使用は避けること。例えば、このように書いてはならない。
if ((foo = (char *) malloc (sizeof *foo)) == 0) fatal ("virtual memory exhausted");
その代わりに、このように書きなさい。
foo = (char *) malloc (sizeof *foo); if (foo == 0) fatal ("virtual memory exhausted")
lint の (エラーや警告の) 出力を減らすためにプログラム自体を見づらくしてはならない。例えば、このためにキャストを入れてはならない。null ポインタ (定数) を表す場合、キャストなしのゼロが一番良い。
名前の付け方については、単語の区分に下線を使いなさい。そうすれば Emacs のワード・コマンドがそのような単語に対して有効となる。通常は小文字を使うこと。大文字はマクロ名や列挙型定数で使用する。接頭語の使用は統一した規則に従うこと。
例えば、ignore_space_change_flag のような名前を使いなさい。iCantReadThis のような名前を使ってはならない。
コマンド行オプションを指定しているかどうかを示す変数の名前は、オプションの文字で始めるのではなく、オプションの意味で始まるものにしなさい。注釈には、オプションの意味とその (オプションの) 文字の両方について書きなさい。
/* Ignore changes in horizontal * whitespace(-b). */ int ignore_space_change_flag;
(代入を行なわない) 整数値を使った名前を定義したい場合は、#define よりも enum を使いなさい。◆3
全てのデータ構造を動的に割り当てることによって、どのようなデータ構造の長さ、数に関する長さや個数にも制限を設けてはならない。これにはファイル名や行、ファイル、記号が含まれる。大方の Unix のユーティリティでは、「長い行は警告されずにそのまま切り詰められる」。このようなことは、GNU ユーティリティではあってはならない。
ファイルを読み込むユーティリティは null 文字や、0177 以降のコードを使っている文字、プリンタ出力に現れない文字を取りこぼしてはならない。
エラーを無視する場合を除いて、それぞれのシステム・コールが返すエラー・メッセージを確認すること。失敗した場合、システム・コールが返す (perror や同等のものからの) それぞれのエラー・メッセージを、ユーティリティが出力するメッセージに入れ、さらに (あれば) ファイル名やユーティリティ名をも入れなさい。"cannot open foo.c" や"stat failed" だけでは不十分である。
malloc や realloc で、戻り値がゼロでないかどうか毎回確認しなさい。realloc でこれまで確保していた大きさより小さいサイズを指定した場合でもこのチェックを行ないなさい。あるシステムでは 2 の階乗のサイズにまるめてしまうかもしれないし、少ない領域を確保するように要求すると、違うブロックを返すかもしれないからである。
Unix では、realloc はゼロを与えられた場合にストレージ・ブロックを破壊する可能性がある。GNU の realloc にはこのバグはない。もし失敗した場合は、元のブロックは変更されない。GNU 版ではバグが修正されたという仮定をして差し支えない。Unix 上でプログラムを実行する際、この失敗をおかしたくなければ GNU の malloc を使うこと。
フリーにしたブロックの内容は「自由」に変更されることを予測しなければならない。ブロックから何かを取り出したい場合は、「free」を呼ぶ前にその内容を他の場所にとっておかなければならない。
引数の構文が適切であれば、コマンドの引数を解析するためには getopt を使いなさい。
静的ストレージをプログラムの実行中に変更する場合は、それを初期化するための明示的な C コードを使いなさい。変化しないデータである旨を C 言語で最初に宣言しておくこと。(ファイル・ディレクトリ、utmp、カーネル・メモリのレイアウトのような) 曖昧な Unix のデータ構造に対する低レベルのインタフェースを避けるようにしなさい。ディレクトリ内の全てのファイルを探す必要がある時は、readdir かその他の上位のインタフェースを使いなさい。GNU ではこれらと互換性を持たせるようなサポートを行なう予定である。
GNU のシグナルの扱いは、おそらく BSD のものが強力で使いやすいので、System V のものよりも BSD に似たものになるだろう。
Unix の世界における移植性と呼ばれるものの多くは、いろいろなバージョンの Unix に移植するという意味である。これは GNU ソフトウェアには関係ない。なぜなら、我々のシステムの目的はある 1 つのカーネル (GNU カーネル) 上でのみ動作することだからである。異なる CPU 上で動作する GNU システムの多種にわたる派生物は、異なる CPU 上で動作する Berkeley 4.3 システム (4.3BSD) と似たものになるだろう。
まだ終了していないので、GNU カーネルではどのような機能を提供するのかは未定である。従って、4.3BSD にあるものは使えると仮定しなさい。ただし、より上位の方法 (readdir) がある時に準内部データベース (例えば、ディレクトリの構造) の形式を使ってはならない。
C 言語やライブラリ、カーネルの適切な標準は自由に使うことができる。というのは、我々が既にその標準を実現しているかどうかにかかわらず、それらの機能をサポートする必要があると考えているからである。GNU カーネルや C コンパイラが、サポートしていなかった機能を満たすようになれば、その点は問題ではない。
いろいろな種類の CPU の違い (バイトの順番や配列の制限に関する違い) については常に配慮しておくこと。GNU は 16 ビット・マシンをサポートしたくない。int が 32 ビット以下になる可能性を考慮するために時間を浪費するのは得策ではない。
1M バイトのメモリを使うことを前提にして構わない。そのレベルに達しない限り、メモリの消費を控えようとしてはならない。プログラムが複雑なデータ構造を生成する場合は、メインメモリ上にそれらを展開し、malloc がゼロを返す場合には致命的なエラーを表示するようにしなさい。
複数行を扱うプログラムにおいて任意のファイルを入力として指定可能な場合、メインメモリ上には 1 行のみを展開しなさい。メインメモリ上に展開しきれないファイルを扱うことはそれほど困難ではないので、ユーザはできるはずと考えるからである。
ユーティリティの実行結果が、その実行に使われる名前に依存するようにしてはならない。異なる名前を使っているユーティリティにリンクするのは時に便利であるが、動作を変更してはならない。
その代わりに、実行時のオプションか、あるいはコンパイル・スイッチを使いなさい。あるいは、それらの動作を選択できるようにしなさい。
GNU プロジェクトのマニュアルは Texinfo で記述しなさい。GNU Emacs Info のサブシステム (C-h i、コントロール・キーを押しながら i をタイプする) のマニュアルかそのハードコピーのいずれかを使って、Texinfo マニュアルを参照のこと。
例題用の GNU Texinfo ファイル (例えば、GNU Emacs 配布の man ディレクトリの下のもの) があり、それを参考にしなさい。
上手に書きなさい。「-」で始まる全てのオプションやその動作について説明しなさい。全てのコマンドについて説明しなさい。それらの使用例を示しなさい。使い方やその条件、それぞれの機能がどのような動作をするのかというだけではなく、普通に使った場合の特徴についてユーザに説明しなさい。
先月から今月にかけて次の表のような GNU 関係のソフトウェアがリリースされた。その中で、面白そうなもの 2 つ (Gnuplot と Mach) の概要をご紹介する。
ちなみに、Mach は筆者らのヒアリングでは「マック」と発音している人が多かったが、「マーク」や「マッハ」と言っている人もいた。
ツール名 バージョン リリース日 コメント ----------+------------+-------------+--------------- Gnuplot 2.0 1990/03/13 グラフ作成ツール、次節参照。 GNU から配布されているソフト ウェアではない。 AE 2.0 1990/03/19 GCC(GNU C コンパイラ) をベース にしたソフトウェアで、実行時の 動作解析ツール。GNU から配布さ れているソフトウェアではない。 flex 2.2 1990/03/21 Unix の lex(字句解析自動生成 系) の GNU 版。αリリースである。 Freemacs 1.6a 1990/03/28 IBM-PC 上で動作する GNU Emacs。 MicroEmacs のように機能縮小版 ではなく、拡張性は GNU Emacs により近い。GNU から配布されて いるソフトウェアではない。 f2c - 1990/04/09 Fortran から C 言語へ交換する ツール。GNU から配布されている ソフトウェアではない。 Mach/i386 2.5 1990/04/10 386 を使った IBM PC/AT 互換機 用の CMU Mach カーネルのリリー ス。当然 GNU ソフトウェアでは ない。
Thomas Williams がリリースした Gnuplot の特徴について取り上げる。詳細については、回を改めてドキュメンテーション関連の話題のところでご紹介しようと思う。
Gnuplot 2.0 なるものが 1990 年 3 月 13 日付でリリースされた。もともとは 1986 年に Colin Kelly と Thomas Williams が、いろいろな端末にさまざまな関数やデータ・ファイルをプロットできるように開発したものである。1989 年から 1990 年にかけて GNU TeX や各種 Gnuplot が 1 つに結合され、新しくできたのがこの Gnuplot 2.0 である。
ちなみに Gnuplot には GNU という 3 文字が付いているが Free Software Foundation の GNU には無関係で、偶然の一致のネーミングだそうである。
Gnuplot は Unix や MS-DOS や VMS 上で動作するプロット・ツール、つまりグラフィック・プログラムである。数学関数やデータをグラフなどで視覚的に理解できる点が特徴である。処理結果はグラフィックス端末ではなくても表示可能である。LaTeX のマクロ・パッケージ EEPIC を使って TeX が dvi(TeX の出力ファイル形式で出力装置に依存しない) 形式のデータを生成する。
フリーなソフトウェアである。
カルテシアン座標と極座標のプロットを使う。
ログ目盛りの付いたグラフ
目盛りの自動設定
選択可能な自動スケーリング
複素数のサポート
VMS(DEC のミニコンピュータ VAX 用のオペレーティング・システム) に似たオンライン・ヘルプ
ユーザが関数や変数を定義できる。
C や Fortran、BASIC が提供する全ての組み込み関数
C、その他がサポートする単項やバイナリ全ての演算子
ラベル付けやグリッド、矢印のような多くの清書用の機能
作業環境の保存・ロード機能
コマンド行からの文字修正など
また、Gnuplot で作成されたデータ・ファイルを PostScript 形式のデータに変換するコマンド plot2ps(αバージョン) も 1989 年 7 月 5 日に Richard Murphey がリリースしている。
plot2ps の使用条件は、Free Software Foundation の一般公的使用許諾に則ってフリーに配布することができるようになっている。plot2ps のソース・ファイルには、PostScript のハードコピーだけではなく texinfo 形式のドキュメントも含まれている。詳細は rich@rice.edu まで電子メールにて。◆4
a. USENET のニュース・グループ comp.sources.misc に投稿されるまで待つ。
b. duke.cs.duke.edu(128.109.140.1) マシンから pub/gnuplot.tar.Z を anonymous ftp で入手する。
c. anonymous ftp ができなければ ftp サーバ (BITETP@pucc.princeton.edu) へ、help という単語を入れた電子メールを出す。
d. a〜c で入手できなければ、フォーマット済みの FD と宛名を書いた返信用封筒と切手を次の所まで送り、いつの日か返送されてくるのを待つ。FD は 1.25M フォーマットならば 5.25 インチ 1 枚、720K か 1.44M フォーマットならば 3.5 インチ 1 枚、360K フォーマットならば 5.25 インチ 2 枚を同封すればよい。
GNUPLOT attn: Thomas Williams 48 Lyford Drive#8 Tiburon, CA 94920 U.S.A.
電子メールにて、質問とコメントは pixar!info-gnuplot へ発信し、フォローは comp.sources.d へ投稿していただきたい。
Intel 80386 用の CMU Mach カーネルが、プロジェクト・リーダの Richard F. Rashid 助教授から 1990 年 4 月 10 日付でリリースされたので、その様子を紹介する。
現在、(IBM)AT クローンや Olivetti M386 や東芝 T5200、HP Vectra RS25C、Intel 301、Intel 302 上で動作しているが、ターゲットとなるマシン用にサポートしている / いない仕様は次の通りである。
Intel 80387 ハードウェア浮動小数点演算チップ
AT 互換のバス
WD 1007 互換のディスク・コントローラ。バイナリは 30M バイト、カーネルのソース・コードは 15M バイトある。最低 10M バイトのディスクを確保すべきである。300M バイトの ESDI ドライブで開発している。しかし、ST506 ドライブでも (遅いが) 動く。
Intel iMX-LAN/586 Ethernet ボード (以前は PC586 あるいは ENET 586 と呼ばれていたもの)、あるいは 3cm 501 Ethernet ボード
高密度タイプの 3.5 インチ (1.44M バイト)/5.25 インチ (1.2M バイト) のフロッピー・ディスク
{E,C,V}GA とモノクロのディスプレイ (25 行×80 文字のモード)
Wantek 1/4 インチ 3M のストリーマ (オプション)
内蔵のシリアル・ライン、:COM1(オプション)
マイクロチャネル・バス (IBM PS2/70 や PS2/80、NCR マシン)
SCSI ディスク / テープ
4.3BSD や AT&T の (System V)3.2 のソース・コード・ライセンスが必要とのこと。商用ライセンスが必要な NFS は配布されていない。また、ライセンスとハードウェアの要求事項を満たせば、Mach 2.5 i386 インストレーション・マニュアルを anonymous ftp で wbl.cs.cmu.edu から入手することができる。ファイルは /usr/mach/public/doc にある。
現在、(CMU の) 資源が限られているので、このシステムを広く配布するために他のサイトの募集をしている。CMU の活動負荷をかけないために、tcp/ip を使って Internet のアクセスが可能なサイトに限る。
CMU で使っている VGA 上の X Window System がじきに配布可能となりそうである。
配布サイトの申し出やその他の問い合わせは、次の所まで電子メールか手紙で連絡していただきたい。
電子メールの場合 mach@wbl.cs.cmu.edu
(これを読むのはプロジェクト管理者と配布担当者だけである。)
郵便の場合
Mach Project c/o Richard F. Rashid School of Computer Science Carnegie Mellon University Pittsburgh, PA 15213-3890 U.S.A.
プロジェクト GNU 前夜とコーディング規則を紹介した。コーディング規則はおそらく随時更新されていくだろう。GNU ソフトウェアのソース・コードを見て、あるいは電子掲示板の情報を見て、自分なりにカスタマイズしたスタンダードを作っていけば、プログラマの貴重な財産になるはずである。
Donald E. Knuth, Tracy Larrabee and Paul M. Roberts,MATHEMATICAL WRITING,The Mathematical Association of America, 1988(邦訳、有澤誠訳「クヌース先生のドキュメント纂法」共立出版、1989)
Guy L. Steele Jr., Donald R. Woods, Raphael A. Finkel, Mark R.Crispin, Richard M. Stallman and Geoffrey S. Goodfellow, 犬伏重之訳「ハッカー英語辞典」自然社、1989(英語版 1983)
「座談会 リチャード・ストールマン氏を囲んで」「bit」1987 年 8 月号、共立出版
坂村健「I Love COMPUTER 9, Lisp マシンのアーキテクチャ」「bit」1981 年 3 月号、共立出版
ChangeLog ファイルに変更点を記述しなさい
このファイルがあれば、ある問題を発見した場合、どの変更点で問題を引き起こしたのかを調べることができる。最後に行なった修正が原因で新しい問題が発生することが多い。変更点をソース・コードと共に配布することにより、新たな修正、追加、改良がこれまでの変更と矛盾なく行なわれるようになる。
Emacs を使えば、M-x(ESC キーを押してから x キーを与える、あるいはメタキーと x キーを同時に押す)add-change コマンドを使って自動的に新しい項目を入力することができる。それぞれの項目には、
* 変更を施したファイル名 (変更した関数名、あるいは変数名): 変更についての記述。
のように書く。空白行で区切ったものを 1 つの項目とする。同じ修正が複数個所におよんでも項目分けはしない。同じファイル内の修正ならその前の * も省略する。
変更の目的やなぜそのような修正方法にしたかについての、理由を記述する必要はない。
関数の呼び出しプロトコルを変更した場合は、呼び出し側の全てを記述するのではなく、
「全ての呼び出し側を変更」
と書く。
ドキュメントや注釈の変更に関しては、ファイル名のみでよく、
「ドキュメントの修正」
と書く。
このようにドキュメントについてシンプルなのは、発生した問題点の影響を受けにくく、修正も容易だからである。さらにこれまでの修正との一貫性を保つ必要がなく、誤りを修正するのに過去の履歴を知る必要もない。
Makefile には次のターゲットを入れなさい。
all
全てのプログラムをコンパイルする。
install
プログラムをコンパイルして、実行形式やライブラリをコピーし、必要に応じてファイル名を変更する。簡単なテストがあれば行なう。
clean
そのディレクトリ内で、プログラム作成途中で生成された全てのファイルを消去する。コンフィギュレーションの記録を消してはいけない。プログラム作成途中で生成されたファイルは配布テープに入れてはいけないが、消さないでおく。
distclean
コンフィギュレーションやプログラムを作成する上で生成されたファイル全てを消去する。配布テープ用のファイルのみを残す。
mostlyclean
clean と同じ動作を行なう。その際、再コンパイルしたくないファイルはそのまま残しておく。例えば gcc の mostyclean というターゲットでは、libgcc.a を消さない。再コンパイルはほとんど必要ないし、行なうとすると時間がかかるからである。
realclean
必要ないもの、もう一度作り直せるもの全てを消去する。distclean で消すファイル以外のファイルをも消去する。Bison が生成した C ソース・ファイル、タグテーブルなど。
TAGS
プログラムのタグテーブルを更新する。
dist
tar ファイルの名前はサブディレクトリ名で始める。サブディレクトリ名は配布するパッケージの名前であること。例えば、gcc バージョン 1.40 の tar ファイルを展開すると、gcc-1.40 というディレクトリが生成され、その下に必要なファイルが展開される。最も簡単な方法は、任意のディレクトリ名にコピー(cp) するかリンク (ln) をはることである。dist ターゲットには全ての「非ソース・ファイル」を明示的に指定すること。これにより配布イメージを確実に最新のものとすることができる (「5. リリースの方法」を参照のこと)。
check
必要に応じて、セルフテストを行なう。テストする前に必ずプログラムが作成されていなければならないが、インストールしておく必要はない。
Makefile には、
SHELL= /bin/sh
も入れておくこと。環境変数 SHELL を継承して発生する問題を事前に防止することができる。コマンドやオプションなどは、Makefile 内で直接記述するのではなく、変数で定義してから使うこと。特にユーティリティ・プログラムにおいてはそのようにしなさい。Bison を使う場合、BISON という変数名を用いて、必要になった時点で $(BISON) というふうにして Bison を参照する。
それぞれのコマンドに使うオプション用の変数名には、そのコマンド名を含んでいること。コマンド名に FLAGS という文字列を付ける。例えば、BISONFLAGS のように (CFLAGS は例外である。これが標準だからである)。
システム・ファイルのインストールに使うコマンドに対しては、INSTALL という変数名を用いる。
変数 INSTALL_PROGRAM と INSTALL_DATA を用いる (既定値では $(INSTALL) とする)。実行形式、非実行形式をインストールする場合にそれぞれ使用する。
$(INSTALL_PROGRAM) foo ${bindir}/foo $(INSTALL_DATA) libfoo.a ${libdir}/libfoo.a
(それぞれの第 2 引数にはディレクトリ名ではなくファイル名を与えること。いずれのファイルのインストールにもインストール・コマンドを使用すること)
インストールする場所のディレクトリのパス名を変数名で与えること。標準以外の方法でインストールする際に楽になる。標準変数を次に示す。
bindir
ユーザが実行する実行形式をインストールするディレクトリ。一般に /usr/local/bin を指定し、$(prefix) を使った値にしておく。
datadir
プログラムが実行中に参照する読み込み専用のデータ・ファイルをインストールするディレクトリ。使うマシンに依存しないファイル形式とする。ネットワーク・インストールを行なった場合はマシン間で共有することが可能となる。一般に /usr/local/bin を指定し、$(prefix) を使った値にしておく。
statedir
実行中に更新するようなファイルをインストールするディレクトリ。使うマシンに依存しないファイル形式とする。ネットワーク・インストールを行なった場合はマシン間で共有することが可能となる。一般に /usr/local/lib を指定し、$(prefix) を使った値にしておく。
libdir
ユーザではなくプログラムが起動する実行形式をインストールするディレクトリ。オブジェクト・ファイルやライブラリもここに置く。マシン・アーキテクチャに依存するファイルをここに置くという案もある。一般に /usr/local/lib を指定し、$(prefix) を使った値にしておく。
includedir
ユーザ・プログラムで挿入するヘッダー・ファイル #include をインストールするディレクトリ。一般に /usr/local/include を指定し、$(prefix) を使った値にしておく。
gcc 以外のコンパイラでは、/usr/local/include をほとんど参照しない。gcc と共にこのヘッダー・ファイルをインストールしておくと便利である。gcc を想定したライブラリのみの場合には通常問題にならない。しかし、他のライブラリは別のコンパイラを想定しているので、ヘッダー・ファイルを 2 箇所にインストールしなければならない。ひとつは includedir で、もうひとつは oldincludedir である。
oldincludedir
gcc 以外のコンパイラで用いるヘッダー・ファイル #include をインストールするディレクトリ。通常は /usr/include になるだろう。make コマンドでは oldincludedir がないかどうかをまずチェックし、そこに何もなければ、oldincludedir を使ってはいけない。ヘッダー・ファイルのインストールのコマンドの 2 番目の引数で指定しないようにする (つまり oldincludedir にインストールしてはいけない、ということ)。
mandir
必要に応じて、man ページをインストールするディレクトリ。
マニュアルのセクションを拡張子とする。ユーティリティは通常、1 である。
man1dir
セクション 1 の man ページのディレクトリ。
man2dir
セクション 2 の man ページのディレクトリ。
...
セクションが複数にわたるマニュアルをインストールする場合に、mandir という名前を用いる。
GNU ソフトウェアの主要なドキュメントとして man ページで作成してはいけない。TexInfo でマニュアルを書くこと。man ページは 2 次的なものであり、GNU ソフトウェアを Unix 上で動かしている人々のためだけのものである。
manext
man ページの拡張子を指定する。ピリオドの後に数字が来る。
infodir
このパッケージ用の info ファイルが入るディレクトリ。既定値は /usr/local/info であり、$(prefix) を含む値で初期化される。
srcdir
コンパイルするソース・コードが入っているディレクトリ。configure シェル・スクリプトで設定される。
preifx
前述の変数を作成するために指定する接頭語 (つまり bindir などのパス名と最初の部分をこの変数で指定する)。
例
# Common prefix for installation directories. # NOTE: This directory must exist when you start installation. prefix= /usr/local # Directory in which to put the executable for the command `gcc' bindir= $(prefix)/bin # Directory in which to put the directories used by the compiler. libdir= $(prefix)/lib
GNU のそれぞれのパッケージには configure という名前のシェル・スクリプトが入っている。スクリプトでは複数の引数を与えて、プログラムをコンパイルしたいマシンやシステムの種類を記述する。
configure ではコンフィギュレーションのオプションを記述しなければならない。後々のコンパイル時に必要だからである。
config.h のような標準名と、選択したシステム向けのコンフィギュレーション・ファイルとリンクする、という方法もある。この方法を使った場合は、配布テープに config.h というファイルを入れてはいけない。最初にコンフィギュレーション・スクリプトを実行しないでプログラムが作成されることを防止するためである。configure の目的は、Makefile を修正することである。この方法を採用する場合に、Makefile という名前のファイルを配布イメージに含めてはならない。ファイル Makefile.in を用意し、修正用入力ファイルとする。もう一度繰り返す。これは、最初にコンフィギュレーション・スクリプトを実行しないでプログラムが作成されることを防止するために行なう。
configure が Makefile を生成するようになっていた場合には、Makefile 内のターゲットには Makefile を入れ、configure を起動して最新のコンフィギュレーションの状態にする。configure の入力ファイルを Makefile のターゲットの依存リストに記述しておくこと。
configure スクリプトが生成する全てのファイルには、注釈として、configure から自動的に生成されてある旨を記すこと。そうすればユーザがそのファイルを直接修正することはない。configure スクリプトが configure.status というファイルを生成するようにしておくこと。最後に、configure スクリプトを起動したいときのオプションを入れる。それ自体はシェル・スクリプトであり、実行すれば同じコンフィギュレーションを再生成することができる。
configure スクリプトはオプション--srcdir=dirname を指定できるようにしておく。そのディレクトリになければ、ソース・ファイルの場所を指定することができる。このオプションによって他の場所のディレクトリでプログラムを作成できるようになる。その場合、実際のソース・ディレクトリの内容は修正しない。
--srcdir というオプションの指定がなければ、configure は現在のディレクトリを調べて、ソース・ファイルがあるかどうかを確認しなさい。どちらかが見つかればそれをソース・ディレクトリとする。そうでなければ、ソースが見つからない旨を報告し、ゼロ以外のステータス・コードを返す。一般に--srcdir をサポートするためには、Makefile の VPATH を定義するように修正する。Makefile の中のルールのうち、ソース・ディレクトリを明確に指定する必要があるかもしれない。これに備えて、Makefile の srcdir という変数名にソース・ディレクトリを指定すること。
configure スクリプトの引数で、作成するプログラムのシステム・タイプをも受け付けられるようにする。形式は、
cpu-company-system
で、例えば Sun-3 は、
m68k-sun-sunos4.1
というふうになる。
configure スクリプトは、そのマシンを示すそれらしい別名をも解釈できるようにすべきである。sun3-sunos4.1 も妥当である。基本的に sun3-bsd4.2 もよいだろう。sunos は基本的に BSD であり、Sun 以外に BSD システムを使っていないからである。たいていのプログラムでは、vax-dec-ultrix の別名として、vax-dec-bsd は妥当であろう。というのは単純に BSD と Ultrix の相違はほとんどない。時にはプログラムでは区別する必要があるかもしれない。
config.sub というシェル・スクリプトを、システム名あるいは別名が適切かどうかを調べるために用いる。
他のオプションとして次のようなものが可能である。各オプションではマシンのハードウェアやソフトウェアの詳細を記述する。
-with-package
package がインストールされており、package を使うようにコンフィギュレーションに指定する。X や gnu-as(あるいは gas)、gnu-ld、gnu-libc、gdb など。
--nfp
浮動小数点プロセッサがないターゲット・マシンに用いる。
--gas
ターゲット・マシンのアセンブラは GAS(GNU アセンブラ) である。このオプションは古い形式なので、-with-gnu-as を用いるように。
--x
X Window System がインストールされているターゲット・マシンに用いる。このオプションも古い形式なので、--with-x を使うように。
将来、独自のパッケージで相違が生じるかどうかにかかわらず、configure スクリプトは前述の詳細なオプション全てを受け付けるようにしなさい。特に、--with-で始まる全てのオプションも受け付けるように。そうすれば、ユーザは一連のオプションを与えるだけで、一度で全ての GNU ソース・ツリーを構成できるようになる。
コンパイルするようなパッケージならば、クロス・コンパイルをサポートするかもしれない。その場合、プログラムのホストとターゲットのマシンが異なる。configure スクリプトでは通常、ホスト・マシンとターゲット・マシンの両方のマシン・タイプを指定する。従って、スクリプトが起動されるマシンと同じもので動作するプログラムを生成する。
クロス・コンパイラやクロス・アセンブラなどを作成するには、configure に --host= ホストタイプ・オプションを指定する。ターゲット・システムは変更しない。ホスト・タイプの書き方は前述のものと同じである。
クロスとしての動作が無意味なプログラムでは--host を受け付けてはいけない。クロス動作を行なわせるために全てのオペレーティング・システムを構成すること自体が無意味だからである。
プログラムによってコンフィギュレーションを自動的に行なう。
この場合には、前述の全ての引数を無視してもよい。
C 言語以外の言語を使うということは標準に従っていないことになる。gcc でさえ、他の言語のフロントエンドを複数用意してサポートしている。その言語をインストールするために他の言語をインストールすることは手間がかかるので、C 言語を使うように。
規則には次の 3 つの例外がある。
インタープリタを備えていれば問題ない。例えば GNU Emacs の場合には、インタープリタも用意してあるので、Emacs Lisp のコードを含んでいても問題がない。
言語の利用を定義するために、ツールの中で別の言語を用いるといった場合は特に問題ない。とにかくツールを作りたい人が使いたい言語を自分でインストールすればよいからである。
広く使われていないアプリケーション・プログラムならば、インストールが面倒かどうかは問題にならないだろう。
foo バージョン 69.69 のパッケージは、foo-69.69.tar というファイル名で配布する。展開すると、foo-69.69 というサブディレクトリの元にファイルが生成される。
プログラムを作成しインストールする際に、配布イメージに入っているファイルを修正してはいけない。 これは、どのような場合でもプログラムは形式上「ソース・ファイル」と「非ソース・ファイル」に分類されていなければならない、という意味である。「ソース・ファイル」は人間が作成したものであり、自動的に修正されてはいけない。「非ソース・ファイル」は、「ソース・ファイル」から Makefile に従ってプログラムが生成したものである。
もちろん、全てのソース・ファイルは配布イメージ内に入っている必要がある。「非ソース・ファイル」は入っていてもかまわないが、最新のもので、しかもマシンに依存しないものでなければならない。配布イメージを作成する際に修正しないこと。一般に我々は、Bison や Lex、TeX、Makeinfo で生成した「非ソース・ファイル」を含めている。配布イメージ内の不要な依存関係の記述を省いている。このようにして希望するものをどれでもインストールできるようにしている。
プログラムの作成や、インストールを行なうために実際に修正が入る可能性のある「非ソース・ファイル」を、配布イメージに入れてはいけない。もし「非ソース・ファイル」を配布する時に、新たに配布イメージを作成する場合は常に最新のものになるよう注意しなさい。
配布イメージ内には 14 文字より長い名前のファイルがない点に留意すること。同様にできあがったプログラムも 14 文字より長い名前のファイルを生成してはならない。というのは POSIX 規格を変に解釈しているシステムがあるためである。そのシステムは、長い名前のファイルを切り詰めてオープンせずに、オープンすること自体を拒否しているのである。
MS-DOG 上でもファイル名が重複しないように考慮してみること。MS-DOG のファイル名は 9 文字からなり、さらにピリオドの後に 3 文字を追加することができる。MS-DOG は、ピリオドの前後でこの制限を越えたものは切り捨てられる。従って、foobarhacker.c と foobarhacker.o は重複しない。それぞれ foobarhac.c と foobarhac.o とに切り捨てられて区別できるからである。
texinfo.tex のコピーを配布イメージに入れなさい。*.texinfo ファイルを出力するのに必要である。
rms の今年 37 才とは 1990 年起稿時のこと。
「GNU コーディング規則」の最新版は、マニュアルとしてプリンタに出力できるきれいな体裁となっている。
その最新 GNU コーディング規則では、
変更点の記述について
Makefile の書き方について
コンフィギュレーションについて
C 以外の言語の利用について
リリースの方法
といった章が追加された。この章の最後に概略を示したので参考にしてほしい。
enum を使うと gdb で表示できるからでもある。
以前の注記でもふれたが、GNU General Public License のことを「GNU 一般公的使用許諾」ではなく、「一般公有使用許諾書」に訂正して呼んでいる。