make-default - Makefile 内でデフォルトのターゲットを任意に変更する

目的

コマンドラインでターゲットを指定せずにmakeを実行したとき、ビルドされるのはMakefileの最初に定義されたターゲットになる。
この「デフォルトターゲット」を、Makefile内で任意のものに変更したい。

結論

GNU Make 3.81(かそれ以降)を使って、.DEFAULT_GOAL 変数をMakefile内で設定すればよい。


以下、詳細。

背景と動機

大きなソースツリーでは、システム全体で使うMakefileを個々のディレクトリのMakeilfeがincludeして使う、という構成になっている場合が多い。
たとえば以下のような感じで、個々のMakefileがmk/env.mkをincludeして、変数定義やビルド方法などを共通化している。

  + TOP
    + mk
      + env.mk    <----+--+
    + src              |  | 共通のファイルをinclude
      + subdir1        |  |
        + Makefile  ---+  |
      + subdir2           |
        + Makefile  ------+

このとき、共通のMakefileが多数あってinclude関係が複雑になっていると、個々のMakefile内の記述の自由度が少なく、色々と困る場合がある。

今、includeの都合で最初に定義できないターゲットを、makeのデフォルトターゲットにしたくて困っているとしよう。

マニュアルで該当機能を発見

GNU Makeのマニュアル(GNU make)によると、

3.6 Other Special Variables

GNU make also supports other special variables....

.DEFAULT_GOAL
Sets the default goal to be used if no targets were specified on the command line....

とあり、.DEFAULT_GOALという変数を設定すれば、デフォルトターゲットを任意に変更できるようだ。

テスト用のファイル

以下のファイルで、.DEFAULT_GOAL の動作テストをする。

default-target.mk
https://sssvn.jp/svn/spikelet/make/default-target.mk
.DEFAULT_GOAL := 2nd

1st:
        @echo $@
2nd:
        @echo $@

以下のようになれば、目的達成。

% make -f default-target.mk
2nd

makeのバージョンにより動作がことなる

手元の環境*1ではうまくいかない。

% make -f default-target.mk
1st
% make -v | head -1
GNU Make 3.80

GNU makeのマニュアルは3.81を対象に書かれているので、3.81でためしてみると、今度は成功。

% make -f default-target.mk
2nd
% make -v | head -1
GNU Make 3.81

ソースを解析する

GNU make 3.81 では、以下のような処理をしている。

  • デフォルトゴールについて、2つの変数がある
    • default_goal_name: .DEFAULT_GOAL_NAME の値
    • default_goal_file: 最初に定義されたターゲット
  • コマンドラインでターゲット指定無しの場合
    1. default_goal_name が定義済みなら、これをビルドする
    2. (そうでなければ)default_goal_file をビルドする
main.c: main() にて、
  {
    struct variable *v = define_variable (".DEFAULT_GOAL", 13, "", o_file, 0);
    default_goal_name = &v->value;
  }
  // グローバル変数 "default_goal_name" の領域を確保
  // その他にも、.DEFAULT_GOALが存在しない場合の処理がある

read.c: eval() にて、
        if (**default_goal_name == '\0' && set_default)
          {
          ....
                if (!reject)
                  {
                    define_variable_global (".DEFAULT_GOAL", 13, t->name,
                                            o_file, 0, NILF);
                    break;
                  }
          ....
          }
  // デフォルトターゲットが指定されていない場合は、依存リストで先頭にある(有効な)ものをターゲットを設定する

一方 GNU make 3.80 では、default_goal_name に関する処理が無い。ターゲット未指定時はdefault_goal_nameのみを処理する。

つまり、.DEFAULT_GOAL 変数での指定は、GNU make 3.81 で導入されたもの。

念のためChangeLogを確認


GNU make 3.81 の ChangeLog で以下を発見:

2005-05-03  Paul D. Smith  <psmith@gnu.org>

        Rename .DEFAULT_TARGET to .DEFAULT_GOAL: in GNU make terminology
        the targets which are to ultimately be made are called "goals";
        see the GNU make manual.  Also, MAKECMDGOALS, etc.

2005-03-09  Boris Kolpackov  <boris@kolpackov.net>

        * main.c (main): Use o_file instead of o_default when defining
        the .DEFAULT_TARGET special variable.
        * read.c (eval): Use define_variable_global() instead of
        define_variable() when setting new value for the .DEFAULT_TARGET
        special variable.  Fixes Savannah bug #12266.

2005-02-28  Boris Kolpackov  <boris@kolpackov.net>

        Implementation of the .DEFAULT_TARGET special variable.

3.80が2002-10-03、3.81が2006-04-01リリースなので、たしかに.DEFAULT_GOAL機能は3.81以降でしか使えないことを確認した。