makefile符号$ @和$ <是什么意思?

What do the makefile symbols $@ and $< mean?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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手册中找到所有这些特殊变量的列表。

例如,请考虑以下声明:

1
all: library.cpp main.cpp

在这种情况下:

  • $@评估为all
  • $<评估为library.cpp
  • $^评估为library.cpp main.cpp


$@$<称为自动变量。变量$@表示已创建文件的名称(即目标),$<表示创建输出文件所需的第一个先决条件。
例如:

1
2
hello.o: hello.c hello.h
         gcc -c $< -o $@

这里,hello.o是输出文件。这是$@扩展到的内容。第一个依赖是hello.c。那是$<扩展到的。

-c标志生成.o文件;有关更详细的说明,请参阅man gcc-o指定要创建的输出文件。

有关更多详细信息,请阅读有关Linux Makefiles的文章。

另外,您可以查看GNU make手册。它可以更容易地制作Makefile并调试它们。

如果运行此命令,它将输出makefile数据库:

1
make -p


来自使用GNU Make管理项目,第3版(它是在GNU自由文档许可下):

Automatic variables are set by make after a rule is matched. They
provide access to elements from the target and prerequisite lists so
you don’t have to explicitly specify any filenames. They are very
useful for avoiding code duplication, but are critical when defining
more general pattern rules.

There are seven"core" automatic variables:

  • $@: The filename representing the target.

  • $%: The filename element of an archive member specification.

  • $<: The filename of the first prerequisite.

  • $?: The names of all prerequisites that are newer than the target,
    separated by spaces.

  • $^: The filenames of all the prerequisites, separated by spaces. This
    list has duplicate filenames removed since for most uses, such as
    compiling, copying, etc., duplicates are not wanted.

  • $+: Similar to $^, this is the names of all the prerequisites separated
    by spaces, except that $+ includes duplicates. This variable was
    created for specific situations such as arguments to linkers where
    duplicate values have meaning.

  • $*: The stem of the target filename. A stem is typically a filename
    without its suffix. Its use outside of pattern rules is
    discouraged.

In addition, each of the above variables has two variants for
compatibility with other makes. One variant returns only the directory
portion of the value. This is indicated by appending a"D" to the
symbol, $(@D), $(, etc. The other variant returns only the file
portion of the value. This is indicated by appending an"F" to the
symbol, $(@F), $(, etc. Note that these variant names are more than
one character long and so must be enclosed in parentheses. GNU make
provides a more readable alternative with the dir and notdir
functions.


$@$<是特殊的宏。

哪里:

$@是目标的文件名。

$<是第一个依赖项的名称。


如果main.cpphello.cppfactorial.cpp中的任何一个发生更改,Makefile将构建hello可执行文件。实现该规范的最小可能Makefile可能是:

1
2
hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • 亲:非常容易阅读
  • con:维护噩梦,重复C ++依赖
  • con:效率问题,我们重新编译所有C ++,即使只有一个被更改

为了改进上述内容,我们只编译那些已编辑的C ++文件。然后,我们将结果对象文件链接在一起。

1
2
3
4
5
6
7
8
9
10
11
12
13
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
  • 亲:解决效率问题
  • con:新的维护噩梦,对象文件规则的潜在错字

为了改进这一点,我们可以用一个.cpp.o规则替换所有对象文件规则:

1
2
3
4
5
6
7
OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@
  • 亲:回到有一个简短的makefile,有点容易阅读

这里.cpp.o规则定义了如何从anyfile.cpp构建anyfile.o

  • $<与第一个依赖项匹配,在本例中为anyfile.cpp
  • $@匹配目标,在本例中为anyfile.o

Makefile中存在的其他更改包括:

  • 更容易将编译器从g ++更改为任何C ++编译器。
  • 更容易更改编译器选项。
  • 更容易更改链接器选项。
  • 更容易更改C ++源文件和输出。
  • 添加了一个默认规则"all",用于快速检查以确保在尝试构建应用程序之前存在所有源文件。

例如,如果你想编译源但在另一个目录中有对象:

你需要这样做:

1
gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...

但在大多数情况下(与其他宏),结果将是:

1
gcc -c -o

所以这不会编译任何东西^^和你将无法将你的对象文件放在不同的目录:(

解决方案是使用这些特殊的宏

1
$@ $<

这将为SRC中的每个.c文件生成一个.o文件(obj / file.o)(src / file.c)

1
2
$(OBJ):$(SRC)
   gcc -c -o $@ $< $(HEADERS) $(FLAGS)

它的意思是 :

1
2
    $@ = $(OBJ)
    $< = $(SRC)

但是按行INSTEAD排列OBJ的所有行,然后是SRC的所有行