web-dev-qa-db-ja.com

メイクファイルのシンボル$ @と$ <はどういう意味ですか?

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 $@

$@$<は正確に何をしますか?

339
Mohit Deshpande

$@は生成されるファイルの名前、$<は最初の前提条件(通常はソースファイル)です。これらすべての特殊変数のリストは GNU Makeマニュアル にあります。

たとえば、次のような宣言を考えます。

all: library.cpp main.cpp

この場合:

  • $@allに評価されます
  • $<library.cppに評価されます
  • $^library.cpp main.cppに評価されます
412
bdonlan

$@$<自動変数と呼ばれます。変数$@は作成されたファイルの名前(つまりターゲット)を表し、$<は出力ファイルを作成するために必要な最初の前提条件を表します。
例えば:

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 
67

GNUMake、第3版を使ったプロジェクト管理 (これはGNU Free Documentation Licenseの下にあります):

自動変数は、ルールが一致した後にmakeによって設定されます。ターゲットリストと前提条件リストの要素にアクセスできるため、ファイル名を明示的に指定する必要はありません。これらはコードの重複を避けるために非常に役立ちますが、より一般的なパターンルールを定義するときに重要です。

7つの「コア」自動変数があります。

  • $@:ターゲットを表すファイル名.

  • $%:アーカイブメンバ指定のファイル名要素。

  • $<:最初の前提条件のファイル名.

  • $?:ターゲットよりも新しいすべての前提条件の名前。スペースで区切っています。

  • $^:すべての前提条件のファイル名。スペースで区切られています。このリストでは、コンパイル、コピーなどのほとんどの用途で重複ファイルが不要なため、重複ファイル名が削除されています。

  • $+$^と同様に、これはスペースで区切られたすべての前提条件の名前です。ただし、$+は重複を含みます。この変数は、重複する値に意味があるリンカへの引数など、特定の状況用に作成されました。

  • $*:ターゲットファイル名の語幹。語幹は通常、接尾辞のないファイル名です。パターンルール以外での使用はお勧めできません。

さらに、上記の各変数には、他のmakeとの互換性のために2つのバリエーションがあります。 1つの変形は値のディレクトリ部分だけを返します。これは、シンボル$(@D)$(<D)などに「D」を追加することによって示されます。他のバリアントは、値のファイル部分だけを返します。これは、シンボル、$(@F)$(<F)などに「F」を追加することで示されます。これらのバリアント名は1文字以上の長さであるため、括弧で囲む必要があります。 GNU makeは、dir関数とnotdir関数を使用した、より読みやすい選択肢です。

45
alex

$@$<は特別なマクロです。

どこで:

$@はターゲットのファイル名です。

$<は最初の依存関係の名前です。

34
Eric

main.cpphello.cppfactorial.cppのいずれかが変更された場合、Makefileはhello実行可能ファイルをビルドします。その仕様を実現するための最小のMakefileは、次のとおりです。

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • pro:とても読みやすい
  • con:メンテナンスの悪夢、C++の依存関係の複製
  • con:効率の問題、1つだけが変更されたとしても、すべてのC++を再コンパイルします

上記を改善するために、編集された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
  • pro:効率の問題を修正しました
  • con:新しいメンテナンスの悪夢、オブジェクトファイルのルールに関する潜在的なタイプミス

これを改善するために、すべてのオブジェクトファイルの規則を単一の.cpp.o規則に置き換えることができます。

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

.cpp.o:
    g++ -c $< -o $@
  • pro:短いmakefileを持っていることに戻って、やや読みやすい

ここで.cpp.oルールはanyfile.oからanyfile.cppを構築する方法を定義します。

  • $<は最初の依存関係に一致します。この場合、anyfile.cpp
  • $@はターゲット、この場合はanyfile.oに一致します。

Makefileに存在するその他の変更は以下のとおりです。

  • コンパイラをg ++から任意のC++コンパイラに簡単に変更できるようにします。
  • コンパイラー・オプションを変更しやすくします。
  • リンカオプションの変更が簡単になりました。
  • C++のソースファイルと出力を簡単に変更できます。
  • アプリケーションを構築する試みが行われる前に、すべてのソースファイルが存在することを確認するためのクイックチェックとして機能するデフォルトのルール 'all'を追加しました。
18
Stephen Quan

ソースをコンパイルしたいが、別のディレクトリにオブジェクトがある場合の例:

あなたがする必要があります:

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のすべての行が続く

0
Aominé