Makefile でのヘッダファイルの依存関係を自動的に解決する
Makefile でヘッダファイルの依存関係を書くのは結構面倒である。以前は X に付属の makedepend コマンドを使って行うのが普通だったが、便利な方法がないか調べてみた。
GNU make のマニュアルに、まさに依存関係を自動生成する方法そのものがかかれていた。
4.14 Generating Prerequisites Automatically に詳しい説明がある。make の info の日本語訳が GNU make 日本語訳(Coop編) - ルールの記述 があるが、ここにかかれている Makefile のルールそのままでは動作しなかった。英語の原文の方のルールにしないと動作しない。単に引用符の対応関係がとれていないだけ。
以下のようにすればよい。Makefile 全体を乗せておく。
- 生成された *.d を include する。ただし、一番最初は *.d は存在しないので、-include としてエラーメッセージが表示されないようにする。
- make clean では *.d も消去するようにする。
PROG=one SRC=one.c two.c three.c OBJS=$(patsubst %.c,%.o,$(SRC)) DEPENDS=$(patsubst %.c,%.d,$(SRC)) $(PROG): $(OBJS) $(CC) -o $@ $(OBJS) .c.o: $(CC) $(CFLAGS) -c $< .PHONY : clean depend clean: -$(RM) $(PROG) $(OBJS) $(DEPENDS) %.d: %.c @set -e; $(CC) -MM $(CPPFLAGS) $< \ | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ -include $(DEPENDS)
このルールは、コンパイラの -M オプションがインクルードされるファイルのリストを生成してくれる機能を利用している。-MM にすると、標準ディレクトリにあるファイルは表示されず、ローカルのファイルだけが対象となる。こんな感じになる。
#include <stdio.h> #include "two.h" #include "three.h" int main(void) { printf("One! "); two(); three(); return 0; }
[motoki@centos3 maketest]$ gcc -M one.c one.o: one.c /usr/include/stdio.h /usr/include/features.h \ /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \ /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include/stddef.h \ /usr/include/bits/types.h /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \ /usr/include/gconv.h \ /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include/stdarg.h \ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h two.h \ three.h [motoki@centos3 maketest]$ gcc -MM one.c one.o: one.c two.h three.h
生成される *.d はこんな感じ。
[motoki@centos3 maketest]$ make cc -c one.c cc -c two.c cc -c three.c cc -o one one.o two.o three.o [motoki@centos3 maketest]$ cat one.d one.o one.d : one.c two.h three.h
生成された *.d ファイルの内容はこんな感じ。
参考情報
調査している過程で見つけた Makefile 関係のページをメモしておく。
RPM 作成
これまで Debian ばかりで Redhat 系の RPM は作成したことがなかったが、作成方法を知っておいた方が何かと便利そうなので、簡単なパッケージを作成してみることにした。
参考にしたのは、http://vinelinux.org/MakingRPM/MakingRPM.html。rpm 3.x の頃の資料なのでちょっと古いかもしれないが、CentOS の SRPM を持ってきてみたところ、説明が古そうな点は見あたらないようである。
まずは前準備。
RPM の作成は、システムを上書きしないように一般ユーザで行った方がよい。デフォルトで rpmbuild を行うと /usr/src/redhat 以下を使おうとするので、~/.rpmmacros を作成し、ホーム以下を使用するようにする。ここでは ~/redhat 以下で RPM 作成を行う。また、RPM 作成時の一時データを作成するフォルダも指定しておく。
[motoki@centos3 redhat]$ cat ~/.rpmmacros %_topdir /home/motoki/redhat %_tmppath %{_topdir}/tmp
さて、パッケージ作成。
簡単なプログラムである GNU hello を材料に spec ファイルを作成してみた。こんな感じ。非常に簡単であった。
Summary: The classic greeting, and a good example Name: hello Version: 2.2 Release: 1 Source: hello-2.2.tar.gz URL: http://www.gnu.org/software/hello/ License: GPL Group: Local BuildRoot: %{_tmppath}/%{name}-root %description The GNU Hello program produces a familiar, friendly greeting. It allows non-programmers to use a classic computer science tool which would otherwise be unavailable to them. %changelog * Sat May 19 2007 Akihiro MOTOKI <amotoki@gmail.com> - first release for version 1.1 %prep %setup -q %build ./configure --prefix=/usr make %install make DESTDIR=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc ABOUT-NLS AUTHORS COPYING INSTALL NEWS README THANKS TODO /usr/bin/hello /usr/share/locale/ /usr/share/info/hello.info.gz /usr/share/man/man1/hello.1.gz
%files セクションは最初から書くのは大変なので、分かる範囲で書いて、残りは rpmbuild -bi
error: Installed (but unpackaged) file(s) found:
/usr/bin/hello
/usr/share/info/hello.info.gz
/usr/share/locale/bg/LC_MESSAGES/hello.mo
/usr/share/locale/ca/LC_MESSAGES/hello.mo
/usr/share/locale/da/LC_MESSAGES/hello.mo...
/usr/share/locale/vi/LC_MESSAGES/hello.mo
/usr/share/locale/zh_CN/LC_MESSAGES/hello.mo
/usr/share/locale/zh_TW/LC_MESSAGES/hello.mo
/usr/share/man/man1/hello.1.gz
LDP man-pages 2.48
The Linux Documentation Project Works を見に行ったら、man-pages 2.48 がリリースされていた。JM の更新は明日行おうっと。
しかし、これまで最新版が置かれていた ftp://ftp.win.tue.nl/pub/linux-local/manpages/ には最新版がなく、http://www.tldp.org/manpages/ に最新版が置かれている。配布場所が変更されたのだろうか。