CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
$@
と$<
は正確に何をしますか?
$@
は生成されるファイルの名前、$<
は最初の前提条件(通常はソースファイル)です。これらすべての特殊変数のリストは GNU Makeマニュアル にあります。
たとえば、次のような宣言を考えます。
all: library.cpp main.cpp
この場合:
$@
はall
に評価されます$<
はlibrary.cpp
に評価されます$^
はlibrary.cpp main.cpp
に評価されます$@
と$<
は自動変数と呼ばれます。変数$@
は作成されたファイルの名前(つまりターゲット)を表し、$<
は出力ファイルを作成するために必要な最初の前提条件を表します。
例えば:
hello.o: hello.c hello.h
gcc -c $< -o $@
ここで、hello.o
は出力ファイルです。これが$@
の展開先です。最初の依存関係はhello.c
です。それが$<
の拡張です。
-c
フラグは.o
ファイルを生成します。より詳しい説明はman gcc
を見てください。 -o
は作成する出力ファイルを指定します。
詳細については、 このLinux Makefilesに関する記事 を参照してください。
また、 GNU make
のマニュアル をチェックすることもできます。 Makefileを作成してデバッグするのが簡単になります。
このコマンドを実行すると、メークファイルデータベースが出力されます。
make -p
GNUMake、第3版を使ったプロジェクト管理 (これはGNU Free Documentation Licenseの下にあります):
自動変数は、ルールが一致した後に
make
によって設定されます。ターゲットリストと前提条件リストの要素にアクセスできるため、ファイル名を明示的に指定する必要はありません。これらはコードの重複を避けるために非常に役立ちますが、より一般的なパターンルールを定義するときに重要です。7つの「コア」自動変数があります。
$@
:ターゲットを表すファイル名.
$%
:アーカイブメンバ指定のファイル名要素。
$<
:最初の前提条件のファイル名.
$?
:ターゲットよりも新しいすべての前提条件の名前。スペースで区切っています。
$^
:すべての前提条件のファイル名。スペースで区切られています。このリストでは、コンパイル、コピーなどのほとんどの用途で重複ファイルが不要なため、重複ファイル名が削除されています。
$+
:$^
と同様に、これはスペースで区切られたすべての前提条件の名前です。ただし、$+
は重複を含みます。この変数は、重複する値に意味があるリンカへの引数など、特定の状況用に作成されました。
$*
:ターゲットファイル名の語幹。語幹は通常、接尾辞のないファイル名です。パターンルール以外での使用はお勧めできません。さらに、上記の各変数には、他のmakeとの互換性のために2つのバリエーションがあります。 1つの変形は値のディレクトリ部分だけを返します。これは、シンボル
$(@D)
、$(<D)
などに「D」を追加することによって示されます。他のバリアントは、値のファイル部分だけを返します。これは、シンボル、$(@F)
、$(<F)
などに「F」を追加することで示されます。これらのバリアント名は1文字以上の長さであるため、括弧で囲む必要があります。 GNU makeは、dir関数とnotdir関数を使用した、より読みやすい選択肢です。
$@
と$<
は特別なマクロです。
どこで:
$@
はターゲットのファイル名です。
$<
は最初の依存関係の名前です。
main.cpp
、hello.cpp
、factorial.cpp
のいずれかが変更された場合、Makefileはhello
実行可能ファイルをビルドします。その仕様を実現するための最小のMakefileは、次のとおりです。
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
上記を改善するために、編集されたC++ファイルのみをコンパイルします。それから、結果のオブジェクトファイルを一緒にリンクします。
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
main.o: main.cpp
g++ -c main.cpp
hello.o: hello.cpp
g++ -c hello.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
これを改善するために、すべてのオブジェクトファイルの規則を単一の.cpp.o
規則に置き換えることができます。
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
.cpp.o:
g++ -c $< -o $@
ここで.cpp.o
ルールはanyfile.o
からanyfile.cpp
を構築する方法を定義します。
$<
は最初の依存関係に一致します。この場合、anyfile.cpp
$@
はターゲット、この場合はanyfile.o
に一致します。Makefileに存在するその他の変更は以下のとおりです。
ソースをコンパイルしたいが、別のディレクトリにオブジェクトがある場合の例:
あなたがする必要があります:
gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...
しかし、ほとんどの場合(他のマクロを使用)、結果は次のようになります。
gcc -c -o <all OBJ path> <all SRC path>
したがって、これは何もコンパイルしません^^、uはオブジェクトファイルを別のディレクトリに置くことはできません:(
解決策は、これらの特別なマクロを使用することです
$@ $<
これにより、SRCの各.cファイル(src/file.c)に対して.oファイル(obj/file.o)が生成されます。
$(OBJ):$(SRC)
gcc -c -o $@ $< $(HEADERS) $(FLAGS)
その意味は :
$@ = $(OBJ)
$< = $(SRC)
ただし、OBJのすべての行のINSTEAD行ごとに、SRCのすべての行が続く