Linux カーネル Makefile
2000 年 9 月 14 日
Michael Elizabeth Chastain, <mec@shout.net>

翻訳団体: JF プロジェクト (http://www.linux.or.jp/JF/)
  翻訳者: 川崎 貴彦 <takahiko@hakubi.co.jp>
  校正者: 佐野 武俊 <kgh12351@nifty.ne.jp>
  校正者: 小林 雅典 <zap03216@nifty.ne.jp>



=== 目次

本ドキュメントは、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 に感謝します。
