コンパイルって何ですか.


このコーナーは「今日のコンパイル」ですが, コンパイルって何ですか, みたいな人も中には居るでしょうから, ちょっとそういう人をフォローする記事でも書いてみるか. だいたい「今日のコンパイル」も, 表紙の「 今日のらくがき 」 の対として適当につけた題名なんで, 今となっては若干 アレな気分なんですけど.

コンパイルというのは英語で, compile と書く. もともと資料なんかを集めて何か作る作業を指すものだったようだ. と, 今 dic で英和辞典を引いて知りました. 3番めくらいに, 「プログラムを機械語に翻訳する」というのがありますが, ここで使っている意味は, こっちです.

翻訳は, 人間がやる場合もありますが, たいていはそのためのプログラムがあって, それがやります. Linux では gcc というプログラムがそれです.

プログラムを機械語に翻訳するといっても, その機械語ってのは 何でしょう? 機械語というのはそのままで, 機械が解る言語です. あと, ゴルゴも解るという噂あり. なぜなら, 奴はマシーンだから. なんつって.

0000000 177   E   L   F 001 001 001  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020 002  \0 003  \0 001  \0  \0  \0 204  \0 005  \b   4  \0  \0  \0
0000040 304   ] 005  \0  \0  \0  \0  \0   4  \0      \0 005  \0   (  \0
0000060 027  \0 026  \0 006  \0  \0  \0   4  \0  \0  \0   4 200 004  \b
0000100   4 200 004  \b 240  \0  \0  \0 240  \0  \0  \0 005  \0  \0  \0
0000120 004  \0  \0  \0 003  \0  \0  \0 324  \0  \0  \0 324 200 004  \b
0000140 324 200 004  \b 023  \0  \0  \0 023  \0  \0  \0 004  \0  \0  \0
0000160 001  \0  \0  \0 001  \0  \0  \0  \0  \0  \0  \0  \0 200 004  \b
0000200  \0 200 004  \b   4   ! 005  \0   4   ! 005  \0 005  \0  \0  \0
0000220  \0 020  \0  \0 001  \0  \0  \0   4   ! 005  \0   4 261  \t  \b
0000240   4 261  \t  \b 370   2  \0  \0  \b 246 001  \0 006  \0  \0  \0
0000260  \0 020  \0  \0 002  \0  \0  \0 214   S 005  \0 214 343  \t  \b
0000300 214 343  \t  \b 240  \0  \0  \0 240  \0  \0  \0 006  \0  \0  \0
0000320 004  \0  \0  \0   /   l   i   b   /   l   d   -   l   i   n   u
0000340   x   .   s   o   .   2  \0  \0  \t 002  \0  \0 207 003  \0  \0

上に, 機械語のプログラムを一部紹介致しました. 機械語というよりは, 宇宙語ですな. なんせ, 機械ですから, わしらが喋る言葉とは, だいぶ違うわけでして. 昔はコレを直接, トグルスイッチや 16キー (テンキーではないぞ. 0から 9までに加えて ABCDEF の 16個のキーがが付いて いるのじゃ. 16進をそのまま入力できるスグレモノだ!) で人間が入力したものである. つまり, 人間が特訓を積み, 機械語を喋ってあげたのだ. 上に紹介したような奴をな.

プログラムを書くのがむちゃくちゃに大変だということ以外に, 機械語によるプログラミングはもっと重大な欠点があった. 世の中には何種類ものコンピュータがある. インテル狂ってるとか, りんご とかの他に, Cray sparc alpha PDP VAX atari amiga news Next Indy ..... コンピュータの種類というのは, 何の種類かというと, 機械語の種類のことだ. せっかく書いたプログラムも, 違うコンピュータでは違う機械語が使われている せいで, 全然使えないのだ.

違うコンピュータでも同じプログラムを使うというのは, じっくり考えてみると, けっこう難しい発想を含んでいる. 全然違う機械語で書かれた 2つのプログラムが, 使う人間から見たら 同じものとして見えるということだ. 全然違う言語が「同じ内容」を表現しているということである. 自然言語では, これは非常に難しく思えるかも知れないが, 計算機の世界ではあながち無茶でもない. 実際, 足し算は足し算であり, CPU が何をどう使って計算しようが, 使う方にとってみれば, そんなこと知ったことではない. しかし, 機械語のプログラムには, CPU がどういうふうに足し算を実行すべきかが, いちいち全部書いてあるのだ. つまり, 機械語で書いたものは, 単純な足し算のプログラムすらも, 違う機械では動かないのだ.

そこで, 機械がどうやってプログラムを実行するかということに 煩わされること無く, プログラムの本質, つまり処理の手続きのところだけを人間が考えて, 機械語のプログラムは, 人が書いた手続きを元に生成すれば飛躍的に楽になるはずだ. ようし!手続きを元に, 機械語のプログラムを生成するプログラムを作ろう. こいつを作るのは大変だが, 一種類のコンピュータにつき, 一個ずつ, 何とか作ってしまえば, あとはずいぶん楽になる. 一度これを書けば, あとは機械語に翻訳するだけで いろんな計算機で動くものができるぞ! ということを, 30年以上も前に考えて, 実際に作った奴が居た. 天才や. マジで. 機械語に翻訳してくれるプログラムを コンパイラ という.

#include "zsh.mdh"
#include "main.pro"

/**/
int
main(int argc, char **argv)
{
    char **t;
#ifdef LC_ALL
    setlocale(LC_ALL, "");
#endif
    global_permalloc();
    init_hackzero(argv, environ);
    for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
    zsh_name = argv[0];
    do {
      char *arg0 = zsh_name;
      if (!(zsh_name = strrchr(arg0, '/')))

これが, 上で紹介した機械語の元になった, 真のプログラム. 人間の書いたプログラムだ. C という言葉で書いてある. 英語と数式のごちゃまぜみたいな, ヘンテコリンな言葉だけど, 英語と数式をごちゃまぜにするというのは, 確かに, 手続き, つまりプログラムの本質を記述するのに適しているね. まあ, 日本語と数式でもいいんだけど, 残念ながら, こういう分野で日本人は ほとんど何にもやってない ので, 歴史的事情により, 英語と数式になっているのである. それに, 英語は文字が少ないから, 計算機で扱うのもわりかし楽だしね.

C の他にも幾つか言語があるが, 諸般の事情により, 専ら C とその一族が人気だ. C は 1970年代のはじめにできた言葉だ. B. Kerninghan と D. Ritchie の 2人が中心になって作った. そして, C で書いた人間向きプログラムを機械語に翻訳するのが, C コンパイラ だ. "gcc" というのは GNU の C compiler ということだ.

機械語のプログラムは, 機械の制御の方に気を取られて どういう処理をしてるのかが全然掴めないので, コンパイルしたものだけを渡されても, 一体何だか全然解らない. だから, プログラムのうち大切なのは, 機械語に翻訳されたものよりも, プログラムの本質である, 処理手続き(それに, データ構造も)を書いた C 言語の方だ. この, C 言語で書かれた手続きの記述こそが プログラムの本体なのであり, 機械語のファイルなんか, (コンパイラがあればの話だが) コンパイラで処理すればいくらでも作れるのである. この, プログラムのアイデアと本質が書かれた C 言語の記述を ソースコード という. 機械で高度なプログラムを動かすために, この50年間というもの, このような途方もない力が注がれて来たのだ. すげえぜ!

プログラムの本質が書かれた ソースコードの状態で配付されており, 受け取った人が, それを自由に改変し, さらにそれを他の人に配っても構わない, という条件で配付されているプログラムを Free Software という. 言うまでもなく, Linux では OS 本体も, コンパイラ自体も Free Software である. ついでに言うと, 箱に入って偉そうに街で売っている製品は, コンパイル済みの, 機械語の方なのだ. 金払ってまでして, コンパイラが吐き出した機械語のファイル買って来るなんてな, うわー. すげえダメでしょ. てゆうか, マジで損してる感じ.

フリーソフトを書くということが, どんなにスゲエことで, カッコイイことか, 解ってもらえたら嬉しい. つまり, この記事は, そんなスゲエ奴が書いたプログラムを, 俺がコンパイラでコンパイルする, というだけの, 泣けて来る程アホらしいコーナーなのである.

諸般の事情により, プログラムは幾つかのファイルに分かれている事が多い. 複数のプログラムで同じ処理があったとすれば, それを使いまわすほうが, 書くのも楽だし, 不具合の修正も楽だ. 例えば, スクロールバーやボタンは, いろんなプログラムで共通して 使われる機能だから, それだけまとめて別のプログラムにしておき, いろんなアプリケーションから呼び出して使えるようになっていると便利だ. そいういう使いまわし用のプログラムを ライブラリ という. /usr/lib とか /usr/local/lib とか /lib に置いてあるのが, これだ. 間違って消すなよ.

ところで, 俺はいつも gcc -O2 -o hoge.o hoge.c とかいうコマンドを 入力しまくっているのであろうか. なんせ, 「今日のコンパイル」だし. でも, GIMP なんか, 4000個も そういうファイルがあるんだぜ. そんなことしてたら, それ以外何もやる暇無いがな. つうか, そんな作業, 自動化するに決まっとるがな. それが make です. make を使えば, 沢山のコンパイルを自動的に 実行してくれるのだ.

make は, Makefile という名前のファイルを捜し, そこに書いてある指令どお りにコマンドを実行する. 大抵は, 「あるファイルをコンパイルして, こういうファイルを作れ」という指令が書いてあるが, 別にコンパイルに使わないといけないというわけじゃあない. じゃあ shell script と同じでは? という疑念がわくかもしれないが, make ならでは, という機能があり, その代表が ファイルの依存関係を記述することが簡単にできるようになっている事だろう. 沢山のファイルに分割されたプログラムをコンパイルするときは, この機能が非常にありがたいのだ. 話を聞いただけじゃあ判らん? やってみれば判るよ.

Makefile には, コンパイラを起動するコマンドが直接書いてあるので, ライブラリなどの場所によっては, 同じコマンドが効かなくなり, 便利が悪い. そこで, Makefile の雛型を作っておき, これを元に, そのシステムに ぴったりの Makefile を作る, というのが主流になった. これが configure スクリプトの役割だ. 実際には, configure スクリプト自体も configure.in という雛型の雛型を元に, autoconf という プログラムを用いて生成されているのだが.

そんなわけで, 最近リリースされるプログラムの多くは, パッケージを展開したら, あとは

./configure && make
でコンパイルできてしまうのである. コンパイラを直接起動するのは, 自分ではなく, make 君だ. これで, 全然違う種類のコンピュータでも, 同じソースコードを元に して, ばっちり動く機械語のファイルが作れるというわけだ(若干誇張あり). 楽な時代になったもんじゃのう. でも, 幾ら何でも README くらいは読めよ.

gnome-pim-1.0.50

すげえ具合良いっす. カレンダーアプリケーションが起動するまでの時間が 1/3 になったっす. どういうわけ? というより, いままで何であんなに遅かったの?

gPS-0.4.1

gtop という, 何でも判るすげえシステムモニタプログラムがあるが, 重たいのでこういうのを入れてみた. どっかの雑誌に載ってたかも. メインの画面はこんな感じ. 画面に表示されているプロセスを左クリックで選択して メニューの "Action" から送信するシグナルを選択できる.

CPUとメモリの strip chart もあって, その画面はこんな感じ.

というと, なんか, すげえ便利そうで, ikll なんかお払い箱という感じで, そうだと嬉しいんですが, それがそうでもないんですよ. なんせ, プロセスといっても, 俺のノートですら 60個もあるからな. お目当てのを選ぶだけでひと苦労じゃ. 表示のコラムをクリックすれば, その項目でソートできるので, プロセス ID 順とか名前順とか起動順とかでソートできるんだけど, 60個が 6個に減るわけじゃなし.

とにかく, 起動が速いのはありがたい. ヰンドウヅとかに付いてるタスクマネージャみたいな感じで, パネルに登録してあります. アイコンも可愛いし. これで, gimp や netscape が暴走したら, いちいち端末を起動して, ikill netscape とかやらなくてよくなったので, とても良い. もちろん, 端末があるときは, ikill を使うけどね. なんせ zshell なら, 動作中のプロセス名から拾って来て引数を補完できるし.

zsh の補完

ヘッダファイルやライブラリへのパス(-I/usr/local/include/gtk や, -L/usr/local/gimp-1.1/lib など)と, リンクするライブラリ(-lVFlib2 とか)を補完する. といっても, 普通は gcc を直接叩く事は無いんで, あんまり関係無いんですが. それに, compsys を使えばもっとナイスな補完ができるかも. しかも, 他に膨大にあるオプションは全くフォローしてない.

shared_objects (){
	reply=(`ldconfig -vNX 2>/dev/null \
	| sed -e 's/lib//' -e 's/\.so.*//'| grep -v :`)
	}
compctl -f -x 'n[-1,-I]' -/ \
	- 'n[-1,-L]' -/ \
	- 'n[-1,-l]' -K shared_objects \
	-- gcc cc

こっちは新しくなった ikill の引数, すなわちプロセス名の補完. 名前が途中で切れるけど, 以前, ps から拾ってたよりもずっと速くなった. ただし, /proc から直接 sed で所得しているので, Linux 以外では動かないと思われる.

running_process () {
	reply=(`cat /proc/*/stat | sed -e 's/.*(//' -e 's/).*//'`)
	}
compctl -K running_process + -caF ikill pid