/ «2008-03-01 (Sat) ^ 2008-03-05 (Wed)» ?
   西田 亙の本:GNU 開発ツール -- hello.c から a.out が誕生するまで --

Categories Books | Hard | Hardware | Linux | MCU | Misc | Publish | Radio | Repository | Thoughts | Time | UNIX | Writing | プロフィール


2008-03-04 (Tue)

[Thoughts] プログラマの教養は manual pages に宿る (その3)

早速、Cソースからの実行可能ファイル作成に進みたいところですが、その前に作業環境を確認しておきましょう。

Linux/GNU 開発環境の確認方法

私が使用している Linux/GNU 開発環境は以下の通りです。

 $ uname -a
 Linux debian64 2.6.22-3-amd64 #1 SMP Sun Nov 4 18:18:09 UTC 2007 x86_64 
 GNU/Linux

オペレーティングシステム環境を簡単に知るためには、uname (Uts NAME: UTS = Universal Time-sharing System / Unix Time-sharing System) コマンドを使います。この Linux マシンは Core 2 プロセッサ搭載のため、Debian AMD64 版 testing を使用しています。

 $ ld -v
 GNU ld (GNU Binutils for Debian) 2.18.0.20080103
 $ gcc --version
 gcc (GCC) 4.2.3 (Debian 4.2.3-1)
 Copyright (C) 2007 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.

まず最初に、後で述べる binutils のバージョン番号を確認します。ld コマンドに -v オプションを与えると binutils パッケージのバージョン番号 2.18.0 が表示されています。次に GCC のバージョン番号を gcc コマンドの --version オプションで確認しますが、この環境では 4.2.3 と表示されています(binutils と GCC のバージョン番号が異なる点に注目)。

次に、C言語によるプログラム開発において、その存在なくしては語れないCライブラリですが、Linux/GNU 開発環境では GNU C Library (GNU libc, glibc とも略される) が採用されています。glibc のバージョン番号は、パッケージ中に含まれるシステム管理ユーティリティ ldconfig に -V (Version) オプションを与えることで確認できます。小文字の -v を指定すると、/etc/ld.so.cache の再構築を試みようとするため、オプション指定には十分注意してください(パーミッションエラーが発生するため、通常は心配ありませんが)。

なお、ldconfig はシステム管理ツールに属するため、/sbin (Supser-user's BINaries) ディレクトリに格納されています。一般ユーザの PATH 環境変数に /sbin ディレクトリは含まれていないため、ldconfig を起動するためには /sbin を前置する必要があります(一般ユーザでも起動は可能)。

 $ /sbin/ldconfig -V
 ldconfig (GNU libc) 2.7
 Copyright (C) 2007 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 Written by Andreas Jaeger.

私が使用している64ビット環境では、最新版の 2.7 がインストールされていました。Debian etch 32ビット環境では、次のように 2.3.6 がインストールされています。

 $ /sbin/ldconfig -V
 ldconfig (GNU libc) 2.3.6
 Copyright (C) 2005 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.  There is NO warranty;
 not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 Written by Andreas Jaeger.

最後に、標準ライブラリ・ヘッダーファイルおよび Linux 専用ヘッダーファイルがインストールされているかどうかを確認します。

 $ file /usr/include/stdio.h
 /usr/include/stdio.h: ASCII C program text
 $ cat /usr/include/linux/version.h 
 #define LINUX_VERSION_CODE 132630
 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))

具体的には標準ライブラリ・ヘッダーファイルの代表として stdio.h が /usr/incude ディレクトリに存在するかどうかを file コマンドで確認し、Linux 専用ヘッダーファイルの代表として、/usr/include/linux ディレクトリに格納されている version.h の内容を出力しています。

LINUX_VERSION_CODE マクロは、KERNEL_VERSION マクロに示されている通り、最上位バイトにメジャー番号・中位バイトにマイナー番号・最下位バイトにパッチ番号を格納しています。実行例の 132630 は、16進数表記で 0x020616 ですから、メジャー番号は2・マイナー番号は6・パッチ番号は22となります。

以下に、Linux/GNU 開発環境の確認手順をまとめておきます。Linux 環境上で Cソースのビルドが出来ないときは、この5点をチェックしてみて下さい。表中に Debian での対応パッケージ名を添えておきます。

確認対象確認方法Debian dpkg
binutilsld -vbinutils
GCCgcc --versiongcc
GNU C ライブラリ/sbin/ldconfig -Vlibc6
標準ライブラリ・ヘッダーファイルfile /usr/include/stdio.hlibc6-dev
Linux 専用ライブラリ・ヘッダーファイルcat /usr/include/linux/version.hlinux-kernel-headers

GCC ≠ gcc

世間では混同されることが多いのですが、gcc と GCC は全く異なる概念を意味しています。GCC は「GNU Compiler Collection」の略であり、文字通りコンパイラの集合体を意味する「総称名」です。具体的には、Cをはじめとして、C++, Objective-C, Fortran, Ada などのコンパイラが用意されていますが、この他にもCプリプロセッサやアーキテクチャ依存性ヘッダーファイル、特殊ライブラリなどが含まれています。

これに対して gcc は、ユーザから与えられたオプションとファイル名に基づき、各種コンパイラやアセンブラ・リンカを呼び出し、ビルド作業を統括的に行う「ドライバープログラムの名前」です。gcc は、拡張子が .c であればCコンパイラを呼び出しますし、.f であれば Fortran 95 コンパイラを呼び出します。つまり、gcc は言語の垣根を超えた調整役なのです。

この事実は、gcc に -v オプションを与えると観察できます。

 $ gcc -v
 Using built-in specs.
 Target: x86_64-linux-gnu
 Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --disable-libmudflap --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
 Thread model: posix
 gcc version 4.2.3 (Debian 4.2.3-1)

4行目以降に表示されているメッセージは、GCC パッケージのビルド時に指定された configure オプションですが、先頭付近の --enable-languages に注目してください。ここには、C, C++, Fortran, Objective-C, Objective-C++, treelang 計6種類のコンパイラをビルドするように指定されています(OSやディストリビュータにより、コンパイラの種類は異なる)。

隠されたCコンパイラ

となると、「ご本尊であるCコンパイラは一体どこなのよ?」という疑問が持ち上がると思いますが、シェルプロンプト上で cc1 (Cコンパイラプログラムの名称)と入力しても、該当プログラムはありません。

 $ cc1
 -bash: cc1: command not found

実は、Cコンパイラ本体は、PATH 環境変数に記述されていない秘密のディレクトリに隠されているのです。もちろん、gcc ドライバは cc1 の在りかを知っていますので、-print-prog-name オプションを使って吐かせてみましょう。

 $ gcc -print-prog-name=cc1
 /usr/lib/gcc/x86_64-linux-gnu/4.2.3/cc1
 $ ls -F /usr/lib/gcc/x86_64-linux-gnu/4.2.3/
 32/          crtbeginS.o    include/         libgfortranbegin.a  libobjc_gc.so@
 cc1*         crtbeginT.o    libgcc.a         libgfortran.so@     libobjc.so@
 cc1obj*      crtend.o       libgcc_eh.a      libgomp.a           libstdc++.a
 cc1objplus*  crtendS.o      libgcc_s_32.so@  libgomp.so@         libstdc++.so@
 cc1plus*     crtfastmath.o  libgcc_s.so@     libgomp.spec        libsupc++.a
 collect2*    f951*          libgcov.a        libobjc.a
 crtbegin.o   finclude/      libgfortran.a    libobjc_gc.a

/usr/lib/gcc/x86_64-linux-gnu/4.2.3 ディレクトリ(GCCのバージョン番号およびターゲット・アーキテクチャに応じて、ディレクトリ名は異なる)には、Cコンパイラをはじめとして、アーキテクチャ依存性ヘッダーファイルや GCC 専用ライブラリ, crt (C Run Time) オブジェクトファイルなど、様々なファイルが格納されています。

次回は

何と今回は、作業環境の確認だけで終わってしまいました。UNIX システムプログラミングの教科書で登場する開発ツールは、通常 gcc ドライバ唯一人ですが、実際の裏方では5つのパッケージ群が協調して働いているのです。ひとつひとつの役柄を具体的にイメージできるようになれば、GNU 開発ツールに対する理解は一段と深まることでしょう。なお、個々の役者や、今回紹介した各種オプション群について、さらに深く知りたい方は「GNU 開発ツール」をご参照ください。

次回は、binutils パッケージを使い、アセンブラとリンカだけで hello 実行可能ファイルを作成してみます。GNU 開発環境の基礎部分に位置するものは binutils であり、GNU C Compiler や GNU C ライブラリが、その上層でビルド作業に関わっている事実を実感することは、プログラマにとって大切な経験となります。

続く