基本を再チェック〜gcc〜 |
| YAMAMORI Takenori ●yamamori@kt.rim.or.jp |
今度はXのアプリケーションをコンパイルしてみましょう. サンプルソースを下のリストに示します. これはXawを用いたHello Worldのプログラムで, 表示する"Hello World !"の文字列は,リソースを用いず, プログラム中に埋め込んでいます.
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Label.h>
main(int argc, char **argv)
{
XtAppContext app_context;
Widget topLevel, hello;
topLevel = XtVaAppInitialize(
&app_context,
"Hello",
NULL, 0,
&argc, argv,
NULL,
NULL
);
hello = XtVaCreateManagedWidget(
"hello",
labelWidgetClass,
topLevel,
XtNlabel, "Hello World !",
NULL
);
XtRealizeWidget(topLevel);
XtAppMainLoop(app_context);
}
|
それではhello_x11.cをコンパイルしてみましょう. 今までと同様に下の実行例のようにコマンド操作を進めて行きます.
$ su -c 'rm -f /usr/include/X11' ← (*1)
$ make hello_x11 ← (*2)
gcc -O2 hello_x11.c -o hello_x11
hello_x11.c:1: X11/Intrinsic.h: No such file or directory
hello_x11.c:2: X11/StringDefs.h: No such file or directory
hello_x11.c:3: X11/Xaw/Label.h: No such file or directory
make: *** [hello_x11] Error 1
$ make CPPFLAGS=-I/usr/X11R6/include hello_x11 ← (*3)
gcc -O2 -I/usr/X11R6/include hello_x11.c -o hello_x11
/tmp/ccXtpRf1.o: In function `main':
/tmp/ccXtpRf1.o(.text+0x20): undefined reference to `XtVaAppInitialize'
/tmp/ccXtpRf1.o(.text+0x31): undefined reference to `XtStrings'
/tmp/ccXtpRf1.o(.text+0x38): undefined reference to `labelWidgetClass'
/tmp/ccXtpRf1.o(.text+0x42): undefined reference to `XtVaCreateManagedWidget'
/tmp/ccXtpRf1.o(.text+0x48): undefined reference to `XtRealizeWidget'
/tmp/ccXtpRf1.o(.text+0x50): undefined reference to `XtAppMainLoop'
collect2: ld returned 1 exit status
make: *** [hello_x11] Error 1
$ make CPPFLAGS=-I/usr/X11R6/include LDLIBS='-lXaw -lXmu -lXt -lX11' hello_x11
↑ (*4)
gcc -O2 -I/usr/X11R6/include hello_x11.c -lXaw -lXmu -lXt -lX11 -o hello_x11
/usr/bin/ld: cannot open -lXaw: No such file or directory
collect2: ld returned 1 exit status
make: *** [hello_x11] Error 1
$ make CPPFLAGS=-I/usr/X11R6/include LDFLAGS=-L/usr/X11R6/lib \
LDLIBS='-lXaw -lXmu -lXt -lX11' hello_x11 ← (*5)
gcc -O2 -I/usr/X11R6/include -L/usr/X11R6/lib hello_x11.c -lXaw -lXmu -lXt -lX11 -o hello_x11
$ ./hello_x11 ← (*6)
|
OS環境によっては過去との互換性のため, 「/usr/include/X11 -> ../X11R6/include/X11」 というシンボリックリンクが張られている場合があります. ここでは説明のため,あらかじめこのシンボリックリンクを削除しています.(*1)
環境変数CC=gcc,CFLAGS=-O2の状態にあらかじめセットされている状態で, そのまま「make hello_x11」としてみます. すると,インクルードファイルが見つからないというエラーが出て, コンパイルに失敗してしまいました.(*2) Xのプログラムのためのインクルードファイルは, 標準ディレクトリの/usr/includeではなく,/usr/X11R6/includeの下にあります. したがってgccでのXのプログラムをコンパイルする際には, 「-I」オプションでインクルードファイルのディレクトリを指定する必要があるのです.
そこで,「CPPFLAGS=-I/usr/X11R6/include」を指定して, 再度makeを実行してみます.(*3) (GNU make以外では動作が異なる場合があります. うまくいかない場合は実行例に表示されているgccのコマンド行を 直接入力して下さい) 今度はインクルードファイルのエラーはなくなりましたが, なにやら「undefined reference ...」というエラーが出ています. これは,所定のXのライブラリとのリンクを指定しなかったため, いくつかのXの関数が見つからないというエラーです.
そこで,「-l」オプションを追加し,必要なライブラリを指定します. このhello_x11.cの場合, 「-lXaw -lXmu -lXt -lX11」を指定すればよいことがわかっていますので, これをLDLIBS=で指定してmakeを実行します.(*4) すると今度は,「-lXawが見つからない」というエラーになりました.
「-lXaw」オプションを付けると,ライブラリとしてlibXaw.soがサーチされます。 ところがlibXaw.soやそのほかのXのライブラリは, libcなどの標準ライブラリのある/usr/libではなく,/usr/X11R6/lib以下にあります. したがって,gccでのコンパイル時(正確にはリンク時)に, 「-L」オプションでこのディレクトリを指定する必要があるのです.
そこで,今度は「LDFLAGS=-L/usr/X11R6/lib」という指定をさらに追加して makeを実行します.(*5) これでやっとコンパイルが通りました. (Solarisの場合はさらにオプション追加が必要です.コラム参照) できあがったhello_x11を実行すると, 「Hello World !」がウィンドウ表示されます.(*6)
確認のため,lddでhello_x11がリンクしている共有ライブラリを 表示してみましょう.(*7) すると,libXextほか「-l」オプションで直接指定しなかったいくつかのライブラリも, 結果的にリンクされていることがわかります.
さて,このようにXのアプリケーションのコンパイルとなると, もはやgccのオプションを直接指定して起動する方法は限界に来ています. そこで参考までに,Imakefileを使った方法をちょっとだけ書いておきます. 下のリストのような,たった2行のImakefileをカレントディレクトリに作成して下さい. すると,単に「xmkmf -a; make」とするだけで, gccに必要なオプションは自動的に付けられ,コンパイルが完了します.
LOCAL_LIBRARIES = XawClientLibs SimpleProgramTarget(hello_x11) |