makefile符号$ @和$<意思?

时间:2010-07-10 17:54:56

标签: makefile

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

$@$<到底做了什么?

6 个答案:

答案 0 :(得分:408)

$@是正在生成的文件的名称,$<是第一个先决条件(通常是源文件)。您可以在GNU Make manual中找到所有这些特殊变量的列表。

例如,请考虑以下声明:

all: library.cpp main.cpp

在这种情况下:

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

答案 1 :(得分:67)

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

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

此处,hello.o是输出文件。这是$@扩展到的内容。第一个依赖是hello.c。这就是$<扩展到的目标。

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

有关详细信息,请参阅this article about Linux Makefiles

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

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

make -p 

答案 2 :(得分:45)

来自Managing Projects with GNU Make, 3rd Edition GNU自由文档许可证下):

  匹配规则后,

自动变量make设置。他们   提供对目标和先决条件列表中元素的访问权限   您不必显式指定任何文件名。他们很   有助于避免代码重复,但在定义时至关重要   更一般的模式规则。

     

有七个“核心”自动变量:

     
      
  • $@:表示目标的文件名。

  •   
  • $%:归档成员规范的文件名元素。

  •   
  • $<:第一个先决条件的文件名。

  •   
  • $?:比目标更新的所有先决条件的名称,   用空格分隔。

  •   
  • $^:所有先决条件的文件名,以空格分隔。这个   列表中删除了重复的文件名,因为大多数用途,例如   编辑,复制等,不需要重复。

  •   
  • $+:与$^类似,这是所有先决条件的名称   按空格,但$+包含重复项。这个变量是   为特定情况创建,例如链接器的参数where   重复值具有意义。

  •   
  • $*:目标文件名的主干。词干通常是文件名   没有后缀。它在模式规则之外的使用是   气馁。

  •   
     

此外,上述每个变量都有两个变体   与其他品牌的兼容性。一个变体仅返回目录   部分价值。通过在“。”上附加“D”来表示   符号,$(@D)$(<D)等。另一个变量仅返回文件   部分价值。通过在“。”上添加“F”来表示   符号,$(@F)$(<F)等。请注意,这些变体名称不仅仅是   一个字符长,因此必须括在括号中。 GNU make   使用dir和notdir提供更具可读性的替代方案   功能

答案 3 :(得分:34)

$@$<是特殊的宏。

其中:

$@是目标的文件名。

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

答案 4 :(得分:18)

如果hellomain.cpphello.cpp中的任何一个发生了更改,则Makefile会构建factorial.cpp可执行文件。实现该规范的最小可能Makefile可能是:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • 亲:非常容易阅读
  • con:维护噩梦,重复C ++依赖
  • con:效率问题,我们重新编译所有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 ++源文件和输出。
  • 添加了默认规则&#39; all&#39;在尝试构建应用程序之前,它可以作为快速检查以确保所有源文件都存在。

答案 5 :(得分:1)

例如,如果您要编译源代码但对象在不同目录中,则为

您需要做的事情:

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的所有行中逐行INSTEAD,然后在SRC的所有行中逐行