GNU makeで使うMakefileの基本的な機能の説明はほぼ網羅できた。もう少しだけ、知っていると便利な機能を紹介しておこう。それでほとんどのMakefileはある程度読めるようになるはずだ。

Makefileを分けて使う - include

Makefileは育てていくと大きな塊になってくる。内容を整理していくと、ほかのところで使っているMakefileと共通する部分が結構出てくるのだ。ほとんど同じ内容が複数のMakefileに存在している状態になってきたら「include」の出番だ。

Makefileにはincludeという命令が用意されており、引数に指定されたパスのファイルを読み込むことができるようになっている。同じような部分が多くのMakefileに存在するようになってきたら、それらを整理して1つのファイルにまとめ、そのファイルをincludeして使えばよい。

このようにMakefileを意味や用途ごとに複数のMakefileに分割しておけば、主となるMakefileには本来記述したい内容だけを書いておくようにでき、見通しがよくなる。さらに、ほかのMakefileを作る際には、必要に応じて既存のMakefileをincludeで読み込めばよいため、作成速度が早くなるという側面もある。ある程度Makefileが使えるようになったらぜひ使いたい機能だ。

includeの基本的な使い方

includeは実際に使い方を見るのが理解が早い。まず、次のようにファイルを用意し、フォルダに配置する。

% tree
.
├── Makefile
└── mk
    ├── inc01.mk
    └── inc02.mk

1 directory, 3 files
% 

「Makefile」が本体、「mk/inc01.mk」と「mk/inc02.mk」が読み込まれるファイルだ。

includeを使う際、読み込まれる方のファイルの拡張子を「.mk」にするというのも、よくやる方法だ。厳密に決まっているわけではないのだが、慣例的にこの拡張子が使われることが多い。

それぞれ次のような内容にしておく。

◆Makefile

test: target1 target2
    @echo "----"
    @echo test:
    @echo -n "  pwd: "
    @pwd

include mk/inc01.mk
include mk/inc02.mk

◆mk/inc01.mk

target1:
    @echo "--------"
    @echo target1: mk/inc01.mk
    @echo -n "  pwd: "
    @pwd

◆mk/inc02.mk

target2:
    @echo "----"
    @echo target2: mk/inc02.mk
    @echo -n "  pwd: "
    @pwd

実行すると次のようになる。

% make
--------
target1: mk/inc01.mk
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
----
target2: mk/inc02.mk
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
----
test:
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
% 
  • 実行結果

    実行結果

ここで注目しておきたいのは、pwdコマンドの実行結果だ。Makefileとmk/inc01.mkは同じディレクトリにはない。しかし、pwdの結果はmakeコマンドを実行したディレクトリになっている。つまり、このMakefileは次のような状態になっているのと同じということになる。

test: target1 target2
    @echo "----"
    @echo test:
    @echo -n "  pwd: "
    @pwd

target1:
    @echo "--------"
    @echo target1: mk/inc01.mk
    @echo -n "  pwd: "
    @pwd

target2:
    @echo "----"
    @echo target2: mk/inc02.mk
    @echo -n "  pwd: "
    @pwd

このinclude機能はGNU make以外のmakeにも存在するが、読み込みの規則が異なっていることがある。どのように動くは、きちんと把握しておく必要がある。

includeで読み込むときはパスに注意

includeが使えるようになると、includeしたファイルの中でさらにincludeしたいというケースも出てくる。複雑になってしまうのであまりやらない方が良いと思うのだが、機能としてはそういった使い方もできる。

例えば次のように、「Makefile」→「mk/inc01.mk」→「inc02.mk」と読み込んでいくように書いてみよう。

◆Makefile

test: target1 target2
    @echo "----"
    @echo test:
    @echo -n "  pwd: "
    @pwd

include mk/inc01.mk

◆mk/inc01.mk

target1:
    @echo "--------"
    @echo target1: mk/inc01.mk
    @echo -n "  pwd: "
    @pwd

include inc02.mk

◆mk/inc02.mk

target2:
    @echo "----"
    @echo target2: mk/inc02.mk
    @echo -n "  pwd: "
    @pwd

実行すると次のようになる。

% make
mk/inc01.mk:7: inc02.mk: No such file or directory
make: *** ターゲット 'inc02.mk' を make するルールがありません.  中止.
% 

この書き方だとエラーになる。mk/inc01.mkとmk/inc02.mkは同じディレクトリにある。そう考えると、inc01.mkには「include inc02.mk」と書くのが自然のように見える。実際、そのように機能するmakeの実装系もある。しかし、GNU makeの実装は違うのだ。

まず、Makefileは次のように展開される。

test: target1 target2
    @echo "----"
    @echo test:
    @echo -n "  pwd: "
    @pwd

target1:
    @echo "--------"
    @echo target1: mk/inc01.mk
    @echo -n "  pwd: "
    @pwd

include inc02.mk

となると、「include inc02.mk」ではエラーになってしまう。ここは「include mk/inc02.mk」と書いていないと動かないというわけだ。

GNU makeのincludeは指定パスに関してこのような挙動になっているため、大本となるファイルからの相対パスで指定する必要がある。この部分は実装系によって異なるため、ほかのmakeを使う場合には実装がどうなっているか確認してから使うようにしよう。

include先でさらにincludeする場合の書き方サンプル

先ほどのファイルを動くように書き換えると次のようになる。

◆Makefile

test: target1 target2
    @echo "----"
    @echo test:
    @echo -n "  pwd: "
    @pwd

include mk/inc01.mk

◆mk/inc01.mk

target1:
    @echo "--------"
    @echo target1: mk/inc01.mk
    @echo -n "  pwd: "
    @pwd

include mk/inc02.mk

◆mk/inc02.mk

target2:
    @echo "----"
    @echo target2: mk/inc02.mk
    @echo -n "  pwd: "
    @pwd

実行すると次のようになる。

% make
--------
target1: mk/inc01.mk
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
----
target2: mk/inc02.mk
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
----
test:
        pwd: /home/daichi/Documents/lwt/20220802/stuffs
%

想定通りに動いていることがわかる。

Makefileの分け方に正解はない

Makefileの内容はユーザーのやりたいことによってさまざまなので、どのようなファイルに分割するのが最適かという正解は示しにくい。意味的に分割しつつ、再利用性の高いものにまとめられるかどうかがポイントになる。うまくまとめられると、さまざまなプロジェクトに流用できるようになるので便利だ。

分ければ良いというものでもない。細かく分割しすぎると返ってわかりにくくなる。この辺りはセンスも問われる。Makefileをきれいに分けられるようになったら、相当高いレベルに到達していると考えて良いだろう。

参考