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 $@ |
例如,请考虑以下声明:
1 | all: library.cpp main.cpp |
在这种情况下:
-
$@ 评估为all -
$< 评估为library.cpp -
$^ 评估为library.cpp main.cpp
例如:
1 2 | hello.o: hello.c hello.h gcc -c $< -o $@ |
这里,
有关更多详细信息,请阅读有关Linux Makefiles的文章。
另外,您可以查看GNU
如果运行此命令,它将输出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.
哪里:
如果
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:新的维护噩梦,对象文件规则的潜在错字
为了改进这一点,我们可以用一个
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,有点容易阅读
这里
-
$< 与第一个依赖项匹配,在本例中为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的所有行