Makefile-quick-guide

提供:Dev Guides
移動先:案内検索

なぜMakefileなのか?

ソースコードファイルのコンパイルは、特に複数のソースファイルをインクルードし、コンパイルする必要があるたびにコンパイルコマンドを入力する必要がある場合、疲れる場合があります。 Makefileは、このタスクを簡素化するソリューションです。

メイクファイルは、プロジェクトのビルドと管理を自動的に支援する特別な形式のファイルです。

たとえば、次のソースファイルがあるとします。

  • main.cpp

  • hello.cpp

  • factorial.cpp

  • functions.h

    *main.cpp*

以下は、main.cppソースファイルのコードです-

#include <iostream>

using namespace std;

#include "functions.h"

int main(){
   print_hello();
   cout << endl;
   cout << "The factorial of 5 is " << factorial(5) << endl;
   return 0;
}
*hello.cpp*

以下に示すコードはhello.cppソースファイル用です-

#include <iostream>

using namespace std;

#include "functions.h"

void print_hello(){
   cout << "Hello World!";
}
*factorial.cpp*

factorial.cppのコードは以下のとおりです-

#include "functions.h"

int factorial(int n){

   if(n!=1){
      return(n * factorial(n-1));
   } else return 1;
}
*functions.h*

以下は、fnctions.hのコードです-

void print_hello();
int factorial(int n);

ファイルをコンパイルして実行可能ファイルを取得する簡単な方法は、コマンドを実行することです-

gcc  main.cpp hello.cpp factorial.cpp -o hello

このコマンドは、_hello_バイナリを生成します。 この例では、4つのファイルしかなく、関数呼び出しのシーケンスがわかっています。 したがって、上記のコマンドを入力し、最終的なバイナリを準備することが可能です。

ただし、数千のソースコードファイルがある大規模なプロジェクトでは、バイナリビルドを維持することが困難になります。

*make* コマンドを使用すると、大きなプログラムまたはプログラムのグループを管理できます。 大きなプログラムの作成を開始すると、大きなプログラムの再コンパイルには短いプログラムの再コンパイルよりも時間がかかることがわかります。 さらに、通常はプログラムの小さなセクション(単一の関数など)でのみ作業し、残りのプログラムの多くは変更されないことに気付きます。

次のセクションでは、プロジェクトのメイクファイルを準備する方法を説明します。

Makefile-マクロ

*make* プログラムを使用すると、変数に類似したマクロを使用できます。 マクロはMakefileで=ペアとして定義されます。 以下に例を示しました-
MACROS  = -me
PSROFF  = groff -Tps
DITROFF = groff -Tdvi
CFLAGS  = -O -systype bsd43
LIBS    = "-lncurses -lm -lsdl"
MYFACE  = ":*)"

特別なマクロ

ターゲットルールセットでコマンドを発行する前に、事前定義された特定の特別なマクロがあります-

  • $ @は、作成するファイルの名前です。
  • $? 変更された依存の名前です。

たとえば、次のようなルールを使用できます-

hello: main.cpp hello.cpp factorial.cpp
   $(CC) $(CFLAGS) $? $(LDFLAGS) -o $@

Alternatively:

hello: main.cpp hello.cpp factorial.cpp
   $(CC) $(CFLAGS) [email protected] $(LDFLAGS) -o $@

この例では、$ @は_hello_および$?を表します。 または、$ @。cppは、変更されたすべてのソースファイルを取得します。

暗黙のルールで使用される特別なマクロがさらに2つあります。 彼らは-

  • $ <アクションを引き起こした関連ファイルの名前。 $ ターゲットおよび依存ファイルによって共有されるプレフィックス。

一般的な暗黙のルールは、.cpp(ソースファイル)から.o(オブジェクト)ファイルを作成することです。

.cpp.o:
   $(CC) $(CFLAGS) -c $<

Alternatively:

.cpp.o:
   $(CC) $(CFLAGS) -c $*.c

従来のマクロ

さまざまなデフォルトマクロがあります。 それらを確認するには、「make -p」と入力してデフォルトを出力します。 ほとんどは、それらが使用されるルールから非常に明白です。

これらの事前定義変数、つまり暗黙のルールで使用されるマクロは、2つのクラスに分類されます。 彼らは次のとおりです-

  • プログラムの名前であるマクロ(CCなど) *プログラムの引数を含むマクロ(CFLAGSなど)。

以下は、メイクファイルの組み込みルールでプログラムの名前として使用される一般的な変数のいくつかの表です-

Sr.No Variables & Description
1
  • AR*

アーカイブ管理プログラム。デフォルトは「ar」です。

2

AS

アセンブリファイルをコンパイルするプログラム。デフォルトは「as」です。

3

CC

Cプログラムをコンパイルするプログラム。デフォルトは「cc」です。

4

CO

RCSからファイルをチェックアウトするプログラム。デフォルトは「co」です。

5

CXX

C プログラムをコンパイルするプログラム。デフォルトは「g 」です。

6

CPP

Cプリプロセッサーを実行するためのプログラム。結果は標準出力に出力されます。デフォルトは `$(CC)-E 'です。

7

FC

FortranおよびRatforプログラムをコンパイルまたは前処理するプログラム。デフォルトは `f77 'です。

8

GET

SCCSからファイルを抽出するプログラム。デフォルトは「get」です。

9

LEX

Lex文法をソースコードに変換するために使用するプログラム。デフォルトは「lex」です。

10

YACC

Yacc文法をソースコードに変換するために使用するプログラム。デフォルトは「yacc」です。

11

LINT

ソースコードでlintを実行するために使用するプログラム。デフォルトは「lint」です。

12

M2C

Modula-2ソースコードのコンパイルに使用するプログラム。デフォルトは「m2c」です。

13

PC

Pascalプログラムをコンパイルするためのプログラム。デフォルトは「pc」です。

14

MAKEINFO

TexinfoソースファイルをInfoファイルに変換するプログラム。デフォルトは「makeinfo」です。

15

TEX

TeXソースからTeX dviファイルを作成するプログラム。デフォルトは `tex 'です。

16

TEXI2DVI

TexinfoソースからTeX dviファイルを作成するプログラム。デフォルトは「texi2dvi」です。

17

WEAVE

WebをTeXに変換するプログラム。デフォルトは「weave」です。

18

CWEAVE

C WebをTeXに変換するプログラム。デフォルトは「cweave」です。

19

TANGLE

WebをPascalに翻訳するプログラム。デフォルトは「もつれ」です。

20

CTANGLE

C WebをCに変換するプログラム。デフォルトは「ctangle」です。

21

RM

ファイルを削除するコマンド。デフォルトは「rm -f」です。

上記のプログラムの追加引数が値である変数の表を次に示します。 特に明記しない限り、これらすべてのデフォルト値は空の文字列です。

Sr.No. Variables & Description
1

ARFLAGS

アーカイブ管理プログラムに与えるフラグ。デフォルトは `rv 'です。

2

ASFLAGS

.s 'または .S’ファイルで明示的に呼び出されたときにアセンブラに与える追加のフラグ。

3

CFLAGS

Cコンパイラに与える追加のフラグ。

4

CXXFLAGS

Cコンパイラに与える追加のフラグ。

5

COFLAGS

RCS coプログラムに与える追加のフラグ。

6

CPPFLAGS

Cプリプロセッサとそれを使用するプログラム(CやFortranコンパイラなど)に与える追加フラグ。

7

FFLAGS

Fortranコンパイラーに与える追加のフラグ。

8

GFLAGS

SCCS取得プログラムに与える追加のフラグ。

9

LDFLAGS

コンパイラーがリンカー「ld」を呼び出すことになっているときにコンパイラーに与える追加フラグ。

10

LFLAGS

レックスに与える追加のフラグ。

11

YFLAGS

Yaccに与える追加のフラグ。

12

PFLAGS

Pascalコンパイラに渡す追加のフラグ。

13

RFLAGS

Ratforプログラム用のFortranコンパイラーに与える追加フラグ。

14

LINTFLAGS

糸くずに与える追加フラグ。

-「-R」または「--no-builtin-variables」オプションを使用して、暗黙のルールで使用されるすべての変数をキャンセルできます。

以下に示すように、コマンドラインでマクロを定義することもできます-

make CPP =/home/courses/cop4530/spring02

Makefileでの依存関係の定義

最終的なバイナリがさまざまなソースコードとソースヘッダーファイルに依存することは非常に一般的です。 依存関係は、ターゲットのソースについて make を知らせるために重要です。 次の例を考慮してください-

hello: main.o factorial.o hello.o
   $(CC) main.o factorial.o hello.o -o hello

ここでは、helloはmain.o、factorial.o、hello.oファイルに依存していることを make に伝えます。 したがって、これらのオブジェクトファイルのいずれかが変更されるたびに、 make がアクションを実行します。

同時に、 make に.oファイルの準備方法を伝える必要があります。 したがって、これらの依存関係も次のように定義する必要があります-

main.o: main.cpp functions.h
   $(CC) -c main.cpp

factorial.o: factorial.cpp functions.h
   $(CC) -c factorial.cpp

hello.o: hello.cpp functions.h
   $(CC) -c hello.cpp

Makefileでのルールの定義

Makefileのルールを学習します。

Makefileターゲットルールの一般的な構文は次のとおりです-

target [target...] : [dependent ....]
[ command ...]

上記のコードでは、括弧内の引数はオプションであり、省略記号は1つ以上を意味します。 ここで、各コマンドの前にタブが必要なことに注意してください。

以下に、他の3つのファイルからターゲットを作成するルールを定義する簡単な例を示します。

hello: main.o factorial.o hello.o
   $(CC) main.o factorial.o hello.o -o hello

-この例では、ソースファイルからすべてのオブジェクトファイルを作成するルールを指定する必要があります。

セマンティクスは非常に単純です。 「ターゲットを作る」と言うと、 make は適用されるターゲットルールを見つけます。そして、依存関係のいずれかがターゲットよりも新しい場合、 make はコマンドを一度に1つずつ実行します(マクロ置換後)。 依存関係を作成する必要がある場合は、最初に依存関係が発生します(したがって、再帰が発生します)。

*Make* は、いずれかのコマンドが失敗ステータスを返すと終了します。 そのような場合、次のルールが表示されます-
clean:
   -rm *.o *~ core paper
*Make* は、ダッシュで始まるコマンドラインで返されたステータスを無視します。 たとえば、コアファイルがない場合は誰が気にしますか?
*Make* は、マクロ置換の後、何が起こっているかを示すためにコマンドをエコーし​​ます。 時々、それをオフにしたいかもしれません。 たとえば-
install:
   @echo You must be root to install

人々は、Makefileの特定のターゲットを期待するようになりました。 常に最初に参照する必要があります。 ただし、ターゲットall(またはmakeのみ)、install、およびcleanが検出されることを期待するのは合理的です。

  • make all -アプリケーションをインストールする前にローカルテストを実行できるように、すべてをコンパイルします。
  • make install -アプリケーションを適切な場所にインストールします。
  • make clean -アプリケーションをクリーンアップし、実行可能ファイル、一時ファイル、オブジェクトファイルなどを取り除きます。

Makefileの暗黙のルール

このコマンドは、ソースコードx.cppから実行可能ファイルxをビルドするすべての場合に機能するはずです。 これは暗黙のルールとして述べることができます-

.cpp:
   $(CC) $(CFLAGS) [email protected] $(LDFLAGS) -o $@

この暗黙のルールは、x.cからxを作成する方法を示しています。x.cでccを実行し、出力xを呼び出します。 特定のターゲットが言及されていないため、ルールは暗黙的です。 すべての場合に使用できます。

もう1つの一般的な暗黙のルールは、.cpp(ソースファイル)から.o(オブジェクト)ファイルを作成することです。

.cpp.o:
   $(CC) $(CFLAGS) -c $<

alternatively

.cpp.o:
   $(CC) $(CFLAGS) -c $*.cpp

Makefileでのカスタムサフィックスルールの定義

*Make* は、対応する.cファイルでcc -cを使用して、a.oファイルを自動的に作成できます。 これらのルールは *make* に組み込まれており、この利点を利用してMakefileを短縮できます。 現在のターゲットが依存しているMakefileの依存行で.hファイルのみを指定すると、 *make* は対応する.cfileがすでに必要であることを認識します。 コンパイラーのコマンドを含める必要はありません。

これは、以下に示すように、Makefileをさらに削減します-

OBJECTS = main.o hello.o factorial.o
hello: $(OBJECTS)
   cc $(OBJECTS) -o hello
hellp.o: functions.h

main.o: functions.h
factorial.o: functions.h
*Make* では、_。SUFFIXES_という特別なターゲットを使用して、独自のサフィックスを定義できます。 たとえば、以下の依存関係の行を参照してください-
.SUFFIXES: .foo .bar

これらの特別なサフィックスを使用して独自のルールを作成することを make に通知します。

*make* が_.c_ファイルから_.o_ファイルを作成する方法を既に知っている方法と同様に、次の方法でルールを定義できます-
.foo.bar:
   tr '[A-Z][a-z]' '[N-Z][A-M][n-z][a-m]' < $< > $@
.c.o:
   $(CC) $(CFLAGS) -c $<

最初のルールでは、。foo_ファイルから.bar_ファイルを作成できます。 基本的にファイルをスクランブルします。 2番目のルールは、。c_ファイルから.o_ファイルを作成するために make によって使用されるデフォルトのルールです。

Makefile-ディレクティブ

さまざまな形式で利用可能な多数のディレクティブがあります。 システム上の make プログラムは、すべてのディレクティブをサポートしていない場合があります。 あなたの make がここで説明しているディレクティブをサポートしているかどうかを確認してください。 GNU make はこれらのディレクティブをサポートしています。

条件付きディレクティブ

条件付きディレクティブは-

  • ifeq ディレクティブは条件を開始し、条件を指定します。 コンマで区切られ、括弧で囲まれた2つの引数が含まれています。 両方の引数で変数置換が実行され、それらが比較されます。 ifeqに続くmakefileの行は、2つの引数が一致する場合に従います。それ以外の場合は無視されます。
  • ifneq ディレクティブは条件を開始し、条件を指定します。 コンマで区切られ、括弧で囲まれた2つの引数が含まれています。 両方の引数で変数置換が実行され、それらが比較されます。 2つの引数が一致しない場合、ifneqに続くメイクファイルの行に従います。それ以外の場合は無視されます。
  • ifdef ディレクティブは条件を開始し、条件を指定します。 単一の引数が含まれます。 指定された引数がtrueの場合、条件はtrueになります。
  • ifndef ディレクティブは条件を開始し、条件を指定します。 単一の引数が含まれます。 指定された引数がfalseの場合、条件はtrueになります。
  • else ディレクティブは、前の条件が失敗した場合、次の行に従います。 上記の例では、これは、最初の代替が使用されない場合は常に2番目の代替リンクコマンドが使用されることを意味します。 条件にelseを含めることはオプションです。
  • endif ディレクティブは条件を終了します。 すべての条件はendifで終わる必要があります。

条件ディレクティブの構文

他のない単純な条件付き構文は次のとおりです-

conditional-directive
   text-if-true
endif

text-if-trueは任意のテキスト行で、条件がtrueの場合にメイクファイルの一部と見なされます。 条件が偽の場合、代わりにテキストは使用されません。

複雑な条件の構文は次のとおりです-

conditional-directive
   text-if-true
else
   text-if-false
endif

条件が真の場合、text-if-trueが使用されます。それ以外の場合、text-if-falseが使用されます。 text-if-falseには、テキストの任意の行数を指定できます。

条件ディレクティブの構文は、条件が単純であろうと複雑であろうと同じです。 さまざまな条件をテストする4つの異なるディレクティブがあります。 彼らは与えられたとおりです-

ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"

上記の条件の反対のディレクティブは次のとおりです-

ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2"

条件付きディレクティブの例

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
   $(CC) -o foo $(objects) $(libs_for_gcc)
else
   $(CC) -o foo $(objects) $(normal_libs)
endif

includeディレクティブ

  • includeディレクティブ*を使用すると、 make は現在のメイクファイルの読み取りを一時停止し、続行する前に1つ以上の他のメイクファイルを読み取ります。 ディレクティブは、次のように見えるメイクファイル内の行です-
include filenames...

ファイル名には、シェルファイル名のパターンを含めることができます。 行の先頭では余分なスペースを使用できますが、タブは使用できません。 たとえば、3つの「.mk」ファイル、つまり「a.mk」、「b.mk」、および「c.mk」、および$(bar)がある場合、bish bashに展開され、次に表現。

include foo *.mk $(bar)

is equivalent to:

include foo a.mk b.mk c.mk bish bash
*make* がincludeディレクティブを処理すると、makefileの読み取りを一時停止し、リストされた各ファイルから順番に読み取ります。 それが終了すると、 *make* はディレクティブが含まれるmakefileの読み取りを再開します。

オーバーライドディレクティブ

コマンド引数で変数が設定されている場合、makefile内の通常の割り当ては無視されます。 コマンド引数で設定された変数をメイクファイルに設定したい場合は、オーバーライドディレクティブを使用できます。

override variable = value

or

override variable := value

Makefile-再コンパイル

*make* プログラムはインテリジェントなユーティリティであり、ソースファイルで行った変更に基づいて機能します。 main.cpp、hello.cpp、factorial.cpp、およびfunctions.hの4つのファイルがある場合、残りのすべてのファイルはfunctions.hに依存し、main.cppはhello.cppとfactorial.cppの両方に依存します。 したがって、functions.hに変更を加えると、 *make* はすべてのソースファイルを再コンパイルして新しいオブジェクトファイルを生成します。 ただし、main.cppを変更すると、これは他のファイルに依存しないため、main.cppファイルのみが再コンパイルされ、help.cppとfactorial.cppは変更されません。

ファイルのコンパイル中、 make はオブジェクトファイルをチェックし、タイムスタンプを比較します。 ソースファイルにオブジェクトファイルより新しいタイムスタンプがある場合、ソースファイルが変更されたと仮定して、新しいオブジェクトファイルを生成します。

再コンパイルの回避

数千のファイルで構成されるプロジェクトが存在する場合があります。 ソースファイルを変更した場合でも、それに依存するすべてのファイルを再コンパイルしたくない場合があります。 たとえば、他のファイルが依存するヘッダーファイルにマクロまたは宣言を追加するとします。 保守的であるため、 make はヘッダーファイルの変更にはすべての依存ファイルの再コンパイルが必要であることを前提としていますが、再コンパイルが不要であり、コンパイルを待つ時間を無駄にしないことを知っています。

ヘッダーファイルを変更する前に問題を予測した場合は、-tフラグを使用できます。 このフラグは、ルール内のコマンドを実行するのではなく、最終変更日を変更してターゲットを最新の状態にマークするように make に指示します。 あなたはこの手順に従う必要があります-

  • コマンド `make 'を使用して、本当に再コンパイルが必要なソースファイルを再コンパイルします。
  • ヘッダーファイルに変更を加えます。
  • コマンド `make -t 'を使用して、すべてのオブジェクトファイルを最新としてマークします。 次回makeを実行すると、ヘッダーファイルの変更によって再コンパイルは発生しません。

一部のファイルが再コンパイルを必要とするときにヘッダーファイルを既に変更している場合、これを行うには遅すぎます。 代わりに、指定されたファイルを「古い」としてマークする「-o file」フラグを使用できます。 つまり、ファイル自体は再作成されず、そのアカウントでは他の何も再作成されません。 あなたはこの手順に従う必要があります-

  • `make -o header file 'を使用して、特定のヘッダーファイルとは無関係の理由でコンパイルが必要なソースファイルを再コンパイルします。 複数のヘッダーファイルが関係している場合は、ヘッダーファイルごとに個別の「-o」オプションを使用します。
  • すべてのオブジェクトファイルを「make -t」で更新します。

Makefile-その他の機能

この章では、Makefileのその他のさまざまな機能について説明します。

Makeの再帰的な使用

*make* を再帰的に使用するということは、 *make* をメイクファイルのコマンドとして使用することを意味します。 この手法は、より大きなシステムを構成するさまざまなサブシステム用に別々のメイクファイルが必要な場合に役立ちます。 たとえば、独自のmakefileを持つ「subdir」という名前のサブディレクトリがあり、そのディレクトリのmakefileでサブディレクトリで *make* を実行するとします。 あなたは以下のコードを書くことでそれを行うことができます-
subsystem:
   cd subdir && $(MAKE)

or, equivalently:

subsystem:
   $(MAKE) -C subdir

この例をコピーするだけで、再帰的な make コマンドを作成できます。 ただし、それらがどのように機能し、なぜ、そしてサブメイクがトップレベルのメイクにどのように関連するかについて知る必要があります。

サブメイクへの変数の伝達

最上位の make の変数値は、明示的な要求によって環境を通じてサブメイクに渡すことができます。 これらの変数は、サブメイクでデフォルトとして定義されています。 `-e 'スイッチを使用しない限り、サブmake makefileで使用されるmakefileで指定されているものをオーバーライドすることはできません。

変数を渡す、またはエクスポートするには、 make は変数とその値を環境に追加して、各コマンドを実行します。 サブメイクは、環境を使用して変数値のテーブルを初期化します。

特別な変数SHELLおよびMAKEFLAGSは常にエクスポートされます(エクスポートをアンエクスポートしない限り)。 MAKEFILESは、何かに設定するとエクスポートされます。

特定の変数をサブメイクにエクスポートする場合は、以下に示すように、エクスポートディレクティブを使用します-

export variable ...

変数がエクスポートされないようにする場合は、以下に示すように、unexportディレクティブを使用します-

unexport variable ...

変数MAKEFILES

環境変数MAKEFILESが定義されている場合、 make は、その値を他のメイクファイルの前に読み込まれる追加のメイクファイルの名前(空白で区切られた)のリストと見なします。 これはincludeディレクティブと同じように機能します。さまざまなディレクトリでそれらのファイルが検索されます。

MAKEFILESの主な用途は、 make の再帰呼び出し間の通信です。

異なるディレクトリのヘッダーファイルを含める

ヘッダーファイルを別のディレクトリに配置し、別のディレクトリで make を実行している場合、ヘッダーファイルのパスを指定する必要があります。 これは、メイクファイルの-Iオプションを使用して実行できます。 functions.hファイルが/home/finddevguides/headerフォルダーにあり、残りのファイルが/home/finddevguides/src/フォルダーにあるとすると、makefileは次のように記述されます-

INCLUDES = -I "/home/finddevguides/header"
CC = gcc
LIBS =  -lm
CFLAGS = -g -Wall
OBJ =  main.o factorial.o hello.o

hello: ${OBJ}
   ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}
.cpp.o:
   ${CC} ${CFLAGS} ${INCLUDES} -c $<

変数にさらにテキストを追加する

多くの場合、すでに定義されている変数の値にテキストを追加すると便利です。 これを行うには、次のように「+ =」を含む行を使用します-

objects += another.o

変数オブジェクトの値を取得し、テキスト「another.o」を追加します。次に示すように、スペースを1つ付けます。

objects = main.o hello.o factorial.o
objects += another.o

上記のコードは、オブジェクトを「main.o hello.o factorial.o another.o」に設定します。

`+ = 'の使用は次のようになります。

objects = main.o hello.o factorial.o
objects := $(objects) another.o

Makefileの継続行

Makefileの大きすぎる行が気に入らない場合は、以下に示すようにバックスラッシュ「\」を使用して行を分割できます-

OBJ =  main.o factorial.o \
   hello.o

is equivalent to

OBJ =  main.o factorial.o hello.o

コマンドプロンプトからMakefileを実行する

「Makefile」という名前のMakefileを準備した場合は、コマンドプロンプトでmakeと記述するだけでMakefileファイルが実行されます。 しかし、あなたがMakefileに他の名前を付けている場合は、次のコマンドを使用します-

make -f your-makefile-name

Makefile-例

これは、helloプログラムをコンパイルするためのMakefileの例です。 このプログラムは、3つのファイル_main.cpp factorial.cpp_、および_hello.cpp_で構成されています。

# Define required macros here
SHELL =/bin/sh

OBJS =  main.o factorial.o hello.o
CFLAG = -Wall -g
CC = gcc
INCLUDE =
LIBS = -lm

hello:${OBJ}
   ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}

clean:
   -rm -f *.o core *.core

.cpp.o:
   ${CC} ${CFLAGS} ${INCLUDES} -c $<

これで、 make を使用してプログラム hello をビルドできます。 コマンド make clean を発行すると、現在のディレクトリで使用可能なすべてのオブジェクトファイルとコアファイルが削除されます。