xmkmfとimakeによるMakefile生成

8年前のX Window Systemのコードをビルドしようとしてドハマリしています。

Makefileについてgdgdメモします。

Makefileを得るいくつかの方法

ソースコードをmakeするには、Makefileを使用します。

自分が知っているMakefileの作り方は、次の4つです。


  • 方法1. configureを使用して生成する
  • 方法2. xmkmfを使用して生成する
  • 方法3. imakeを直接使用して生成する
  • 方法4. 自分で書く

よく使うのは、方法1です。configureスクリプトを実行すると、Makefile.iniMakefile.inからMakefileが生成されます。

また、ダウンロードしてきたオープンソースのコードにMakefileやconfigureスクリプトがなく、代わりにImakefileがある場合は、方法2あるいは3によってMakefileを得ることになります。xmkmfを実行すると、内部でimakeが実行され、ImakefileからMakefileが生成されます。

ちなみに、オープンソースのコードに、親切にも依存ライブラリや関連コマンドが含まれていた場合は、自分のマシンに同じライブラリやコマンドがすでにインストールされていたとしても、ソースコードに同梱されていたものを使ってビルドします(よね?)。ソースコードと一緒に配布されているツールであれば、ライブラリ同士のバージョンの相性が良く、問題なくビルドできる可能性が高いためです。

可能性が高い、と書きました。残念ながら、xmkmfやimakeを叩いただけでは、ビルド可能なMakefileが生成されないことがあります。その場合は、泣きながらMakefileを修正します。

今ハマっているのも、方法2で作ったMakefileでmakeできないケースです。

その話の前に、xmkmfとimake自体について調べたことをメモしておきます。

xmkmfの使い方

次のコマンドを実行すると、実行ディレクトリにあるImakefileからMakefileが生成されます。

$ xmkmf

次のようにaオプションを付けると、Makefileが生成された後、make Makefiles、make includes、make dependが順に実行されます。

$ xmkmf -a

imakeの使い方

次のコマンドを実行すると、実行ディレクトリにあるImakefileからMakefileが生成されます。

$ imake

imakeは、ルールが書かれた設定ファイルを実行時に読み込みます。Iオプションの引数で、ルールファイルがあるディレクトリを指定します。

$ imake -I/usr/share/X11/config

「I」とパスの間に半角スペースを入れないように注意します。

ついでに、Imakefileの記述ルール周りに少し触れると、こんなカンジです。

マクロ定義

imakeのルールが記述されたファイル(Imake.rule)に、MACHINE-INDEPENDENT RULESという項目があり、標準のマクロ定義がコメントで掲載されています。記述の実体は、imakeのテンプレートファイル(Imake.tmpl)にあります。

(ルールの例)サブディレクトリがある場合

Imakefileが、サブディレクトリを持つディレクトリに配置されている場合、次の記述が必要です。

  • SUBDIRSという変数を定義し、サブディレクトリ名をスペース区切りで列挙する
  • #define IHaveSubdirs を宣言する
  • MakeSubdirs() と DependSubdirs() を呼び出す

実際のImakefileを見てみると、まさにそのまま書かれています。

#define IHaveSubdirs
(略)

        SUBDIRS = include config lib $(NLSSUBDIR) \
                  programs $(FONTSDIR) $(DOCSDIR)
(略)

MakeSubdirs($(SUBDIRS))
(略)

DependSubdirs($(SUBDIRS))
ターゲットの記述

makeコマンドによって実行されるMakefileのターゲットは、Imake.ruleに基づいて自動生成された標準のターゲットと、Imakefileに明示的に記述されたターゲットの2種類があります。別の言い方をすると、Imake.ruleで提供されないものは、Imakefileで書かなければなりません。

xmkmfとimakeによる生成結果の差異

ところで、xmkmfコマンドで間接的にimakeを使う場合と、imakeコマンドを直接使う場合とで、生成されるMakefileに違いはあるのでしょうか。

よく分からないので確認してみました。というのも、もし違いがあるならば、より妥当なMakefileを出力できる方を使いたいからです。

昔のXのコードについていたImakefileを、xmkmfとimakeそれぞれに渡してみました。

※ 以下では、xmkmfと比較するために、マシンにインストールされたimakeを使用しました。が、実際の(ハマり中の…)作業では、コードに同梱されていた古いimakeでMakefileを生成しています。

xmkmfでのMakefile生成
$ sudo xmkmf
mv -f Makefile Makefile.bak
imake -DUseInstalled -I/usr/share/X11/config
$ ls
(略)
-rw-r--r--.  1 root root 33580 May  9 07:35 Makefile

生成されたMakefileは、1326行でした。

imakeでのMakefile生成
$ whereis imake
imake: /usr/bin/imake /usr/share/man/man1/imake.1x.gz
$ sudo imake -I/usr/share/X11/config
$ ls
(略)
-rw-r--r--.  1 root root 34403 May  9 10:03 Makefile

生成されたMakefileは、1333行でした。行数だけを見ると、差はほとんどありません。

差分の確認

xmkmfとimake、それぞれのコマンドで生成した2つのMakefileのdiffを取ってみました。

# diff {xmkmfで生成したMakefile} {imakeで生成したMakefile} > diff-xmkmf-imake
# cat diff-xmkmf-imake

123,124c123,124
<             IMAKE = imake
<            DEPEND = gccmakedep
---
>             IMAKE = $(IMAKESRC)/imake
>            DEPEND = $(DEPENDSRC)/makedepend
126c126
<           REVPATH = revpath
---
>           REVPATH = $(CONFIGSRC)/util/revpath
(略)
948c951
< FCCACHE = $(BINDIR)/fc-cache
---
> FCCACHE = set -x; $(CLIENTENVSETUP) $(PRELOADXFTSETUP) FONTCONFIG_PATH=$(FONTCONFIGLIBSRC) $(XBUILDBINDIR)/fc-cache
(略)

コマンドやパスの定数に設定された値が異なっています。

分からないこと

xmkmfとimakeのどちらを使えばよいのかは、ソースコードとマシン依存なので、がんばって確認して決めよう!てことでFAなのでしょうか。

また、xmkmfから生成したMakefileで、コマンド定数が直書きされていたのも気になります。あのMakefileをそのまま使うと、makeの再帰処理の中では、特殊なバージョンのimakeを適用することができなさそうです。これも、各自で修正して変数を使うべしってことなんですかね。

何かxmkmfなりimakeなりの実行時オプションを追加するか、あるいはImakefileを適切に変更すれば、カンタンに解決するのかな…とも思うものの、よく分かりません。。。

続きはまた今度

個別具体的なハマリについて泣き言を書くつもりでしたが、長くなったので今度に。

参考

Imakefileの記述方法で参考になる資料は、ルールファイル、テンプレートファイル自体のコメント、config/cf以下のreadmeです。それ以外にはほとんど見当たりません。

# オライリーのmake本の付録にimakeの項があり、期待したのだけれど、「非常に広く使用されているツールとしては、imakeはいまだに異常なほど文書化されていません」とか書かれていて、ガックシ・・・。