Linux カーネル Makefile 2000 年 9 月 14 日 Michael Elizabeth Chastain, 翻訳団体: JF プロジェクト (http://www.linux.or.jp/JF/) 翻訳者: 川崎 貴彦 校正者: 佐野 武俊 校正者: 小林 雅典 === 目次 本ドキュメントは、Linux カーネルの Makefile について記述するものです。 1 概要 2 Makefile に対する関わり方 3 Makefile 言語 4 最上位から渡される変数 5 アーキテクチャ Makefile の構造 5.1 アーキテクチャ固有の変数 5.2 vmlinux 構築変数 5.3 vmlinux の次の構築対象 5.4 必須となるアーキテクチャ固有のターゲット 6 サブディレクトリ Makefile の構造 6.1 コメント 6.2 構築対象定義 6.3 調整セクション 6.4 Rules.make セクション 6.5 特別な規則 7 Rules.make 変数 7.1 サブディレクトリ 7.2 構築対象となるオブジェクトファイル 7.3 構築対象となるライブラリファイル 7.4 構築対象となるローダブルモジュール 7.5 複合モジュール 7.6 コンパイルフラグ 7.7 その他の変数 8 新しい形式の変数 8.1 新しい変数 8.2 古い形式への変換 9 Linux カーネル 2.2 との互換性 10 謝辞 === 1 概要 Makefile には 5 つの区分があります。 Makefile: 最上位 Makefile. .config: カーネル設定ファイル。 arch/*/Makefile: アーキテクチャ Makefile. サブディレクトリ Makefile: 約 300 あります。 Rules.make: 全てのサブディレクトリ Makefile に共通の規則。 カーネル構成定義処理 (make config 等) により .config が生成され、 .config は最上位 Makefile に読み込まれます。 最上位 Makefile には、二つの主要なプロダクト ――vmlinux (常駐カーネル イメージ) とモジュール群 (全てのモジュールファイル)―― を構築するという 役目があります。最上位 Makefile は、カーネルソースツリーを再帰的に下降 していき、これらの構築対象物を作成します。どのサブディレクトリが対象と なるかは、カーネル構成定義の内容に依存します。 最上位 Makefile は、arch/$(ARCH)/Makefile という名前のアーキテクチャ Makefile をそのままインクルードします。アーキテクチャ Makefile は、 アーキテクチャ固有の情報を最上位 Makefile に提供します。 各サブディレクトリには、上位から渡されたコマンドを実行する Makefile が 存在します。サブディレクトリ Makefile は、各種のファイルリストを作成 するため、.config ファイルの情報を利用します。また、Rules.make の共通 規則もそのままインクルードします。 Rules.make では、全サブディレクトリ Makefile に共通の規則が定義されて います。Rules.make には、変数リストという形式で提供される公開インター フェースがあり、これらのリストに基づく規則が宣言されています。 === 2 Makefile に対する関わり方 カーネル Makefile に対する関わり方には 4 通りあります。 『ユーザ』とは、カーネルを構築する人のことを指します。ユーザは、 "make menuconfig" や "make bzImage" といったコマンドを入力します。 通常は、カーネル Makefile (または、その他のソースファイル) を読ん だり編集したりすることはありません。 『一般の開発者』とは、デバイスドライバやファイルシステム、ネットワーク プロトコルなどの機能に対する作業をおこなう人を指します。一般の開発者は、 作業対象となるサブシステム用のサブディレクトリ Makefile を維持管理する 必要があります。維持管理を効率的におこなうためには、カーネル Makefile の概要および Rules.make の公開インターフェースの詳細を知っておく必要が あります。 『アーキテクチャ開発者』とは、sparc や ia64 などのアーキテクチャに関する 全体的な作業をおこなう人を指します。アーキテクチャ開発者は、サブディレク トリ Makefile と同様、アーキテクチャ Makefile についても知っておく必要が あります。 『カーネル構築開発者』とは、カーネル構築システム自体に対する作業をおこなう 人のことを指します。カーネル構築開発者は、カーネル Makefile に関する全ての 事項について知っておく必要があります。 このドキュメントは、『一般の開発者』と『アーキテクチャ開発者』を対象として います。 === Makefile 言語 カーネル Makefile は GNU make 用に設計されています。 Makefile では GNU make の機能のうち文書化されたものしか使われていませんが、それでも 多くの GNU 拡張が利用されています。 GNU make は、基本的なリスト処理機能をサポートします。カーネル Makefile では、"if" 文と組み合わせながら、リストの構築および操作の斬新な手法を 利用しています。 GNU make には、":=" と "=" という二つの代入演算子があります。":=" は、 右辺の値をその場で評価し、確定した文字列を左辺に代入します。"=" は、 公式の定義に似ています。"=" は、右辺を未評価の状態にしておき、左辺が 参照されるたびに逐次評価します。 "=" が適切な場合もあります。しかし、通常は ":=" を選択するほうが良い でしょう。 このドキュメント内の全ての例は、実際のカーネルソースから取ってきたものです。 整形 (空白の変更や、行の分割) はされていますが、それ以外は全く同じです。 === 4 最上位から渡される変数 最上位 Makefile は下記の変数をエクスポートします。 VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION 現在のカーネルのバージョンはこれらの変数で定義されます。これらの 値を直接参照しているアーキテクチャ Makefile もいくつかありますが、 かわりに $(KERNELRELEASE) を使うほうがよいでしょう。 バージョンの基本となる 3 つの部分、たとえば、"2", "4", "0" は、 $(VERSION), $(PATCHLEVEL), $(SUBLEVEL) で定義されます。これら 3 つの値は常に数値です。 プレパッチや追加パッチ用の、さらに下位のサブレベルは、 $(EXTRAVERSION) で定義されます。通常は "-pre4" などのような 非数値の文字列ですが、たいていはブランクになっています。 KERNELRELEASE $(KERNELRELEASE) は、"2.4.0-pre4" というような単一の文字列で、 インストールディレクトリ名の生成や、バージョン文字列内の表示で 使用するのに適しています。いくつかのアーキテクチャ Makefile では、 このような用途で $(KERNELRELEASE) を使用しています。 ARCH この変数は、"i386" や "arm", "sparc" などといったターゲット アーキテクチャを定義するためのものです。どのファイルをコン パイルすべきかを判断するため、多くのサブディレクトリ Makefile が $(ARCH) を参照しています。 デフォルトでは、最上位 Makefile は、$(ARCH) をホストシステム アーキテクチャと同一にします。クロス構築する場合には、ユーザが $(ARCH) の値をコマンドラインで上書きしても構いません。 make ARCH=m68k ... TOPDIR, HPATH $(TOPDIR) は、カーネルソースツリーの最上部へのパスです。 サブディレクトリ Makefile が $(TOPDIR)/Rules.make を インクルードできるようにするため、この変数が定義されて います。 $(HPATH) は、$(TOPDIR)/include と同一です。インクルードファイルを 使って何か特殊なことをするためにこの変数を利用するアーキテクチャ Makefile もいくつか存在します。 SUBDIRS vmlinux またはモジュールを構築するのに必要なサブディレクトリの うち、最上位 Makefile が作業の対象とするものは $(SUBDIRS) に リストアップされます。実際にどのようなディレクトリが $(SUBDIRS) に リストアップされるかは、カーネル構成定義の内容に依存します。この 変数は最上位 Makefile により定義され、アーキテクチャ Makefile に おいてさらに値が追加されます。 HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS LINKFLAGS vmlinux にリンクされるオブジェクトファイルとライブラリは、 $(HEAD), $(CORE_FILES), $(NETWORKS), $(DRIVERS), $(LIBS) で 指定されます。 $(HEAD) にリストアップされるファイルは、vmlinux に最初にリンク されます。 vmlinux を構築するためのフラグは $(LINKFLAGS) で指定されます。 これらの変数は、最上位 Makefile とアーキテクチャ Makefile により 定義されます。最上位 Makefile では、$(CORE_FILES), $(NETWORKS), $(DRIVERS), $(LIBS) が定義されます。アーキテクチャ Makefile では、 $(HEAD) と $(LINKFLAGS) が定義され、また、$(CORE_FILES) と $(LIBS) の内容が追加されます。 注意: 必要以上に変数があります。$(NETWORKS), $(DRIVERS), そして $(LIBS) でさえも、$(CORE_FILES) にまとめてしまうことができたでしょう。 CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS PERL GENKSYMS ソースファイルから構築対象を作成するために Rules.make が使用する コマンドとフラグは、これらの変数で指定されます。 常駐カーネルコードをコンパイルするのに使用される追加の C コンパイル フラグは、$(CFLAGS_KERNEL) で指定されます。 ローダブルカーネルモジュール用のコードをコンパイルするのに使用 される追加の C コンパイルフラグは、$(MODFLAGS) で指定されます。 将来的には、このフラグの名称は、より一般的な名称である $(CFLAGS_MODULE) に変更になるかもしれません。 アセンブラフラグは $(AFLAGS) で指定されます。 CONFIG_MODVERSIONS が有効となっているときにカーネルシンボル シグネチャを生成するのに使用されるコマンドは、 $(GENKSYMS) で 指定されます。genksyms コマンドは modutils パッケージに含まれて います。 CROSS_COMPILE この変数は、$(CC) や $(AS), $(LD) などという他の変数のためのプレ フィックスパスです。アーキテクチャ Makefile では、時折この変数を 使用したり、明示的に設定したりします。サブディレクトリ Makefile は、 この変数のことを気にする必要はありません。 必要なら、$(CROSS_COMPILE) をコマンドラインで上書きしてもよい でしょう。 HOSTCC, HOSTCFLAGS ホスト側のプログラムをコンパイルするのに使用する C コンパイラと C コンパイルフラグは、これらの変数で定義します。ターゲット アーキテクチャとホストアーキテクチャが異なる場合もあるため、 これらの変数が別個に用意されています。 カーネルを構築する過程で必要となるプログラムを Makefile 内で コンパイル/実行する場合は、$(HOSTCC) と $(HOSTCFLAGS) を使用 します。 たとえば、drivers/pci サブディレクトリには gen-devlist.c という 補助プログラムがあります。このプログラムは、PCI ID のリストを読み 込み、出力ファイル classlist.h と devlist.h に C のコードを生成 します。 仮に、i386 コンピュータ上で ia64 マシン用のカーネルを構築しよう としていると仮定すると、ほとんどのコンパイル作業は ia64 用クロス コンパイラを使用することになりますが、drivers/pci/gen-devlist.c を コンパイルするには、ネイティブの i386 用ホストコンパイラを使用する ことになります。 他の例としては、scripts/mkdep.c や scripts/lxdialog/*.c などと いったカーネル補助プログラムがありますが、これらも、$(CC) では なく $(HOSTCC) でコンパイルされます。 ROOT_DEV, SVGA_MODE, RAMDISK これらの変数は、カーネルの構成に関する情報を指定するため、 エンドユーザにより編集されます。これらの変数は古いです! また、i386 アーキテクチャに固有のものでもあります。実際問題 として、これらは CONFIG_* オプションに置き換えられなければ なりません。 MAKEBOOT この変数は、メインのアーキテクチャ Makefile (アーキテクチャ用 ディレクトリにおける最上位 Makefile) 内でのみ定義/使用されます。 最上位 Makefile は MAKEBOOT をエクスポートしません。 INSTALL_PATH アーキテクチャ Makefile が常駐カーネルイメージと System.map ファイルをインストールする場所は、この変数で定義されます。 INSTALL_MOD_PATH, MODLIB $(INSTALL_MOD_PATH) は、モジュールをインストールするために $(MODLIB) に付けられるプレフィックスです。この変数は Makefile 内で定義されることはありませんが、必要ならば、ユーザが指定 できます。 モジュールをインストールするディレクトリは、$(MODLIB) で指定します。 最上位 Makefile は、$(MODLIB) を $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) として定義して います。必要なら、コマンドラインでこの変数を上書きしてもよいで しょう。 CONFIG_SHELL この変数は、Makefile と Rules.make のあいだでのみ使用されます。 アーキテクチャ Makefile とサブディレクトリ Makefile は、この 変数を使用してはいけません。 MODVERFILE 内部変数です。最上位 Makefile の外部で使用されることはないので、 エクスポートされる必要はありません。 MAKE, MAKEFILES GNU make の内部変数です。 アーキテクチャ Makefile とサブディレクトリ Makefile が $(TOPDIR)/.config を明示的にインクルードしていない場合でも、 その内容を強制的に読み込ませるようにするため、$(MAKEFILES) が利用されています (とりあえず機能すればよいということで $(MAKEFILES) を利用した実装がおこなわれましたが、できれば きちんとしたものに書き直したいところです) 。 === 5 アーキテクチャ Makefile の構造 --- 5.1 アーキテクチャ固有の変数 最上位 Makefile は、アーキテクチャ Makefile である arhc/$(ARHC)/Makefile を 一つだけインクルードします。この節では、アーキテクチャ Makefile の機能に ついて記述します。 アーキテクチャ Makefile では、アーキテクチャ固有の値が最上位 Makefile の 変数に追加されます。 SUBDIRS $(SUBDIRS) は、最上位 Makefile で定義されています。アーキテクチャ Makefile により、アーキテクチャ固有のディレクトリのリストが $(SUBDIRS) に追加されます。 例: # arch/alpha/Makefile SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm \ arch/alpha/lib arch/alpha/math-emu このリストはカーネル構成定義の内容に依存します。 # arch/arm/Makefile ifeq ($(CONFIG_ARCH_ACORN),y) SUBDIRS += drivers/acorn ... endif CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS これらの変数は最上位 Makefile で定義されており、アーキテクチャ Makefile はその内容を追加します。 どのオプションがサポートされているかを調べるため、多くのアーキ テクチャ Makefile において、ターゲット用の C コンパイラが動的に 実行されます。 # arch/i386/Makefile # gcc がスタックを 16 バイト境界でアラインしないようにする CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 \ -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ then echo "-mpreferred-stack-boundary=2"; fi) 当然、$(CFLAGS) はカーネル構成定義の内容に依存します。 # arch/i386/Makefile ifdef CONFIG_M386 CFLAGS += -march=i386 endif ifdef CONFIG_M486 CFLAGS += -march=i486 endif ifdef CONFIG_M586 CFLAGS += -march=i586 endif アーキテクチャ固有のフラグを追加するため、コンパイルコマンドを 再定義するアーキテクチャ Makefile も存在します。 # arch/s390/Makefile LD=$(CROSS_COMPILE)ld -m elf_s390 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S --- 5.2 vmlinux 構築変数 vmlinux ファイルの構築方法を指定する変数は、アーキテクチャ Makefile と 最上位 Makefile が協調することにより定義されます。但し、これに対応する モジュール用のアーキテクチャ固有部分は存在しないので注意してください。 モジュールを構築する仕組みは、全てアーキテクチャから独立しているのです。 HEAD, CORE_FILES, LIBS LINKFLAGS これらの変数の内容のうち、アーキテクチャに依存しない中心的な部分は 最上位 Makefile で定義され、それ以外のものが アーキテクチャ Makefile で追加されます。$(HEAD) と $(LINKFLAGS) はアーキテクチャ Makefile で定義されることに注意してください (内容の追加ではありま せん) 。 例: # arch/m68k/Makefile ifndef CONFIG_SUN3 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds else LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N endif ... ifndef CONFIG_SUN3 HEAD := arch/m68k/kernel/head.o else HEAD := arch/m68k/kernel/sun3-head.o endif SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) LIBS += arch/m68k/lib/lib.a --- 5.3 vmlinux の次の構築対象 vmlinux ファイルを圧縮し、ブートストラップコードをかぶせ、その結果 として生成されるファイルをある場所にコピーする、という作業をおこなう ターゲット (構築対象) が、アーキテクチャ Makefile で定義されます。 vmlinux の次の構築対象は、異なるアーキテクチャ間では標準化されていません。 vmlinux の次の構築対象、及びそれをサポートするアーキテクチャ (カーネル バージョン 2.4.0-test6-pre5 時点におけるもの) のリストをここに挙げます。 balo mips bootimage alpha bootpfile alpha, ia64 bzImage i386, m68k bzdisk i386 bzlilo i386 compressed i386, m68k, mips, mips64, sh dasdfmt s390 Image arm image s390 install arm, i386 lilo m68k msb alpha, ia64 my-special-boot alpha, ia64 orionboot mips rawboot alpha silo s390 srmboot alpha tftpboot.img sparc, sparc64 vmlinux.64 mips64 vmlinux.aout sparc64 zImage arm, i386, m68k, mips, mips64, ppc, sh zImage.initrd ppc zdisk i386, mips, mips64, sh zinstall arm zlilo i386 znetboot.initrd ppc --- 5.4 必須となるアーキテクチャ固有のターゲット アーキテクチャ Makefile では、下記に示すアーキテクチャ固有のターゲットを 定義しなければなりません。これらのターゲットは、最上位 Makefile 内の対応 するターゲットに対して、アーキテクチャ固有の動作を提供するものです。 archclean clean archdep dep archmrproper mrproper === 6 サブディレクトリ Makefile の構造 サブディレクトリ Makefile には 5 つのセクションがあります。 --- 6.1 コメント 最初のセクションはコメントヘッダです。C ソースファイルを編集している ときと同じように記述します。しかし、"/* ... */" ではなく、"# ..." を 使いましょう。歴史的に、ヘッダに変更履歴を残さないまま、不特定多数の 人々がカーネル Makefile を編集してきました。彼等のコメントが残ってい れば、有益なものとなったことでしょう。 --- 6.2 構築対象定義 二番目のセクションは、サブディレクトリ Makefile の中心部分である定義群 です。構築されるファイル、特別なコンパイルオプション、再帰的に処理され るサブディレクトリ、が定義されます。これらの定義は、カーネルの設定変数 (CONFIG_* シンボル) に大きく依存します。 幾つかの Makefile ("古い形式の Makefile") では、二番目のセクションは 次のようになっています。 # drivers/parport/Makefile ifeq ($(CONFIG_PARPORT_PC),y) LX_OBJS += parport_pc.o else ifeq ($(CONFIG_PARPORT_PC),m) MX_OBJS += parport_pc.o endif endif ほとんどの Makefile ("新しい形式の Makefile") では、二番目のセクションは 次のようになっています。 # drivers/block/Makefile obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o 新しい形式の Makefile のほうが簡潔で、特定の機能 (一つ以上のファイルを 有効にする CONFIG_* オプションなど) に関しては、修正も容易です。どちら でもよいのならば、新しい形式で Makefile を記述してください。 --- 6.3 調整セクション 三番目のセクションは、調整セクションです。古い形式の Makefile には、 この三番目のセクションは存在しません。新しい形式の Makefile では、 新しい形式の変数を古い形式の変数に変換するための定型コードを三番目の セクションに記述します。というのは、Rules.make が古い形式の変数しか 処理できないためです。 例については、8.2 節 ("古い形式への変換") を参照してください。 --- 6.4 Rules.make セクション 4 番目のセクションは、次の一行です。 include $(TOPDIR)/Rules.make --- 6.5 特別な規則 5 番目のセクションには、Rules.make の共通規則には含まれていない特別な Makefile 規則を記述します。 === 7 Rules.make 変数 Rules.make の公開インターフェースは、下記の変数で構成されています。 --- 7.1 サブディレクトリ ALL_SUB_DIRS, SUB_DIRS, MOD_IN_SUB_DIRS, MOD_SUB_DIRS $(ALL_SUB_DIRS) には、あるディレクトリ内の "全て" のサブディレクトリを 無条件にリストアップします。このリストは、カーネル構成定義の内容に依存 させてはいけません。 $(SUB_DIRS) には、vmlinux に関連するコードを含むサブディレクトリを リストアップします。このリストは、カーネル構成定義の内容に依存させ ても構いません。 カーネルモジュールを構築する可能性のあるサブディレクトリは、 $(MOD_SUB_DIRS) と $(MOD_IN_SUB_DIRS) にリストアップします。 どちらの変数も、まったく同じ意味です (バージョン 2.2 以前の カーネルでは、これらの変数には異なる意味が与えられていたため、 別々の名前が付いています) 。 新しいコードでは $(MOD_SUB_DIRS) を使いましょう。$(MOD_IN_SUB_DIRS) は 推奨しません。 例: # fs/Makefile ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs \ umsdos ntfs hpfs sysv smbfs ncpfs ufs efs affs \ romfs autofs hfs lockd nfsd nls devpts devfs \ adfs partitions qnx4 udf bfs cramfs openpromfs \ autofs4 ramfs jffs SUB_DIRS := ... ifeq ($(CONFIG_EXT2_FS),y) SUB_DIRS += ext2 else ifeq ($(CONFIG_EXT2_FS),m) MOD_SUB_DIRS += ext2 endif endif ifeq ($(CONFIG_CRAMFS),y) SUB_DIRS += cramfs else ifeq ($(CONFIG_CRAMFS),m) MOD_SUB_DIRS += cramfs endif endif 例: # drivers/net/Makefile SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring \ wan sk98lin arcnet skfp tulip appletalk ... ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda MOD_IN_SUB_DIRS += irda else ifeq ($(CONFIG_IRDA),m) MOD_IN_SUB_DIRS += irda endif endif ifeq ($(CONFIG_TR),y) SUB_DIRS += tokenring MOD_IN_SUB_DIRS += tokenring else ifeq ($(CONFIG_TR),m) MOD_IN_SUB_DIRS += tokenring endif endif --- 7.2 構築対象となるオブジェクトファイル O_TARGET, O_OBJS, OX_OBJS サブディレクトリ Makefile では、vmlinux 用のオブジェクトファイルを $(O_OBJS) と $(OX_OBJS) というリストに指定します。これらのリストは カーネル構成定義の内容に依存します。 "OX_OBJS" の "X" は、"eXport" を意味します。$(OX_OBJS) にリスト アップされたファイルでは、ローダブルカーネルモジュールから参照 可能な公開シンボルを定義するため、EXPORT_SYMBOL マクロを使用し ても構いません。一方、$(O_OBJS) にリストアップされたファイルでは、 EXPORT_SYMBOL を使用してはいけません (試してみたら分かりますが、 変なエラーメッセージが出力されます) 。 [ おっしゃる通り、手作業でこんなことをするのはバカげています。 確かに、シンボルを定義しているかいないかに関係なく、全ての オブジェクトを $(OX_OBJS) にリストアップしてしまうことも できるでしょう。しかし、何かソースファイルを編集するたびに、 追加のコンパイル作業が大量に発生してしまうということに、 あなたも気付かれることでしょう。これは CONFIG_MODVERSIONS のせいです。 ] 登録関数 (pci_register_driver, pm_register など) 経由でほかの オブジェクトに渡されるデータは、EXPORT_SYMBOL でマークする必要は ありません。登録関数経由でデータを受け渡しするオブジェクトも、 自身がシンボルをエクスポートしていないのであれば、$(OX_OBJS) に リストアップする必要はありません。 Rules.make により、全ての $(O_OBJS) ファイル、$(OX_OBJS) ファイルが コンパイルされます。続けて "$(LD) -r" が実行され、これらのファイルは $(O_TARGET) という名前を持つ単一の .o ファイルにマージされます。最上位 Makefile 内にも $(O_TARGET) という名前があります。 $(O_OBJS) と $(OX_OBJS) 内のファイルの順番は重要です。$(OX_OBJS) に リストアップされているファイルが、並んでいる順番で、まず先頭に置かれ ます。これに、$(O_OBJS) にリストアップされているファイルが、これも また並んでいる順番に、後に続きます。リスト内に重複があっても構いません ――最初のインスタンスのみが $(O_TARGET) にリンクされ、後に続くインス タンスは無視されます (重複があることに対して Rules.make が警告メッ セージを出力するかもしれませんが、なんの問題もありません) 。 例: # arch/alpha/kernel/Makefile O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o \ semaphore.o OX_OBJS := alpha_ksyms.o ifdef CONFIG_SMP O_OBJS += smp.o irq_smp.o endif ifdef CONFIG_PCI O_OBJS += pci.o pci_iommu.o endif たとえサブディレクトリ Makefile で $(O_TARGET) が定義されている としても、その $(O_TARGET) を vmlinux に組み込むかどうかは、 .config オプションで制御することができます。下記の $(M_OBJS) の 例を参照してください。 $(O_OBJS) の前にある $(OX_OBJS) に含まれるファイルの順番付けが、 ときおり問題を起こすことがあります。特に、順番が重要な個所で $(O_OBJS) と $(OX_OBJS) のファイルの双方に __initcall 宣言が 含まれている場合に問題となります。順番付けに課されるこのような 問題を避けるため、$(OX_OBJS) をまったく使わず、かわりに $(MIX_OBJS) を使うこともできます。 この方法を使う場合は、下記の点に気をつけてください。 - vmlinux にリンクされるオブジェクトを全て、求める順番で $(O_OBJS) にリストアップすること - モジュールとして作成されるオブジェクトを全て $(M_OBJS) に リストアップすること - シンボルをエクスポートするオブジェクトを全て $(MIX_OBJS) に リストアップすること この方法は、vmlinux 内におけるオブジェクトファイルの順番付けを より細かく制御できるという点を除き、エクスポートするかしないかに 基づく分類を維持することと同じ効果があります。 --- 7.3 構築対象となるライブラリファイル L_TARGET, L_OBJS, LX_OBJS これらの変数は、O_* と同様です。再度述べますと、$(L_OBJS) と $(LX_OBJS) には、常駐カーネル用のオブジェクトファイルをリスト アップします。このリストは、その時点でのカーネル構成定義の 内容に依存します。また、EXPORT_SYMBOL を呼び出すファイルは、 "X" リストに含めるようにします。 違いは、"L" が "Library" (ライブラリ) を意味しているという点だけです。 $(L_OBJS) と $(LX_OBJS) を作成後、Rules.make ではこれらのファイルを 元に、"$(AR) rcs" というコマンドで $(L_TARGET) という名前を持つアー カイブファイル (ライブラリ) を作成します。この $(L_TARGET) という 変数は、最上位 Makefile 内にもあります。 例: # arch/i386/lib/Makefile L_TARGET = lib.a L_OBJS = checksum.o old-checksum.o delay.o \ usercopy.o getuser.o putuser.o iodebug.o ifdef CONFIG_X86_USE_3DNOW L_OBJS += mmx.o endif ifdef CONFIG_HAVE_DEC_LOCK L_OBJS += dec_and_lock.o endif $(L_OBJS) と $(LX_OBJS) 内のファイルの順番は重要ではありません。 リスト内に重複があっても構いません (重複があることに対して Rules.make が警告メッセージを出力するかもしれませんが、なんの 問題もありません) 。 サブディレクトリ Makefile では、$(O_TARGET) もしくは $(L_TARGET) の どちらか、もしくは両方を指定できます。以下では、その違いについて 述べていこうと思います。 $(O_TARGET) 内のファイルは全て、常駐カーネルイメージに含まれる ことが保証されています。$(L_TARGET) の場合は、他のファイルからの 未定義シンボル参照を解決することができるファイルのみ、vmlinux に 含まれることになります。 伝統的なリンクプロセスでは、リンカはオブジェクトファイルを処理し、 未解決外部シンボルのリストを作成します。その後、リンカはこれらの シンボルを解決するため、ライブラリ群を検索します。実を言えば、 Linux カーネルも、かつては同じようにライブラリ内のコードとリンク されていました。 しかし、このような方法でライブラリから取り出すことのできない オブジェクトファイルが、vmlinux 内には二種類存在します。 (1) 純粋に EXPORT_SYMBOL 定義だけを含むオブジェクトファイル (2) (初期化ルーチンを外部から呼び出してもらうのではなく) module_init もしくは __initcall イニシャライザを使用 するオブジェクトファイル これらのファイルには、明示的に呼び出されなくても、コードと データを提供することのできる独立した初期化セクションがあり ます。もしも、これらのファイルを $(L_TARGET) ライブラリに 含めてしまうと、vmlinux にリンクするときに失敗してしまうで しょう。このため、ほとんどのサブディレクトリ Makefile では $(O_TARGET) を指定し、$(L_TARGET) は使わないようにしています。 その他の考慮点: $(O_TARGET) にしておくと開発時の再リンク 処理が早くなります。しかし、解決できないシンボルがあった 場合には、$(L_TARGET) にしたほうが有益なエラーメッセージを 得ることができます。 --- 7.4 構築対象となるローダブルモジュール M_OBJS, MX_OBJS ローダブルカーネルモジュールとして構築するオブジェクトファイルは、 $(M_OBJS) と $(MX_OBJS) で指定します。他と同じように、$(MX_OBJS) の "X" は "eXport" を意味します。EXPORT_SYMBOL を使用するソース ファイルは $(MX_OBJS) リストに入れておかなければなりません。 モジュールは、一つ、または複数のソースファイルから構築されます。 ソースファイルが一つの場合は、サブディレクトリ Makefile では、 $(M_OBJS) または $(MX_OBJS) のうちのどちらか適切なほうを選んで そのファイルを追加するだけで済みます。 例: # drivers/net/irda/Makefile ifeq ($(CONFIG_IRTTY_SIR),y) L_OBJS += irtty.o else ifeq ($(CONFIG_IRTTY_SIR),m) M_OBJS += irtty.o endif endif ifeq ($(CONFIG_IRPORT_SIR),y) LX_OBJS += irport.o else ifeq ($(CONFIG_IRPORT_SIR),m) MX_OBJS += irport.o endif endif カーネルモジュールが複数のソースファイルから構築される場合は、 ソースファイル群を指定する二つの方法があります。一つは、サブ ディレクトリ全体で一つのモジュールを構築する方法です。この 方法は、ファイルシステムやネットワークプロトコルスタックでは よく使われています。 例: # fs/ext2/Makefile O_TARGET := ext2.o O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o \ ialloc.o inode.o ioctl.o namei.o super.o symlink.o \ truncate.o M_OBJS := $(O_TARGET) この例では、モジュールの名前は ext2.o になります。これは $(O_TARGET) と同じ名前なので、Rules.make は $(O_TARGET) 規則を使用して ext2.o を構築することになります ―― $(O_OBJS) ファイルのリストに対して "$(LD) -r" を実行する ことになります。 このサブディレクトリ Makefile では $(O_TARGET) と $(M_OBJS) の 両方が定義されていることに注意してください。上位の fs/Makefile にある制御コードにより、どちらか一方が選択されます。 CONFIG_EXT2_FS=y の場合は、fs/Makefile により $(O_TARGET) が構築 されます。CONFIG_EXT_FS=m の場合は、かわりに $(M_OBJS) が構築され ます (確かにこの方法は若干扱いにくく、混乱を招くおそれもあります)。 --- 7.5 複合モジュール MI_OBJS, MIX_OBJS 複数のオブジェクトファイルがリンクされ、一つのカーネル モジュールを構成する場合もあります。しかし、必ずしも サブディレクトリ内の全てのオブジェクトファイルが含まれる というわけではありません。こういう場合は、$(MI_OBJS) と $(MIX_OBJS) を使います。 "M" は、モジュールを意味します。 "I" は、中間を意味します。 "X" は、いつものように、"eXport シンボル" を意味します。 例: # drivers/sound/Makefile gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_card.o gus.o: $(gus-objs) $(LD) -r -o $@ $(gus-objs) pas2.o: $(pas2-objs) $(LD) -r -o $@ $(pas2-objs) sb.o: $(sb-objs) $(LD) -r -o $@ $(sb-objs) カーネルモジュール gus.o, pas2.o, sb.o は『合成ファイル』です。 オブジェクトファイル gus_card.o, gus_midi.o, gus_vol.o, gus_wave.o, ics2101.o, pas2_card.o, pas2_midi.o, pas2_mixer.o, pas2_pcm.o, sb_card.o は『コンポーネントファイル』です。コン ポーネントファイルは『中間ファイル』とも呼ばれます。 drivers/sound/Makefile のその他の部分 (上記の例には示されていま せん) では、全てのコンポーネントファイルは分割されています。常駐 ドライバの場合、コンポーネントオブジェクトファイルは、シンボルを エクスポートするかどうかに従って $(O_OBJS) か $(OX_OBJS) にリスト アップされます。そして、合成ファイルが構築されることは決してあり ません。一方、カーネルモジュールの場合は、コンポーネントオブジェ クトファイルは $(MI_OBJS) と $(MIX_OBJS) にリストアップされ、 その合成ファイルが $(M_OBJS) に置かれます。 複数のオブジェクトファイルで構成されるモジュールを構築する 場合は、サブディレクトリ Makefile 内でそれ用のリンク規則を 指定しておかなければなりません。 # drivers/sound/Makefile gus.o: $(gus-objs) $(LD) -r -o $@ $(gus-objs) pas2.o: $(pas2-objs) $(LD) -r -o $@ $(pas2-objs) sb.o: $(sb-objs) $(LD) -r -o $@ $(sb-objs) 7.2 節 ("構築対象となるオブジェクトファイル") でも述べたとおり、 シンボルをエクスポートする全てのオブジェクトファイルを、単純に $(MIX_OBJS) にリストアップすることもできます。この方法を取った 場合は、$(O_OBJS), $(L_OBJS), $(M_OBJS), $(MI_OBJS) にそれぞれ、 vmlinux の全オブジェクトファイル、ライブラリオブジェクトファイル、 モジュールオブジェクトファイル、中間モジュールファイルを、単に リストアップすることになります。$(MI_OBJS) と $(MIX_OBJS) で ファイルの重複があっても、問題にはなりません。 --- 7.6 コンパイルフラグ EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS $(CC) で C ファイルをコンパイルするときに使用するオプションは $(EXTRA_CFLAGS) で指定します。この変数で指定されたオプションは、 カレントディレクトリ内のファイルを対象とする全ての $(CC) コマ ンドに適用されます。 例: # drivers/sound/emu10k1/Makefile EXTRA_CFLAGS += -I. ifdef DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG endif $(EXTRA_CFLAGS) は、カレントディレクトリ内のサブディレクトリには 適用されません。また、$(HOSTCC) でコンパイルされるファイルにも 適用されません。 変数 $(CFLAGS) はソースツリー全体のコンパイルフラグ用に最上位 Makefile で使用されているので、別途 $(EXTRA_FLAGS) という変数が 必要となります。 アセンブリソースをコンパイルするための各ディレクトリ用オプション として、同じように $(EXTRA_AFLAGS) が存在します。 例: この文書を記述している段階では、実際のカーネルソース内に $(EXTRA_AFLAGS) を使用している例はありませんでした。 $(LD), $(AR) についても、各ディレクトリ毎のオプションとして 同様に $(EXTRA_LDFLAGS), $(EXTRA_ARFLAGS) が用意されています。 例: この文書を記述している段階では、実際のカーネルソース内に $(EXTRA_LDFLAGS), $(EXTRA_ARFLAGS) を使用している例はありま せんでした。 CFLAGS_$@, AFLAGS_$@ $(CC) を用いてコンパイルするときの各ファイル用オプションは $(CFLAGS_$@) で指定します。$@ の部分は、コンパイルにより 生成されるファイルのファイル名になります。 例: # drivers/scsi/Makefile CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM 上記 3 行により、aha152x.o, gdth.o, seagate.o 用のコンパイル フラグが指定されることになります。 アセンブリ言語ソースファイル用にも、同じように $(AFLAGS_$@) が 存在します。 例: # arch/arm/kernel/Makefile AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional Rules.make には、コンパイルするときに使われる $(CFLAGS_$@) の値に オブジェクトファイルを依存させる機能があります ($(CFLAGS) や $(EXTRA_CFLAGS) の値にも依存させます)。ですので、あるファイル用の $(CFLAGS_$@) の値を、Makefile を編集するかもしくは他の何らかの 方法で変更した場合、Rules.make が正しく動作し、新しいオプションで ソースファイルが再コンパイルされることになります。 注意: Rules.make 内の依存関係の問題により、アセンブリ言語ファイルは フラグに依存しません。ですので、$(AFLAGS_$@) を変更した場合、ソースを 再コンパイルするためにはオブジェクトファイルを削除する必要があります。 LD_RFLAG この変数は使用されていますが、定義されてはいません。過去に行われた 試験実装の名残のようです。 --- 7.7 その他の変数 IGNORE_FLAGS_OBJS フラグの変更を自動的に追跡して依存性を保つ、という機能を適用 させたくないオブジェクトファイルは、$(IGNORE_FLAGS_OBJS) に リストアップします。これは間に合わせ的な機能で、フラグ依存 関係の実装まわりの問題をとりあえず解決するのに使われています (問題は、%.o ファイルが対応する %.S ファイルまたは %.c ファイル から構築されるものと仮定してフラグ依存関係が実装されている、 という点にあります。これは常に正しいわけではありません) 。 USE_STANDARD_AS_RULE これは移行用変数です。$(USE_STANDARD_AS_RULE) が定義されて いる場合、%.S ファイルを %.o ファイルや %.s ファイル (%.s ファイルは開発者にとってのみ意味があります) にアセンブル するための標準規則を、Rules.make が提供することになります。 逆に $(USE_STANDARD_AS_RULE) が定義されていないときには、 これらの標準規則は Rules.make からは提供されません。この ような場合は、%.S ファイルをアセンブルするための規則を サブディレクトリ Makefile が個別に提供しなければなりません。 以前は、全ての Makefile が個別に %.S 規則を提供していました。 新しい Makefile では、USE_STANDARD_AS_RULE を定義し、標準の Rules.make 規則を使うようにすることが推奨されます。全アーキ テクチャの Makefile が全て USE_STANDARD_AS_RULE に変更され れば、すぐにでも USE_STANDARD_AS_RULE に対する条件テストを Rules.make から取り除くことができます。そうすれば、他の全ての Makefile からも USE_STANDARD_AS_RULE の定義を削除することが できます。 === 8 新しい形式の変数 『新しい形式の変数』は『古い形式の変数』に比べ、よりシンプルで、 よりパワフルです。結果として、多くのサブディレクトリ Makefile を 60% 以上も縮小することができました。筆者としては、全てのアーキ テクチャ Makefile とサブディレクトリ Makefile が、やがては新しい 形式に変換されれば良いと考えています。 Rules.make は新しい形式の変数を理解できません。このため、新しい 形式の Makefile にはそれぞれ、新しい形式の変数を古い形式の変数に 変換するための定型コードセクションを記述することになります。なお、 ほとんどの変数を『新しい形式』で定義しつつ、数行の記述を『古い 形式』でおこなう、というように混ぜて使うこともできます。 --- 8.1 新しい変数 obj-y obj-m obj-n obj- これらの変数は、$(O_OBJS), $(OX_OBJS), $(M_OBJS), $(MX_OBJS) を置き換えるものです。 例: # drivers/block/Makefile obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o 代入演算子の左辺で $(CONFIG_...) による置換をおこなっていることに 注目してください。こうすると、GNU make が連想インデックスを使える ようになります! 各代入行を古い形式の Makefile で記述しようとすると、 それぞれ 8 行分のコードになってしまいます。 全ての代入を実行すると、サブディレクトリ Makefile 内に 4 つの リスト ――$(obj-y), $(obj-m), $(obj-n), $(obj-)―― が作成 されることになります。 $(obj-y) は vmlinux に組み込まれるファイルのリストです。 $(obj-m) は単一ファイルのモジュールとして構築されるファイルの リストです。 $(obj-n) と $(obj-) は無視されます。 各リストには、ファイルが重複して含まれる場合があります。重複して いるものは、後の処理で自動的に取り除かれます。また、ファイルが $(obj-y) と $(obj-m) の両方に含まれている場合は、自動的に $(obj-m) リストから取り除かれます。 例: # drivers/net/Makefile ... obj-$(CONFIG_OAKNET) += oaknet.o 8390.o ... obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o ... obj-$(CONFIG_STNIC) += stnic.o 8390.o ... obj-$(CONFIG_MAC8390) += daynaport.o 8390.o ... この例では、4 つの異なるドライバが 8390.o 内のコードを必要として います。もしも、これら 4 つのドライバのうち一つでも vmlinux に組み 込まれることになれば、8390.o も一緒に vmlinux に組み込まれることに なります。そのため、8390.o を必要とする他のドライバがモジュールと して構築されたとしても、8390.o はモジュールとして構築 "されません" (なぜなら、モジュール形式のドライバからでも、常駐 vmlinux イメージ 内の 8390.o コードのサービスを利用することができるからです) 。 export-objs $(export-objs) は、シンボルをエクスポートする可能性のあるファイルを 全てリストアップしたものです。このリストを構築する正規の方法は、 次のようになります。 grep -l EXPORT_SYMBOL *.c (但し、インクルードしたヘッダファイルから密かに EXPORT_SYMBOL を 呼び出しているファイルもあるので、注意してください!) これは、あくまでシンボルをエクスポートする可能性のあるファイルを リストアップしただけのものなので、カーネル構成定義の内容には依存 しません。シンボルをエクスポートするファイルは、全て $(export-objs) にリストアップされます。実際のファイルのリストを $(*_OBJS) と $(*X_OBJS) とに振り分ける処理は、$(export-objs) を元にして、定型 コードセクションにより行われます。 経験から言うと、古い形式の Makefile でシンボルをエクスポート するかしないかを適切に維持管理することは、困難であり、間違いの 元になります。新しい形式の Makefile で $(export-objs) リストを 管理するほうが、簡単で、しかもチェックしやすいでしょう。 list-multi $(foo)-objs 複数のオブジェクトファイルで構成されるカーネルモジュールも存在 します。$(list-multi) は、そのようなカーネルモジュールのリスト です。これは静的なリストであり、カーネル構成定義の内容には依存 しません。 $(list-multi) にリストアップされているカーネルモジュールには、 それぞれ、そのモジュールを構成するオブジェクトファイルを全て 列挙したリストがあります。たとえば、foo.o というカーネル モジュール用のオブジェクトファイルのリストは、foo-objs に なります。 例: # drivers/scsi/Makefile list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o ... scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o scsi_error.o \ scsi_obsolete.o scsi_queue.o scsi_lib.o \ scsi_merge.o scsi_dma.o scsi_scan.o \ scsi_syms.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o サブディレクトリ Makefile では、カーネル構成定義の内容に従い、 通常どおり、モジュールを obj-* リストに入れていきます。 obj-$(CONFIG_SCSI) += scsi_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_SCSI_INITIO) += initio.o obj-$(CONFIG_SCSI_INIA100) += a100u2w.o 今、仮に CONFIG_SCSI=y であるとしましょう。この場合、scsi_mod.o を 構成する 14 個のオブジェクトファイルを、全て vmlinux にリンクする 必要があります。そのため、これらのオブジェクトファイルは $(O_OBJS) と $(OX_OBJS) に置かれることになります。そして、合成ファイルである scsi_mod.o は決して生成されません。この作業は、数行のリスト処理命令 からなる定型変換コードにより実行されます。 CONFIG_BLK_DEV_SR=m の場合はどうなるでしょうか。この場合は、 "$(LD) -r" コマンドで 3 つのオブジェクトファイルがリンクされ、 カーネルモジュール sr_mod.o が作成されます。これをおこなうため には、3 つのファイルを $(MI_OBJS) と $(MIX_OBJS) に入れておく 必要があります。合成ファイル sr_mod.o は、$(M_OBJS) に置きます。 これらの作業もまた、定型変換コードにより実行されます。 CONFIG_SCSI_INITIO=n の場合は、initio.o が $(obj-n) リストに 入れられるだけで、他には何も起こりません。initio.o を構成する ファイルはコンパイルされず、合成ファイルも生成されません。 最後になりますが、サブディレクトリ Makefile には、オブジェクト ファイルのリストから合成カーネルモジュールを構築する規則を 定義しておく必要があります。 例: # drivers/scsi/Makefile scsi_mod.o: $(scsi_mod-objs) $(LD) -r -o $@ $(scsi_mod-objs) sr_mod.o: $(sr_mod-objs) $(LD) -r -o $@ $(sr_mod-objs) initio.o: $(initio-objs) $(LD) -r -o $@ $(initio-objs) a100u2w.o: $(a100u2w-objs) $(LD) -r -o $@ $(a100u2w-objs) これらの規則は機械的に記述することができます。ですので、定型コード もしくは Rules.make に、このような規則を自動的に生成するコードを 追加したほうがよいでしょう。しかし、実際に追加されるまでは、サブ ディレクトリ Makefile で明示的に定義する必要があります。 subdir-y subdir-m subdir-n subdir- これらは、$(ALL_SUB_DIRS), $(SUB_DIRS), $(MOD_SUB_DIRS) を置き 換えるものです。 例: # drivers/Makefile subdir-$(CONFIG_PCI) += pci subdir-$(CONFIG_PCMCIA) += pcmcia subdir-$(CONFIG_MTD) += mtd subdir-$(CONFIG_SBUS) += sbus これらの変数は obj-* と同じような動作をしますが、オブジェクト ファイルではなく、サブディレクトリを対象としています。 全ての代入を実行すると、サブディレクトリ Makefile 内に 4 つの リスト ――$(subdir-y), $(subdir-m), $(subdir-n), $(subdir-) ―― が作成されることになります。 $(subdir-y) は、 vmlinux を作成するときに make の対象となるディレクトリの リストです。 $(subdir-m) は、 モジュールを作成するときに make の対象となるディレクトリの リストです。 $(subdir-n) と $(subdir-) は、 ディレクトリ内の全サブディレクトリのリストを収集するという 目的のためだけに使用されます。 subdir-y 以外のリストには、ディレクトリが重複して含まれていても 構いません。重複しているものは、後の処理で自動的に取り除かれます。 mod-subdirs $(subdir-y) にリストアップされたときに、同時に $(subdir-m) にも リストアップされるようにしたいディレクトリは、$(mod-subdirs) に 入れておきます。 例: # fs/Makefile mod-subdirs := nls この例の場合、CONFIG_NFS = y ならば、nls が $(subdir-y) と $(subdir-m) に加えられることになります。 --- 8.2 古い形式への変換 下記の例は drivers/usb/Makefile から取ってきたものです。ここでは、 OX_OBJS と MX_OBJS を使わないようにするため、また、$(obj-y) 内の オブジェクトの順番を管理するため、MIX_OBJS を使用しています。 # Rules.make リストに変換する multi-used := $(filter $(list-multi), $(obj-y) $(obj-m)) multi-obj := $(foreach m, $(multi-used), $($(basename $(m))-objs)) active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m)) O_OBJS := $(obj-y) M_OBJS := $(obj-m) MIX_OBJS := $(filter $(export-objs), $(active-objs)) drivers/acorn/scsi/Makefile にあるライブラリの例も見てみましょう。 # Rules.make リストに変換する L_OBJS := $(filter-out $(export-objs), $(obj-y)) LX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) ライブラリでは順番はそれほど重要ではないので、この例ではいまだに LX_OBJS と MX_OBJS を使用しています。しかし、MIX_OBJS を使って 次のように書き換えることも (おそらく) できるでしょう。 active-objs := $(sort $(obj-y) $(obj-m)) L_OBJS := $(obj-y) M_OBJS := $(obj-m) MIX_OBJS := $(filter $(export-objs), $(active-objs)) こちらのほうが明らかに記述量が少なくて済みますし、すっきり していると言えるでしょう。 === 9 Linux カーネル 2.2 との互換性 いつ何が変更になったのかを示す情報は何もありませんが、このドキュメント 内の情報のほとんどは、2.2 にも適用できます。以下に、Linux カーネル 2.2 と互換性のあるサブディレクトリ Makefile を書くためのヒントを挙げようと 思います。 古い形式の Makefile, または定型調整セクションを持つ新しい形式の Makefile, どちらを書いても構いません。定型コードは、カーネル 2.2 の drivers/sound/Makefile などからコピーすればよいでしょう。 2.2 の Rules.make では、$(MOD_SUB_DIRS) と $(MOD_IN_SUB_DIRS) が 明確に区別されています。サブディレクトリを持たない単一のディレクトリ ならば、このことは問題にはなりません。しかし、しっかりした木構造を 持っている場合は、$(MOD_SUB_DIRS) と $(MOD_IN_SUB_DIRS) の違いを 認識しておく必要があります。$(MOD_SUB_DIRS) のコード例は fs/Makefile 内に、$(MOD_IN_SUB_DIRS) のコード例は drivers/net/Makefile 内に 広範囲にわたって存在するので、そちらを参照するとよいでしょう。 既に MOD_LIST_NAME を使用している場合は、そのまま使い続けてください。 まだ MOD_LIST_NAME を使用していない場合は、使わないようにしてください ――この場合、作成されるモジュールの 2.2 での扱いは 'misc' モジュール となります。 2.2 では、アセンブリ言語用の規則はごちゃごちゃしていました。アセンブリ 言語のファイルがある場合は、各ファイルごとの規則を自分で明示的に記述 することをお勧めします。 === 10 謝辞 本文書のドラフトをレビューしてくれたことに対して、linux-kbuild メーリングリストのメンバーの方々、特に Peter Samuelson と Thomas Molina に感謝します。