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

$@和$<到底做什么?


当前回答

$@和$<是特殊的宏。

地点:

$@是目标的文件名。

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

其他回答

例如,如果你想编译源代码,但在不同的目录中有对象:

你需要做的是:

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

但对于大多数宏,结果将是所有对象后面跟着所有源,例如:

gcc -c -o <all OBJ path> <all SRC path>

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

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

$@ $<

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

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

意思是:

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

而是一行一行,而不是OBJ的所有行后面跟着SRC的所有行

摘自《用GNU Make管理项目》第3版第16页(在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), $(<D), etc. The other variant returns only the file portion of the value. This is indicated by appending an “F” to the symbol, $(@F), $(<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.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++依赖的复制 缺点:效率问题,我们重新编译所有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

利:修复效率问题 缺点:新的维护噩梦,目标文件规则上的潜在错字

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

OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@

优点:回到一个简短的makefile,有点容易阅读

这里是。cpp。O规则定义了如何构建任意文件。O从anyfile.cpp。

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

Makefile中的其他更改包括:

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

$@和$<被称为自动变量。变量$@表示目标的名称,$<表示创建输出文件所需的第一个前提条件。 例如:

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

在这里,你好。O是输出文件。这就是$@展开的结果。第一个依赖项是hello.c。这就是$<展开的内容。

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

要了解更多详细信息,可以阅读linoxide上关于Linux Makefiles的文章。

此外,您可以查看GNU make手册。这将使生成makefile和调试它们变得更容易。

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

make -p 

$@和$<是特殊的宏。

地点:

$@是目标的文件名。

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