第46回
makeによるマルチモジュール開発の合理化

デフォルト・ルールを使った簡略表記

LSI-Cのmakeには、ファイルの拡張子を利用したリスト2のような"MAKEDEF"というデフォルト・ルール・ファイル(標準規則ファイル)が用意されています。これを利用すると、makefileの記述を簡略化できます。

基本的な規則は分かりきっている

たとえば「拡張子 .cのソースファイルからは拡張子 .objのオブジェクトファイルが生成される」「拡張子 .objのオブジェクトファイルからは拡張子 .exeの実行形式ファイルが生成される」ということは、わざわざ明示するまでもない規則です。

さらに、datinit.cというソースファイルからはdatinit.objというオブジェクトファイルが生成される――というように、ソースファイル名とオブジェクトファイル名が同じになることも、厳密な規則ではありませんが慣習として一般的です。

そういった拡張子によってある程度自動的に決まる規則がMAKEDEFに記述されており、makeはこれにもとづいて処理を行います。

リスト2:デフォルト・ルールを記述したMAKEDEF
#default rules for make
.SUFFIXES: .obj .a86 .p86 .c .y
YFLAGS =
CFLAGS =
AFLAGS =
.y.c:
    yacc $YFLAGS $<
.y.obj:
    yacc $YFLAGS $<
    lcc $CFLAGS -c -o $@ $*.c
    del $*.c
.p86.obj .c.obj:
    lcc $CFLAGS -c -o $@ $<
.a86.obj:
    r86 $AFLAGS -o $@ $<
.obj.exe .c.exe .a86.exe:
    lcc $CFLAGS -o $@ $#

簡略表記は便利だが注意も必要

MAKEDEFはあくまで一般的な規則とコマンドラインを記述したものなので、どのような場合でもそのまま利用できるとは限りません。

日本語を扱うプログラムの開発では
CFLAGS = -j
を追記するなど、部分的にコマンドラインオプションを補足する必要があります。たとえばMAKEDEFに上のような追記を行った場合、makefileにはstconvの生成規則としてリスト3のように記述するだけで済みます。

ただし、こういった簡略表記に関するルールはプラットフォーム(OS)や処理系によって異なります。ドキュメントをよく読んで、記述と動作の関係を理解しておきましょう。記述を間違えると、正しい生成過程が実行されないこともあります。

リスト3:MAKEDEFを利用して簡略化したmakefile
    # stconv.exe を生成するためのルール
    stconv.exe : stconv.obj datinit.obj convert.obj
      LCC -ostconv.exe stconv.obj datinit.obj convert.obj
    stconv.obj datinit.obj convert.obj : stconv.h


コマンドラインによる開発では、makeは非常に有効なツールとなります。

今回はWindowsのコマンドプロンプト(DOS窓)から実行できるLSI-Cのmakeを紹介しましたが、Visual C++にもコマンドライン版のコンパイラとともにNMAKE.EXEというツールが付属しています。

makeの本家であるUNIX系OSのGCCでも、もちろんmakeを利用できます。

★注意

サンプルソースでは、リスト3の簡略版makefileを"short MakeFile"という名前で保存してあります。動作を試す場合は、まずmakefileの名前を変更するかほかのフォルダに移動した後で、short MakeFileをmakefileに変更してからmakeを実行してください。

あとがき

hiropの『ちょっと気になる専門用語』~《makeとビルド》

makeはUNIXの定番

今回紹介したmakeはUNIX系OSの定番ツールで、C以外のさまざまな言語でも用いられます。

Linuxを使ったことのある人ならご存じと思いますが、UNIX系OSではプログラムをソースファイルで配布することが一般的で、その際にはソースファイルやドキュメント類とともにmakefileも一緒に配布されます。

今回紹介したように、makeは
どのファイルが変更されていれば
どのようなコマンド実行するか
というルールにもとづく動作を行うだけなので、「動作」がCのコンパイラである必要はありません。

ビルドとメイクの違い

さて、makeと似た機能にVisual Studioの「ビルド」があります。ともに、ソースファイルの変更に合わせて無駄のない生成過程を実行する機能です。両者には以下のような違いがあります。

・ビルド(build)
統合環境のプロジェクトで複数の(ユーザーからは見えないものも含む)ソースを管理させ、それらのコンパイルとリンクをすべて自動的に制御して実行形式ファイルを生成させる仕組み。

・メイク(make)
ユーザー(開発者)がソースファイルやオブジェクトファイルの関連(依存関係)を明示し、意図的にコンパイラとリンカを制御して効率的に実行形式ファイルを生成させる仕組み。

ビルドの基本はメイクと同じ

統合環境で1つのプログラムを生成するためのソースファイル群をプロジェクトとして統合管理している環境では、ファイル同士の依存関係を自動的に判別できます。そこで、開発者がわざわざ依存関係を調べて記述する手間を省き、コンパイルとリンクを効率的に実行するのがビルドです。

一方、統合環境を使用しないコマンドラインでの開発では、ファイル同士の依存関係を自動的に構成することはできません。そこで、開発者自身が依存関係と実行する処理をmakefileに明記することになります。

なお、統合環境のビルドも、先述したmakeのデフォルト・ルールにもとづくmakefileの簡略表記の仕組み――たとえば『xyz.cからはxyz.objが生成される』など――が応用されています。

要するに、ビルドは統合環境による生成処理の自動化、makeはコマンドラインによる明示的・意図的な生成処理の効率化を目指す機能、ということです。