Makefile下 $(wildcard $^),$^,$@,$?,$<,$(@D),$(@F)

理解Makefile中关键变量及静态模式规则
本文深入解析Makefile中$(wildcard$^), $(filter-out), $(?^), $(@D), $(@F)等变量的含义与用途,并详细阐述静态模式规则的语法与应用,为构建高效自动化构建流程提供理论基础。

原文路径:http://blog.chinaunix.net/uid-20564848-id-217918.html

makefile下$(wildcard $^),$^,$@,$?,$<,$(@D),$(@F)代表的不同含义


$(filter-out $(PHONY) $(wildcard $^),$^)
常用用法为$(wildcard *.c)
表示列举当前目录下的所有.c文件
这里$^因为会包含依赖的文件名,如果包含的该文件存在,那么将返回其含路径的文件名
所以$(wildcard $^)就是用来过滤$^包含的所有文件并且该文件确实在本地存在.

自动化变量$?代表依赖文件列表中被改变过的所有文件。
自动化变量$^代表所有通过目录搜索得到的依赖文件的完整路径名(目录 + 一般文件名)列表。
自动化变量$@代表规则的目标。
自动化变量$<代表规则中通过目录搜索得到的依赖文件列表的第一个依赖文件。
自动化变量$(@D) 
The directory part of the file name of the target, 
with the trailing slash removed. If the value of ‘$@’ is dir/foo.o 
then ‘$(@D)’ is dir. This value is . if ‘$@’ does not contain a slash.
http://www.gnu.org/software/make/manual/make.html
自动化变量$(@F)
The file-within-directory part of the file name of 
the target. If the value of ‘$@’ is dir/foo.o then ‘$(@F)’ is foo.o. 
‘$(@F)’ is equivalent to ‘$(notdir $@)’. 

4.12 静态模式
静态模式规则是这样一个规则:
规则存在多个目标,
并且不同的目标可以根据目标
文件的名字来自动构造出依赖文件。
静态模式规则比多目标规则更通用,
它不需要多个
目标具有相同的依赖。
但是静态模式规则中的依赖文件必须是相类似的而不是完全相同
的。
4.12.1
静态模式规则的语法
首先,我们来看一下静态模式规则的基本语法:
TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...
COMMANDS
...
“TAGETS”
列出了此规则的一系列目标文件。
像普通规则的目标一样可以包含通
配符。关于通配符的使用可参考 4.4 文件名使用通配符 一节
“TAGET-PATTERN”和“PREREQ-PATTERNS”说明了如何为每一个目标文件
生成依赖文件。从目标模式(TAGET-PATTERN)的目标名字中抽取一部分字符串(称
为“茎”。使用“茎”替代依赖模式(PREREQ-PATTERNS)中的相应部分来产生对
)
应目标的依赖文件。下边详细介绍这一替代的过程。
首 先 在目标模式和依赖模式中 ,一般需要包含模式字符“% ”
。在目标模式
(TAGET-PATTERN)中“%”可以匹配目标文件的任何部分,模式字符“%”匹配的
部分就是“茎”
。目标文件和目标模式的其余部分必须精确的匹配。看一个例子:目标
“foo.o”符合模式“%.o”
,其“茎”为“foo”
。而目标“foo.c”和“foo.out”就不符
合此目标模式。
每一个目标的依赖文件是使用此目标的“茎”代替依赖模式
(PREREQ-PATTERNS)中的模式字符“%”而得到。例如:上边的例子中依赖模式
(PREREQ-PATTERNS)为“%.c”
,那么使用“茎”
“foo”替代依赖模式中的“%”
得到的依赖文件就是“foo.c”
。需要明确的一点是:在模式规则的依赖列表中使用不包
含模式字符“%”也是合法的。代表这个文件是所有目标的依赖文件。
在模式规则中字符‘%’可以用前面加反斜杠“\”方法引用。引用“%”的反斜杠
也可以由更多的反斜杠引用。引用“%”“\”的反斜杠在和文件名比较或由“茎”代

替它之前会从模式中被删除。反斜杠不会因为引用“%”而混乱。如,模式
“the\%weird\\%pattern\\”是“the%weird\”+“%”+“pattern\\”构成。最后的两个
反斜杠由于没有任何转义引用“%”所以保持不变。
我们来看一个例子,它根据相应的.c 文件来编译生成“foo.o”和“bar.o”文件:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
例子中,规则描述了所有的.o文件的依赖文件为对应的.c文件,对于目标“foo.o”
,取
其茎“foo”替代对应的依赖模式“%.c”中的模式字符“%”之后可得到目标的依赖文
件“foo.c”
。这就是目标“foo.o”的依赖关系“foo.o: foo.c”
,规则的命令行描述了如
何完成由“foo.c”编译生成目标“foo.o”
。命令行中“$<”和“$@”是自动化变量,
“$<”
表示规则中的第一个依赖文件,
“$@”
表示规则中的目标文件
(可参考 10.5.3 自
动化变量 一小节)
。上边的这个规则描述了以下两个具体的规则:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
在使用静态模式规则时,指定的目标必须和目标模式相匹配,否则执行make时将
会得到一个错误提示。
如果存在一个文件列表,
其中一部分符合某一种模式而另外一部
分符合另外一种模式,这种情况下我们可以使用“filter”函数(可参考 第八章 make
的内嵌函数)来对这个文件列表进行分类,在分类之后对确定的某一类使用模式规则。
例如:
files = foo.elc bar.o lose.o
$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<
其中;$(filter %.o,$(files))的结果为“bar.o lose.o”“filter”函数过滤不符合“%.o”

模式的文件名而返回所有符合此模式的文件列表。
第一条静态模式规则描述了这些目标
文件是通过编译对应的.c 源文件来重建的。同样第二条规则也是使用这种方式。
我们通过另外一个例子来看一下自动环变量“$*”在静态模式规则中的使用方法:
bigoutput littleoutput : %output : text.g
generate text.g -$* > $@
当执行此规则的命令时,
自动环变量
“$*”
被展开为
“茎” 在这里就是

“big” “little”


静态模式规则对一个较大工程的管理非常有用。
它可以对整个工程的同一类文件的
重建规则进行一次定义,而实现对整个工程中此类文件指定相同的重建规则。比如,可
以用来描述整个工程中所有的.o 文件的依赖规则和编译命令。通常的做法是将生成同
一类目标的模式定义在一个 make.rules 的文件中。在工程各个模块的 Makefile 中包含
此文件。

  1. 静态模式makefile中$(cobjs): $(obj)/%.o: $(src)/%.c

  2. http://www.gnu.org/software/make/manual/make.html
  3. 4.12.1 Syntax of Static Pattern Rules

  4. Here is the syntax of a static pattern rule:

  5.      targets ...: target-pattern: prereq-patterns ...
  6.              recipe
  7.              ...

  8. The targets list specifies the targets that the rule applies to. The targets can contain wildcard characters, just like the targets of ordinary rules (see Using Wildcard Characters in File Names).

  9. The target-pattern and prereq-patterns say how to compute the prerequisites of each target. Each target is matched against the target-pattern to extract a part of the target name, called the stem. This stem is substituted into each of the prereq-patterns to make the prerequisite names (one from each prereq-pattern).

  10. Each pattern normally contains the character ‘%’ just once. When the target-pattern matches a target, the ‘%’ can match any part of the target name; this part is called the stem. The rest of the pattern must match exactly. For example, the target foo.o matches the pattern ‘%.o’, with ‘foo’ as the stem. The targets foo.and foo.out do not match that pattern.

  11. The prerequisite names for each target are made by substituting the stem for the ‘%’ in each prerequisite pattern. For example, if one prerequisite pattern is %.c, then substitution of the stem ‘foo’ gives the prerequisite name foo.c. It is legitimate to write a prerequisite pattern that does not contain ‘%; then this prerequisite is the same for all targets.

  12. %’ characters in pattern rules can be quoted with preceding backslashes (\). Backslashes that would otherwise quote ‘%’ characters can be quoted with more backslashes. Backslashes that quote ‘%’ characters or other backslashes are removed from the pattern before it is compared to file names or has a stem substituted into it. Backslashes that are not in danger of quoting ‘%’ characters go unmolested. For example, the pattern the\%weird\\%pattern\\ has ‘the%weird\’ preceding the operative ‘%’ character, and ‘pattern\\’ following it. The final two backslashes are left alone because they cannot affect any ‘%’ character.

  13. Here is an example, which compiles each of foo.and bar.o from the corresponding .c file:

  14.      objects = foo.o bar.o
  15.      
  16.      all: $(objects)
  17.      
  18.      $(objects): %.o: %.c
  19.              $(CC) -c $(CFLAGS) $< -o $@

  20. Here ‘$<’ is the automatic variable that holds the name of the prerequisite and ‘$@’ is the automatic variable that holds the name of the target; see Automatic Variables.

  21. Each target specified must match the target pattern; a warning is issued for each target that does not. If you have a list of files, only some of which will match the pattern, you can use the filter function to remove nonmatching file names (see Functions for StringSubstitution and Analysis):

  22.      files = foo.elc bar.o lose.o
  23.      
  24.      $(filter %.o,$(files)): %.o: %.c
  25.              $(CC) -c $(CFLAGS) $< -o $@
  26.      $(filter %.elc,$(files)): %.elc: %.el
  27.              emacs -f batch-byte-compile $<

  28. In this example the result of ‘$(filter %.o,$(files))’ is bar.o lose.o, and the first static pattern rule causes each of these object files to be updated by compiling the corresponding C source file. The result of ‘$(filter %.elc,$(files))’ is foo.elc, so that file is made from foo.el.

  29. Another example shows how to use $* in static pattern rules:

  30.      bigoutput littleoutput : %output : text.g
  31.              generate text.-$* > $@

  32. When the generate command is run, $* will expand to the stem, either ‘big’ or ‘little’.
<think>我们正在讨论Makefile中的$()用法。根据引用内容,$()Makefile中有多种用途,主要包括变量引用、自动化变量、函数调用等。下面将详细说明:1.**变量引用**:`$(var_name)`用于引用Makefile中定义的变量。例如:```makefileCC=gcctarget:$(CC)-oprogramprogram.c```这里`$(CC)`会被展开为`gcc`。2.**自动化变量**:在规则中,可以使用一些预定义的自动化变量(引用[3]):-`$@`:表示规则的目标文件名。-`$<`:表示第一个依赖文件。-`$^`:表示所有依赖文件列表(去除重复)。-`$?`:表示比目标更新的所有依赖文件列表。-`$*`:表示目标文件的主干部分(即去掉后缀的部分)。示例:```makefileprogram:main.cutils.cgcc-o$@$^#$@为program,$^为main.cutils.c```3.**函数调用**:Makefile提供了一些内置函数,使用`$(function_namearguments)`调用(引用[1][2]):-`$(wildcardpattern)`:获取匹配模式的文件列表,如`$(wildcard*.c)`。-`$(patsubstpattern,replacement,text)`:模式替换,如`$(patsubst%.c,%.o,$(wildcard*.c))`将.c文件列表替换为.o文件列表。-`$(foreachvar,list,text)`:循环处理,如:```makefiledirs:=abcfiles:=$(foreachdir,$(dirs),$(wildcard$(dir)/*))```4.**在shell命令中使用Make变量**:在规则命令中,使用`$$`表示shell变量(引用[4][5]):```makefilevar=3target:var=4;\echo$(var)#输出Make变量var的值3echo$$var#输出shell变量var的值4```注意:在Makefile中,规则内的命令每一行都是独立的shell进程,所以多行命令如果需要共享变量,需要用反斜杠连接成一行。5.**特殊用法**:-`$(@F)`:表示目标文件的文件名部分(不含路径),例如目标为`dir/file`,则`$(@F)`为`file`(引用[5])。-`%`:模式匹配,用于模式规则。例如:```makefile%.o:%.cgcc-c$<-o$@```###示例说明**示例1:函数使用**```makefile#获取所有.c文件SRC:=$(wildcard*.c)#将.c替换为.oOBJ:=$(patsubst%.c,%.o,$(SRC))program:$(OBJ)gcc$^-o$@```**示例2:循环和条件**```makefileSUBDIRS:=proj1proj2all:$(foreachdir,$(SUBDIRS),$(MAKE)-C$(dir);)```**示例3:自动化变量**```makefile#编译当前目录下的所有.c文件%.o:%.cgcc-c$<-o$@#$<表示第一个依赖(即.c文件)```**示例4:shell变量使用**```makefiletarget:@forfilein*.c;do\echo"Compiling$$file...";\gcc-c$$file;\done```###注意事项1.**变量作用域**:Makefile变量是全局的,而shell变量只在当前命令中有效。2.**函数参数**:函数参数之间用逗号分隔,且不能有空格(除非引起来)。3.**转义**:在规则命令中,使用`$`需要写成`$$`(引用[4])。---§§相关问题§§:1.Makefile中如何定义和使用多行变量?2.Makefile中的条件分支(如ifeq)如何使用?3.如何编写一个可递归调用子目录MakefileMakefile?</think>### Makefile 中 `$()` 的详细用法与示例 `$()` 在 Makefile 中主要用于 **变量引用**、**函数调用** 和 **自动化变量**。其核心功能是将括号内的内容解析为变量或函数,并展开为实际值。以下是详细分类说明: --- #### 一、变量引用(基础用法) **语法**:`$(VAR_NAME)` **作用**:引用已定义的变量值。 ```makefile # 定义变量 CC = gcc SRC = main.c utils.c # 引用变量 target: $(CC) -o program $(SRC) # 展开为 gcc -o program main.c utils.c ``` --- #### 二、自动化变量(动态引用) 自动化变量在规则执行时动态生成值(引用[3][5]): | 变量 | 含义 | 示例 | |------|-----------------------|-------------------------------| | `$@` | 当前目标文件名 | `target:; echo $@` → 输出 `target` | | `$^` | 所有依赖文件 | `target: a.c b.c; gcc $^` → 展开为 `gcc a.c b.c` | | `$<` | 第一个依赖文件 | `target: a.c b.c; cp $< $@` → 复制 `a.c` 到 `target` | | `$*` | 目标文件的主干名(不含后缀) | `file.o: file.c; gcc -c $*.c` → 展开为 `gcc -c file.c` | **示例**: ```makefile # 编译所有 .c 文件为 .o %.o: %.c gcc -c $< -o $@ # $< 是 %.c, $@ 是 %.o ``` --- #### 三、函数调用 **语法**:`$(function_name arguments)` 常用内置函数(引用[1][2]): ##### 1. `$(wildcard pattern)` **作用**:匹配文件模式,返回文件名列表。 ```makefile # 获取所有 .c 文件 SRC_FILES := $(wildcard *.c) # 若目录有 a.c b.c,则 SRC_FILES = a.c b.c ``` ##### 2. `$(patsubst pattern,replacement,text)` **作用**:模式替换(引用[2])。 ```makefile # 将 .c 替换为 .o OBJ_FILES := $(patsubst %.c,%.o,$(SRC_FILES)) # a.c → a.o ``` ##### 3. `$(foreach var,list,text)` **作用**:循环处理列表(引用[1])。 ```makefile # 遍历子目录获取文件 DIRS := src lib FILES := $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)) # 结果:src/a.c lib/b.c ... ``` --- #### 四、特殊用法 ##### 1. 嵌套调用 函数和变量可嵌套组合: ```makefile # 先获取 .c 文件,再替换为 .d 依赖文件 DEPS := $(patsubst %.c,%.d,$(wildcard *.c)) ``` ##### 2. Shell 变量转义(引用[4]) 在规则命令中使用 `$$` 表示 Shell 变量: ```makefile target: @var="hello"; \ # Shell 变量 echo $(CC) # 输出 Make 变量 CC 的值(gcc) echo $$var # 输出 Shell 变量值(hello) ``` ##### 3. 文件名操作(引用[5]) `$(@F)` 提取目标文件名(不含路径): ```makefile build/program: @echo "Target file: $(@F)" # 输出 program ``` --- #### 五、综合示例 ```makefile # 定义目录和编译器 SRC_DIR := src OBJ_DIR := obj CC := gcc # 获取源文件和对象文件 SRCS := $(wildcard $(SRC_DIR)/*.c) OBJS := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS)) # 编译规则 program: $(OBJS) $(CC) $^ -o $@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c mkdir -p $(@D) # 创建目标目录($(@D) 为目标目录名) $(CC) -c $< -o $@ clean: rm -rf $(OBJ_DIR) program ``` --- #### 关键注意事项 1. **空格敏感**:`$()` 内不能有额外空格,例如 `$(patsubst %.c, %.o, text)` 会因逗号后的空格报错。 2. **递归展开**:变量默认递归展开(如 `VAR1 = $(VAR2)`),需用 `:=` 避免(简单赋值)。 3. **函数参数**:函数参数间用逗号分隔,且参数本身不能含逗号。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值