一、变量定义语法
变量的名称 = 值列表
-
变量的名称可以由大小写字母、阿拉伯数字和下划线构成。
-
等号左右的空白符没有明确的要求,因为在执行 make 的时候多余的空白符会被自动的删除。
-
至于值列表,既可以是零项,又可以是一项或者是多项。
-
变量使用可以用 $( ) 或 ${ }
二、变量赋值
1、赋值符
-
简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
-
递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
-
条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
-
追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
特别说明:
- =、?= 为延时变量(延时变量:使用该变量的时候,才展开该变量,并确定该变量的值)
- :=、+=为立即变量(立即变量:定义的时候就已经确定了该变量的值)
符号 | 含义 | 变量类型 |
---|---|---|
= | 递归赋值,当变量展开时,优先从后面展开 | 延时变量 |
:= | 该变量立即赋值(会覆盖前面的值),当变量展开时,优先从前面展开 | 立即变量 |
?= | 若前面没有定义该变量,则此处赋值,如果前面已经定义了,则此处不再赋值 | 延时变量 |
+= | 追加赋值 | 立即变量 |
2、测试
makefile 文件内容:
x = before
y = $(x)_AAAA # 立即展开,当展开$(x)时,x值为before
x = later # x 值会被覆盖
xx := before
yy := $(xx)_AAAA # 延时展开,当展开$(xx)时,xx值为later
xx := later # xx 值会被覆盖
xxx ?= before
xxx ?= later # 条件不满足,未执行
xxxx += before
xxxx += later # 追加
.PHONY:all
all:
@echo "\$$(x) = $(x)"
@echo "\$$(xx) = $(xx)"
@echo "y = $(y)"
@echo "yy = $(yy)"
@echo "xxx = ${xxx}"
@echo "xxxx = ${xxxx}"
测试结果:
$(x) = later
$(xx) = later
y = later_AAAA
yy = before_AAAA
xxx = before
xxxx = before later
三、define
当相同的命令序列在创建各种目标时很有用时,您可以使用defined指令将其定义为固定序列,并引用这些目标的配方中的固定序列。固定序列实际上是一个变量,因此名称不得与其他变量名称冲突。
以下是 defined 的使用示例:
x = "hello world"
y = "1234567890"
define run-yacc =
@echo "run-yacc start"
@echo $(x)
@echo "run-yacc"
@echo $(y)
@echo "run-yacc end"
endef
all:
${run-yacc}
这里 run-yacc 是被定义的变量名字; endef 标志着定义的结束;中间的行是命令。define 指令不会扩展固定序列中的变量引用和函数调用。$字符、括号、变量名等等,都成为您所定义的变量值的一部分。
执行结果如下:
onlylove@ubuntu:~/My/makefile/01$ make
run-yacc start
hello world
run-yacc
1234567890
run-yacc end
onlylove@ubuntu:~/My/makefile/01$
四、变量引用
要替换变量的值,请在括号或大括号前写入一个’$
'符号,后跟变量的名称:“$(foo)
”或“${foo}
”是对变量 foo 的有效引用。 "$
“的这种特殊意义就决定必须编写”$$
“才能在文件名或配方中具有单个”$
"符号的效果。
五、通配符
1、概述
Makefile 是可以使用 shell 命令的,所以 shell 支持的通配符在 Makefile 中也是同样适用的。 shell 中使用的通配符有:"*","?","[…]"。
通配符 | 使用说明 |
---|---|
* | 匹配0个或者是任意个字符 |
? | 匹配任意一个字符 |
[] | 我们可以指定匹配的字符放在 “[]” 中 |
2、’*’ 通配符测试
测试思路:创建 a.c、b.c、c.c 文件,在 makefile 中使用 ‘*’ 通配符进行匹配。
makefile 文件内容如下:
all:
@echo *.c
测试:
onlylove@ubuntu:~/My/makefile/03$ ls
a.c b.c c.c makefile
onlylove@ubuntu:~/My/makefile/03$ make
a.c b.c c.c
onlylove@ubuntu:~/My/makefile/03$
3、’?’ 通配符测试
测试思路:创建 abc.c、abw.c、acw.c、adw.c 文件,在 makefile 中使用 ‘?’ 通配符进行匹配。
makefile 文件内容如下:
all:
@echo a?w.c
测试:
onlylove@ubuntu:~/My/makefile/03$ ls
abc.c abw.c acw.c adw.c makefile
onlylove@ubuntu:~/My/makefile/03$ make
abw.c acw.c adw.c
onlylove@ubuntu:~/My/makefile/03$
4、’[]’ 通配符测试
测试思路:创建 abc.c、abw.c、acw.c、adw.c 文件,在 makefile 中使用 ‘?’ 通配符进行匹配。
特别说明:
- [abcd]:匹配 abcd 中任何一个字符。
- [a-z]:匹配 a 到 z 中任何一个字符。
makefile 文件内容如下:
all1:
@echo a[bc]w.c
all2:
@echo a[b-z]w.c
测试:
onlylove@ubuntu:~/My/makefile/03$ ls
abc.c abw.c acw.c adw.c makefile
onlylove@ubuntu:~/My/makefile/03$ make all1
abw.c acw.c
onlylove@ubuntu:~/My/makefile/03$ make all2
abw.c acw.c adw.c
onlylove@ubuntu:~/My/makefile/03$
六、替换引用
1、概述
替换引用是将变量的值替换为指定的更改值。它的形式是 ‘$(var:a=b)
’ (or ‘${var:a=b}
’),其含义是取变量var的值,将单词末尾的每个A替换为该值中的b,并替换生成的字符串。
当我们说"在单词的末尾"时,我们的意思是必须出现一个,后面跟着空格或在值的末尾才能被替换;值中出现的其他a不改变。例如:
foo := a.o b.o l.a c.o
bar := $(foo:.o=.c)
将“bar”设置为“a.c b.c l.a c.c”。
替换引用是 patsubst 扩展函数的简写:‘$(var:a=b)
’等价于‘$(patsubst %a,%b,var)
’。
2、测试
makefile 内容如下:
foo := a.o b.o l.a c.o
bar := $(foo:.o=.c)
all:
@echo $(bar)
测试:
onlylove@ubuntu:~/My/makefile/03$ make
a.c b.c l.a c.c
onlylove@ubuntu:~/My/makefile/03$
七、计算变量名称
计算变量名是一个复杂的概念,只有复杂的 makefile 编程才需要。在大多数情况下,您不需要考虑它们,除了知道名称中带有美元符号的变量可能会产生奇怪的结果。但是,如果您是想要了解所有内容的类型,或者您实际上对他们所做的事情感兴趣,请继续阅读。
变量可以在变量名中引用。这称为计算变量名称或嵌套变量引用。例如,
x = y
y = z
a := $($(x))
将 a 定义为 ‘z’:’$($(x))
’ 中的 ‘$(x)
’ 扩展为 ‘y’,因此 ‘$($(x))
’ 扩展为 ‘$(y)
’,其中转扩展为’z’。这里没有明确说明要引用的变量的名称;它是通过扩展‘$(x)
’来计算的。这里的引用‘$(x)
’嵌套在外部变量引用中。
前面的示例显示了两个级别的嵌套,但任意数量的级别都是可能的。例如,这里有三个级别:
x = y
y = z
z = u
a := $($($(x)))
这里最里面的‘$(x)
’扩展为‘y’,所以‘$($(x))
’扩展为‘$(y)
’,后者又扩展为‘z’;现在我们有了‘$(z)
’,它变成了‘u’。
对变量名中递归扩展的变量的引用以通常的方式重新扩展。例如:
x = $(y)
y = z
z = Hello
a := $($(x))
将 a 定义为‘Hello’:‘$($(x))
’变成‘$($(y))
’,‘$(z)
’变成‘Hello’。
嵌套变量引用也可以包含修改后的引用和函数调用,就像任何其他引用一样。例如,使用 subst 函数:
x = variable1
variable2 := Hello
y = $(subst 1,2,$(x))
z = y
a := $($($(z)))
最终将 a 定义为“Hello”。是否有人会想写一个像这个一样复杂的嵌套引用是值得怀疑的,但它确实有效:’$($($(z)))
’ 扩展为 ‘$($(y))
’ ,它变成了 ‘$ ($(subst 1,2,$(x)))
’。这从 x 获取值“variable1”,并通过替换为“variable2”将其更改,因此整个字符串变为“$(variable2)
”,一个简单的变量引用,其值为“Hello”。
计算变量名不必完全由单个变量引用组成。它可以包含多个变量引用,以及一些不变的文本。例如:
a_dirs := dira dirb
1_dirs := dir1 dir2
a_files := filea fileb
1_files := file1 file2
ifeq "$(use_a)" "yes"
a1 := a
else
a1 := 1
endif
ifeq "$(use_dirs)" "yes"
df := dirs
else
df := files
endif
dirs := $($(a1)_$(df))
将根据 use_a 和 use_dirs 的设置赋予 dirs 与 a_dirs、1_dirs、a_files 或 1_files 相同的值。
计算变量名也可用于替换引用:
a_objects := a.o b.o c.o
1_objects := 1.o 2.o 3.o
sources := $($(a1)_objects:.o=.c)
根据 a1 的值,将源定义为“a.c b.c c.c”或“1.c 2.c 3.c”。
对嵌套变量引用的这种使用的唯一限制是它们不能指定要调用的函数名称的一部分。这是因为对已识别函数名称的测试是在扩展嵌套引用之前完成的。例如:
ifdef do_sort
func := sort
else
func := strip
endif
bar := a d b g q c
foo := $($(func) $(bar))
试图给‘foo’变量‘sort a d b g q c’或‘strip a d b g q c’的值,而不是给‘a d b g q c’作为sort或strip函数的参数。如果该更改被证明是一个好主意,则将来可以删除此限制。
您还可以在变量赋值的左侧或定义指令中使用计算变量名称,如下所示:
dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print =
lpr $($(dir)_sources)
endef
此示例定义了变量“for”、“food source”和“footprint”。
请注意,嵌套变量引用与递归扩展变量完全不同,尽管在进行 makefile 编程时两者以复杂的方式一起使用。
八、Target-specific变量
make中的变量值通常是全局的;也就是说,不管在哪里求值,它们都是一样的。一个例外是自动变量。
另一个例外是特定于目标的变量值。此功能允许您根据 make 当前正在构建的目标为同一变量定义不同的值。与自动变量一样,这些值仅在目标配方的上下文中可用。
设置特定于目标的变量值,如下所示:
target … : variable-assignment
特定于目标的变量赋值可以以任何或所有特殊关键字"export"、"override"或"private"为前缀;它们的正常行为只应用于变量的这个实例。
多个目标值分别为目标列表的每个成员创建特定于目标的变量值。
变量赋值可以是任何有效的赋值形式;递归(‘=’)、简单(‘:=’或‘::=’)、附加(‘+=’)或条件(‘?=’)。变量赋值中出现的所有变量都将在目标的上下文中进行计算:因此,任何先前定义的特定于目标的变量值都将生效。请注意,此变量实际上与任何"全局"值不同:两个变量不必具有相同的风格。
特定于目标的变量与任何其他 makefile 变量具有相同的优先级。命令行(如果"-e"选项有效,则在环境中)提供的变量将优先。指定 override 指令将允许首选特定于目标的变量值。
特定于目标的变量还有一个特殊功能:当您定义目标特定变量时,该变量值也对该目标的所有先决条件及其所有先决条件等有效(除非这些先决条件使用其自己的特定于目标的变量值覆盖该变量)。例如,像这样的语句:
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
将在 prog 的配方中将 CFLAGS 设置为 ‘-g’,但它也会在创建 prog.o, foo.o 和 bar.o 的配方以及创建其先决条件的任何配方中将 CFLAGS 设置为 ‘-g’。
请注意,每次调用 make 时,给定的先决条件最多只能构建一次。如果同一文件是多个目标的先决条件,并且每个目标对于同一特定于目标的变量具有不同的值,则要生成的第一个目标将导致生成该先决条件,并且先决条件将从第一个目标继承特定于目标的值。它将忽略任何其他目标中特定于目标的值。
九、Pattern-specific变量
除了特定于目标的变量值之外,GNU make 还支持特定于模式的变量值。在这种形式中,变量是为任何匹配指定模式的目标定义的。
设置特定于模式的变量值,如下所示:
pattern … : variable-assignment
其中pattern为%-pattern。与特定于目标的变量值一样,多个模式值分别为每个模式创建一个特定于模式的变量值。变量分配可以是任何有效的赋值形式。任何命令行变量设置都将优先,除非指定了覆盖。
例如:
%.o : CFLAGS = -O
将为 CFLAGS 分配与模式 %.o 匹配的所有目标的 “-O” 值。
如果目标与多个模式匹配,则首先解释具有较长词干的匹配模式特定变量。这会导致更具体的变量优先于更通用的变量,例如:
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
lib/%.o: CFLAGS := -fPIC -g
%.o: CFLAGS := -g
all: foo.o lib/bar.o
在这个例子中,CFLAGS变量的第一个定义将用于更新 lib/bar.o,尽管第二个定义也适用于这个目标。导致相同词干长度的特定于模式的变量将按照它们在 makefile 中定义的顺序进行考虑。
特定于模式的变量在为该目标显式定义的任何特定于目标的变量之后,以及在为父目标定义的特定于目标的变量之前进行搜索。
十、其他特殊变量
详细内容见《GUN make》6.14 Other Special Variables 章节。
十一、隐式规则使用的变量
1、概述
内置隐式规则中的配方自由使用某些预定义的变量。您可以在 makefile 中更改这些变量的值(使用要创建的参数),或者在环境中更改隐式规则的工作方式,而无需重新定义规则本身。您可以使用"-R"或"–no-builtin-variables"选项取消隐式规则使用的所有变量。
例如,用于编译 C 源文件的配方实际上显示 ‘$(CC) -c $(CFLAGS) $(CPPFLAGS)
’。所用变量的默认值为 ‘cc’ 且无值,从而生成命令 ‘cc -c’。通过将‘cc’重新定义为‘ncc’,可以使‘ncc’用于由隐式规则执行的所有 C 编译。通过将"CFLAGS"重新定义为"-g",您可以将"-g"选项传递给每个编译。所有执行 C 编译的隐式规则都使用 “$(CC)
” 来获取编译器的程序名称,并且所有规则在提供给编译器的参数中都包含 “$(CFLAGS)
”。
隐式规则中使用的变量分为两类:程序名称的变量(如 CC)和包含程序参数的变量(如 CFLAGS)("程序名称"也可能包含一些命令参数,但它必须以实际的可执行程序名称开头)。如果变量值包含多个参数,请用空格分隔它们。
下表描述了一些更常用的预定义变量。此列表并非详尽无遗,此处显示的默认值可能不是为您的环境做出选择的原因。要查看 GNU 实例的预定义变量的完整列表,您可以在没有 makefile 的目录中运行 ‘make -p’。
下表列出了一些在内置规则中用作程序名称的更常见变量:
<略(详细内容见官方文档)>
2、测试
make -p 命令输出日志:
a.c b.c l.a c.c
# GNU Make 4.2.1
# Built for x86_64-pc-linux-gnu
# Copyright (C) 1988-2016 Free Software Foundation, Inc.
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software: you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.
# Make data base, printed on Wed Mar 23 20:40:10 2022
# Variables
# automatic
<D = $(patsubst %/,%,$(dir $<))
# automatic
?F = $(notdir $?)
# default
.SHELLFLAGS := -c
# environment
XDG_SESSION_CLASS = user
# environment
XDG_SESSION_TYPE = tty
# default
CWEAVE = cweave
# automatic
?D = $(patsubst %/,%,$(dir $?))
# automatic
@D = $(patsubst %/,%,$(dir $@))
# automatic
@F = $(notdir $@)
# default
MAKE_VERSION := 4.2.1
# makefile
CURDIR := /home/onlylove/My/makefile/03
# makefile
SHELL = /bin/sh
# default
RM = rm -f
# default
CO = co
# default
COMPILE.mod = $(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)
# environment
_ = /usr/bin/make
# default
PREPROCESS.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F
# default
LINK.m = $(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
# default
OUTPUT_OPTION = -o $@
# default
COMPILE.cpp = $(COMPILE.cc)
# makefile (from 'makefile', line 1)
MAKEFILE_LIST := makefile
# 'override' directive
GNUMAKEFLAGS :=
# default
LINK.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# environment
XDG_DATA_DIRS = /usr/local/share:/usr/share:/var/lib/snapd/desktop
# environment
DBUS_SESSION_BUS_ADDRESS = unix:path=/run/user/1000/bus
# default
CC = cc
# default
CHECKOUT,v = +$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)
# environment
LESSOPEN = | /usr/bin/lesspipe %s
# default
CPP = $(CC) -E
# default
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# environment
SSH_CONNECTION = 192.168.6.1 61185 192.168.6.129 22
# environment
PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
# default
LD = ld
# default
TEXI2DVI = texi2dvi
# default
YACC = yacc
# environment
SSH_TTY = /dev/pts/0
# environment
XDG_RUNTIME_DIR = /run/user/1000
# default
ARFLAGS = rv
# default
LINK.r = $(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
LINT = lint
# default
COMPILE.f = $(FC) $(FFLAGS) $(TARGET_ARCH) -c
# default
LINT.c = $(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)
# default
YACC.m = $(YACC) $(YFLAGS)
# default
YACC.y = $(YACC) $(YFLAGS)
# default
AR = ar
# default
.FEATURES := target-specific order-only second-expansion else-if shortest-stem undefine oneshell archives jobserver output-sync check-symlink load
# default
TANGLE = tangle
# environment
LS_COLORS = rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
# default
GET = get
# automatic
%F = $(notdir $%)
# environment
DISPLAY = localhost:10.0
# default
COMPILE.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
CTANGLE = ctangle
# default
.LIBPATTERNS = lib%.so lib%.a
# default
LINK.C = $(LINK.cc)
# environment
PWD = /home/onlylove/My/makefile/03
# default
.LOADED :=
# default
LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)
# default
PREPROCESS.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F
# automatic
*D = $(patsubst %/,%,$(dir $*))
# default
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
LINK.s = $(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)
# environment
HOME = /home/onlylove
# environment
LESSCLOSE = /usr/bin/lesspipe %s %s
# environment
LOGNAME = onlylove
# automatic
^D = $(patsubst %/,%,$(dir $^))
# environment
MAKELEVEL := 0
# default
COMPILE.m = $(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
MAKE = $(MAKE_COMMAND)
# environment
SHLVL = 1
# default
AS = as
# default
PREPROCESS.S = $(CC) -E $(CPPFLAGS)
# default
COMPILE.p = $(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# environment
XDG_SESSION_ID = 4
# environment
USER = onlylove
# default
FC = f77
# makefile
.DEFAULT_GOAL := all
# automatic
%D = $(patsubst %/,%,$(dir $%))
# default
WEAVE = weave
# default
MAKE_COMMAND := make
# default
LINK.cpp = $(LINK.cc)
# default
F77 = $(FC)
# environment
OLDPWD = /home/onlylove/My/makefile
# makefile (from 'makefile', line 2)
bar := a.c b.c l.a c.c
# default
.VARIABLES :=
# default
PC = pc
# automatic
*F = $(notdir $*)
# default
COMPILE.def = $(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)
# default
LEX = lex
# makefile
MAKEFLAGS = p
# environment
MFLAGS = -p
# environment
SSH_CLIENT = 192.168.6.1 61185 22
# default
LEX.l = $(LEX) $(LFLAGS) -t
# default
LEX.m = $(LEX) $(LFLAGS) -t
# automatic
+D = $(patsubst %/,%,$(dir $+))
# default
COMPILE.r = $(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c
# automatic
+F = $(notdir $+)
# default
M2C = m2c
# default
MAKEFILES :=
# default
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# automatic
<F = $(notdir $<)
# default
CXX = g++
# makefile (from 'makefile', line 1)
foo := a.o b.o l.a c.o
# default
COFLAGS =
# default
COMPILE.C = $(COMPILE.cc)
# automatic
^F = $(notdir $^)
# default
COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c
# default
LINK.F = $(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default
SUFFIXES := .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
COMPILE.s = $(AS) $(ASFLAGS) $(TARGET_MACH)
# default
.INCLUDE_DIRS = /usr/include /usr/local/include /usr/include
# default
.RECIPEPREFIX :=
# default
MAKEINFO = makeinfo
# default
MAKE_TERMERR := /dev/pts/0
# default
OBJC = cc
# default
MAKE_HOST := x86_64-pc-linux-gnu
# default
TEX = tex
# environment
LANG = en_US.UTF-8
# environment
TERM = xterm
# default
F77FLAGS = $(FFLAGS)
# default
LINK.f = $(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# environment
MOTD_SHOWN = pam
# variable set hash-table stats:
# Load=124/1024=12%, Rehash=0, Collisions=16/155=10%
# Pattern-specific Variable Values
# No pattern-specific variable values.
# Directories
# SCCS: could not be stat'd.
# . (device 2053, inode 1718663): 8 files, 19 impossibilities.
# RCS: could not be stat'd.
# 8 files, 19 impossibilities in 3 directories.
# Implicit Rules
%.out:
%.a:
%.ln:
%.o:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.c:
%: %.c
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.ln: %.c
# recipe to execute (built-in):
$(LINT.c) -C$* $<
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
%.cc:
%: %.cc
# recipe to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.cc
# recipe to execute (built-in):
$(COMPILE.cc) $(OUTPUT_OPTION) $<
%.C:
%: %.C
# recipe to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.C
# recipe to execute (built-in):
$(COMPILE.C) $(OUTPUT_OPTION) $<
%.cpp:
%: %.cpp
# recipe to execute (built-in):
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.cpp
# recipe to execute (built-in):
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
%.p:
%: %.p
# recipe to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.p
# recipe to execute (built-in):
$(COMPILE.p) $(OUTPUT_OPTION) $<
%.f:
%: %.f
# recipe to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.f
# recipe to execute (built-in):
$(COMPILE.f) $(OUTPUT_OPTION) $<
%.F:
%: %.F
# recipe to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.F
# recipe to execute (built-in):
$(COMPILE.F) $(OUTPUT_OPTION) $<
%.f: %.F
# recipe to execute (built-in):
$(PREPROCESS.F) $(OUTPUT_OPTION) $<
%.m:
%: %.m
# recipe to execute (built-in):
$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.m
# recipe to execute (built-in):
$(COMPILE.m) $(OUTPUT_OPTION) $<
%.r:
%: %.r
# recipe to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.r
# recipe to execute (built-in):
$(COMPILE.r) $(OUTPUT_OPTION) $<
%.f: %.r
# recipe to execute (built-in):
$(PREPROCESS.r) $(OUTPUT_OPTION) $<
%.y:
%.ln: %.y
# recipe to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c
$(RM) y.tab.c
%.c: %.y
# recipe to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
%.l:
%.ln: %.l
# recipe to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c
$(LINT.c) -i $*.c -o $@
$(RM) $*.c
%.c: %.l
# recipe to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
%.r: %.l
# recipe to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
%.ym:
%.m: %.ym
# recipe to execute (built-in):
$(YACC.m) $<
mv -f y.tab.c $@
%.yl:
%.s:
%: %.s
# recipe to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.s
# recipe to execute (built-in):
$(COMPILE.s) -o $@ $<
%.S:
%: %.S
# recipe to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.S
# recipe to execute (built-in):
$(COMPILE.S) -o $@ $<
%.s: %.S
# recipe to execute (built-in):
$(PREPROCESS.S) $< > $@
%.mod:
%: %.mod
# recipe to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
%.o: %.mod
# recipe to execute (built-in):
$(COMPILE.mod) -o $@ $<
%.sym:
%.def:
%.sym: %.def
# recipe to execute (built-in):
$(COMPILE.def) -o $@ $<
%.h:
%.info:
%.dvi:
%.tex:
%.dvi: %.tex
# recipe to execute (built-in):
$(TEX) $<
%.texinfo:
%.info: %.texinfo
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texinfo
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.texi:
%.info: %.texi
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.texi
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.txinfo:
%.info: %.txinfo
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
%.dvi: %.txinfo
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
%.w:
%.c: %.w
# recipe to execute (built-in):
$(CTANGLE) $< - $@
%.tex: %.w
# recipe to execute (built-in):
$(CWEAVE) $< - $@
%.ch:
%.web:
%.p: %.web
# recipe to execute (built-in):
$(TANGLE) $<
%.tex: %.web
# recipe to execute (built-in):
$(WEAVE) $<
%.sh:
%: %.sh
# recipe to execute (built-in):
cat $< >$@
chmod a+x $@
%.elc:
%.el:
(%): %
# recipe to execute (built-in):
$(AR) $(ARFLAGS) $@ $<
%.out: %
# recipe to execute (built-in):
@rm -f $@
cp $< $@
%.c: %.w %.ch
# recipe to execute (built-in):
$(CTANGLE) $^ $@
%.tex: %.w %.ch
# recipe to execute (built-in):
$(CWEAVE) $^ $@
%:: %,v
# recipe to execute (built-in):
$(CHECKOUT,v)
%:: RCS/%,v
# recipe to execute (built-in):
$(CHECKOUT,v)
%:: RCS/%
# recipe to execute (built-in):
$(CHECKOUT,v)
%:: s.%
# recipe to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
%:: SCCS/s.%
# recipe to execute (built-in):
$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<
# 92 implicit rules, 5 (5.4%) terminal.
# Files
# Not a target:
.web.p:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(TANGLE) $<
# Not a target:
.l.r:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LEX.l) $< > $@
mv -f lex.yy.r $@
# Not a target:
.dvi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.ym:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.f.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.f) $(OUTPUT_OPTION) $<
# Not a target:
.l:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.m:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.ln:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.y:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.def.sym:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.def) -o $@ $<
# Not a target:
.p.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.p) $(OUTPUT_OPTION) $<
# Not a target:
.p:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.txinfo.dvi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.a:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.yl:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.l.ln:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
@$(RM) $*.c
$(LEX.l) $< > $*.c
$(LINT.c) -i $*.c -o $@
$(RM) $*.c
# Not a target:
.F.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.F) $(OUTPUT_OPTION) $<
# Not a target:
.texi.info:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.w.c:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(CTANGLE) $< - $@
# Not a target:
.texi.dvi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.ch:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.m.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.m) $(OUTPUT_OPTION) $<
# Not a target:
.cc:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.cc.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.cc) $(OUTPUT_OPTION) $<
# Not a target:
.def:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.SUFFIXES: .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.c.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
# Not a target:
.r.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.r) $(OUTPUT_OPTION) $<
# Not a target:
.r:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.ym.m:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(YACC.m) $<
mv -f y.tab.c $@
# Not a target:
.y.ln:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(YACC.y) $<
$(LINT.c) -C$* y.tab.c
$(RM) y.tab.c
# Not a target:
makefile:
# Implicit rule search has been done.
# Last modified 2022-03-23 19:43:38.530143315
# File has been updated.
# Successfully updated.
# Not a target:
.elc:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.l.c:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
@$(RM) $@
$(LEX.l) $< > $@
# Not a target:
.out:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
all:
# Implicit rule search has not been done.
# Implicit/static pattern stem: ''
# File does not exist.
# File has been updated.
# Successfully updated.
# automatic
# @ := all
# automatic
# % :=
# automatic
# * :=
# automatic
# + :=
# automatic
# | :=
# automatic
# < :=
# automatic
# ^ :=
# automatic
# ? :=
# variable set hash-table stats:
# Load=8/32=25%, Rehash=0, Collisions=1/12=8%
# recipe to execute (from 'makefile', line 5):
@echo $(bar)
# Not a target:
.C:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.r.f:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(PREPROCESS.r) $(OUTPUT_OPTION) $<
# Not a target:
.S:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo.info:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.c:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.w.tex:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(CWEAVE) $< - $@
# Not a target:
.c.ln:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINT.c) -C$* $<
# Not a target:
.s.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.s) -o $@ $<
# Not a target:
.s:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.texinfo.dvi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
# Not a target:
.el:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.lm.m:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
@$(RM) $@
$(LEX.m) $< > $@
# Not a target:
.y.c:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(YACC.y) $<
mv -f y.tab.c $@
# Not a target:
.web.tex:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(WEAVE) $<
# Not a target:
.texinfo:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.DEFAULT:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.h:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.tex.dvi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(TEX) $<
# Not a target:
.cpp.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
# Not a target:
.cpp:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.C.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.C) $(OUTPUT_OPTION) $<
# Not a target:
.texi:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.txinfo:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.tex:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.txinfo.info:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
# Not a target:
.sh:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
cat $< >$@
chmod a+x $@
# Not a target:
.S.s:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(PREPROCESS.S) $< > $@
# Not a target:
.mod:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.mod) -o $@ -e $@ $^
# Not a target:
.mod.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.mod) -o $@ $<
# Not a target:
.F.f:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(PREPROCESS.F) $(OUTPUT_OPTION) $<
# Not a target:
.w:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.S.o:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(COMPILE.S) -o $@ $<
# Not a target:
.F:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.web:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.sym:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
.f:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
# Not a target:
.info:
# Builtin rule
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# files hash-table stats:
# Load=74/1024=7%, Rehash=0, Collisions=410/1479=28%
# VPATH Search Paths
# No 'vpath' search paths.
# No general ('VPATH' variable) search path.
# strcache buffers: 1 (0) / strings = 245 / storage = 2492 B / avg = 10 B
# current buf: size = 8162 B / used = 2492 B / count = 245 / avg = 10 B
# strcache performance: lookups = 436 / hit rate = 43%
# hash-table stats:
# Load=245/8192=3%, Rehash=0, Collisions=171/436=39%
# Finished Make data base on Wed Mar 23 20:40:10 2022
十二、自动变量
1、概述
假设您正在编写一个模式规则以将‘.c’文件编译为‘.o’文件:如何编写‘cc’命令,以便它对正确的源文件名进行操作?无法在配方中写入名称,因为每次应用隐式规则时,名称都不同。
你要做的是使用一个特殊的功能,即自动变量。这些变量根据规则的目标和先决条件,为执行的每个规则重新计算值。在此示例中,您将使用"$@
“作为对象文件名,使用”$<
"作为源文件名。
您必须认识到自动变量值的可用范围是有限的:它们仅在配方中具有值。特别是,您不能在规则的目标列表中的任何位置使用它们;它们在那里没有值,并将扩展到空字符串。此外,无法在规则的先决条件列表中直接访问它们。一个常见的错误是尝试在先决条件列表中使用 $@;这将不起作用。但是,GNU make 有一个特殊功能,即辅助扩展,它将允许在先决条件列表中使用自动变量值。
以下是自动变量表:
-
$@
:规则目标的文件名。如果目标是存档成员,则"$@
“是存档文件的名称。在具有多个目标的模式规则中,”$@
" 是导致运行规则配方的任何目标的名称。 -
$%
:目标成员名称(当目标是存档成员时)。例如,如果目标是 foo.a(bar.o),则 “$%
” 是 bar.o,"$@
" 是 foo.a。当目标不是存档成员时,"$%
"为空。 -
$<
:第一个先决条件的名称。如果目标从隐式规则中获取其配方,这将是隐式规则添加的第一个先决条件。 -
$?
:比目标新的所有先决条件的名称,它们之间有空格。如果目标不存在,则将包括所有先决条件。对于作为存档成员的先决条件,仅使用指定成员。 -
$^
:所有先决条件的名称,它们之间有空格。对于作为存档成员的先决条件,仅使用指定成员。目标在其所依赖的其他文件上只有一个先决条件,无论每个文件作为先决条件列出多少次。因此,如果多次列出目标的先决条件,则$^
的值仅包含该名称的一个副本。此列表不包含任何仅限命令的先决条件;对于那些,请参阅下面的 ‘$|
’变量。 -
$+
:这类似于 ‘$^
’,但多次列出的先决条件将按照它们在 make 文件中列出的顺序重复。这主要用于链接命令,其中按特定顺序重复库文件名是有意义的。 -
$|
:所有仅限命令先决条件的名称,它们之间有空格。 -
$*
:与隐式规则匹配的词干。如果目标是 dir/a.foo.b,目标模式是 a.%.b,则词干是 dir/foo。词干对于构造相关文件的名称非常有用。 -
$(@D)
:目标文件名的目录部分,删除了尾部斜杠。如果 ‘$@
’ 的值为 dir/foo.o,则 ‘$(@D)
’ 为 dir。如果"$@"不包含斜杠,则此值为 .。 -
$(@F)
:目标文件名的目录中的文件部分。如果 “$@
” 的值为 dir/foo.o,则 “$(@F)
” 为 foo.o。’$(@F)
’ 等同于 ‘$(notdir $@)
’。 -
$(*D)
、$(*F)
:词干的目录部分和目录中的文件部分;在此示例中,dir 和 foo。 -
$(%D)
、$(%F)
:目标存档成员名的目录部分和目录中的文件部分。这只对表单archive(member)的归档成员目标有意义,并且只有当成员可能包含目录名时才有用。 -
$(<D)
、$(<F)
:第一个先决条件的目录部分和目录中的文件部分。 -
$(^D)
、$(^F)
:所有先决条件的目录部分和目录中的文件部分的列表。 -
$(+D)
、$(+F)
:所有先决条件的目录部分和目录内文件部分的列表,包括重复先决条件的多个实例。 -
$(?D)
、$(?F)
:比目标更新的所有先决条件的目录部分和文件在目录中的部分的列表。
特别说明:存档文件指库相关文件。
2、测试
测试思路:创建 main.c、a.c、b.c、c.c 文件并生成 main 可执行文件(可执行文件不进行任何处理)。在命令中打印自动变量的值。
测试1:
- makefile 文件内容
main: main.c a.c b.c c.c
gcc main.c a.c b.c c.c -o main
@echo '$$@ = $@'
@echo '$$% = $%'
@echo '$$< = $<'
@echo '$$? = $?'
@echo '$$^ = $^'
@echo '$$+ = $+'
@echo '$$| = $|'
@echo '$$* = $*'
- 测试
onlylove@ubuntu:~/My/makefile/04$ ls
a.c b.c c.c main.c makefile
onlylove@ubuntu:~/My/makefile/04$ make
gcc main.c a.c b.c c.c -o main
$@ = main
$% =
$< = main.c
$? = main.c a.c b.c c.c
$^ = main.c a.c b.c c.c
$+ = main.c a.c b.c c.c
$| =
$* =
onlylove@ubuntu:~/My/makefile/04$ ls
a.c b.c c.c main main.c makefile
onlylove@ubuntu:~/My/makefile/04$
测试 2:
- makefile 文件内容
main: main.c a.c b.c c.o
gcc main.c a.c b.c -o main
@echo '$$@ = $@'
@echo '$$% = $%'
@echo '$$< = $<'
@echo '$$? = $?'
@echo '$$^ = $^'
@echo '$$+ = $+'
@echo '$$| = $|'
@echo '$$* = $*'
- 测试
onlylove@ubuntu:~/My/makefile/04$ ls
a.c b.c c.c main.c makefile
onlylove@ubuntu:~/My/makefile/04$ make
cc -c -o c.o c.c
gcc main.c a.c b.c -o main
$@ = main
$% =
$< = main.c
$? = main.c a.c b.c c.o
$^ = main.c a.c b.c c.o
$+ = main.c a.c b.c c.o
$| =
$* =
onlylove@ubuntu:~/My/makefile/04$ ls
a.c b.c c.c c.o main main.c makefile
onlylove@ubuntu:~/My/makefile/04$ rm c.o
onlylove@ubuntu:~/My/makefile/04$ ls
a.c b.c c.c main main.c makefile
onlylove@ubuntu:~/My/makefile/04$ make
cc -c -o c.o c.c
gcc main.c a.c b.c -o main
$@ = main
$% =
$< = main.c
$? = c.o
$^ = main.c a.c b.c c.o
$+ = main.c a.c b.c c.o
$| =
$* =
onlylove@ubuntu:~/My/makefile/04$
十三、MAKEFILES 环境变量
如果定义了环境变量 MAKEFILES,则 make 会将其值视为一个列表名字(用空格分割)在其他makefile文件之前读取。这与 include 指令非常相似:在各个目录中搜索这些文件。此外,默认目标不会从这些makefiles中的一个(或其中包含的任何makefiles)中获取,如果没有找到makefiles中列出的文件,则不会出现错误。
MAKEFILES的主要用途是进行递归调用之间的通信。通常不希望在顶级调用 make 之前设置环境变量,因为通常最好不要从外部弄乱 makefile。但是,如果运行的是没有特定 makefile 的 makefile,则 MAKEFILES 中的 makefile 可以执行一些有用的操作来帮助内置的隐式规则更好地工作,例如定义搜索路径。
有些用户倾向于在登录时在环境中自动设置MAKEFILES,并编写MAKEFILES程序来期望这样做。这是一个非常糟糕的想法,因为这样的makefile将无法工作,如果由其他人运行。最好在makefile中写入显式的include指令。
十四、在配方中使用变量
make 处理配方的另一种方法是扩展其中的任何变量引用。在 make 读完所有生成文件并确定目标已过期后,会发生这种情况;因此,未重建的目标的配方永远不会扩展。
配方中的变量和函数引用与 makefile 中其他位置的引用具有相同的语法和语义。它们也有相同的引用规则:如果你想在你的食谱中出现一个’$
’,你必须使用 ‘$$
’。对于像默认 shell 这样使用美元符号引入变量的 shell,重要的是要明确要记住要引用的变量是 make 变量(使用单个美元符号)还是 shell 变量(使用两个美元符号)。例如:
LIST = one two three
all:
for i in $(LIST); do \
echo $$i; \
done
将下列命令传递给 shell 的结果:
for i in one two three; do \
echo $i; \
done
这将生成预期结果:
one
two
three
十五、覆盖变量
包含 “=” 的参数指定变量的值:"v=x"将变量 v 的值设置为 x。如果您以这种方式指定一个值,那么在makefile中相同变量的所有普通赋值都会被忽略。我们说它们已被命令行参数覆盖。
使用此工具最常见的方法是将额外的标志传递给编译器。例如,在正确编写的 makefile 中,变量 CFLAGS 包含在运行 C 编译器的每个配方中,因此将编译文件 foo.c,如下所示:
cc -c $(CFLAGS) foo.c
因此,无论你为CFLAGS设置什么值,都会影响发生的每次编译。makefile可能会指定CFLAGS的常用值,如下所示:
CFLAGS=-g
每次运行 make 时,如果您愿意,都可以覆盖此值。例如,如果您选择 ‘make CFLAGS=-g -O’,那么每次 C 编译都将使用 ‘cc -c -g -O’完成(这还说明了在重写变量时,如何在shell中使用引号将空格和其他特殊字符括起来。)。
变量 CFLAGS 只是存在的众多标准变量之一,以便您可以通过这种方式更改它们。您还可以对 makefile 进行编程,以查看您自己的其他变量,从而使用户能够通过更改变量来控制 makefile 工作方式的其他方面。
当使用命令行参数覆盖变量时,可以定义递归扩展的变量,也可以定义简单扩展的变量。上面显示的示例使用递归展开的变量;要创建一个简单扩展的变量,可以用 ‘:=’ 或 ‘::=’ 代替 ‘=’。但是,除非您希望在指定的值中包含一个变量引用或函数调用,否则创建哪种类型的变量没有区别。
有一种方法可以使makefile更改您已经重写的变量。这是为了使用 override 指令,这是一行,如下所示:“override variable = value”。
十六、用于指定命令的变量
makefile应该提供变量来覆盖某些命令、选项等等。
特别是,您应该通过变量运行大多数实用程序。因此,如果您使用Bison,请使用一个名为Bison的变量,其默认值设置为 “BISON = bison”,并在需要使用 Bison 时使用 $(BISON) 引用它。文件管理工具,如ln、rm、mv等,不需要以这种方式通过变量引用,因为用户不需要用其他程序替换它们。
每个程序名变量都应该带有一个用于向程序提供选项的options变量。将FLAGS附加到程序名变量名以获取选项变量名,例如,BISONFLAGS(C编译器的名称CFLAGS、yacc的名称YFLAGS和lex的名称LFLAGS是这条规则的例外,但我们保留它们,因为它们是标准的)。在任何运行预处理器的编译命令中使用CPPFLAGS,在任何进行链接的编译命令中以及在任何直接使用ld的编译命令中使用LDFLAGS。
如果有C编译器选项必须用于正确编译某些文件,不要在CFLAGS中包含它们。用户希望自己能够自由指定CFLAGS。相反,可以将必要的选项独立于CFLAGS传递给C编译器,方法是在编译命令中显式地编写它们,或者定义一个隐式规则,就像这样:
CFLAGS = -g
ALL_CFLAGS = -I. $(CFLAGS)
.c.o:
$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<
一定要在CFLAGS中包含-g选项,因为正确编译不需要它。您可以将其视为仅推荐使用的默认值。如果包被设置为默认使用GCC编译,那么你也可以在CFLAGS的默认值中包含 ‘-O’。
将CFLAGS放在编译命令的最后,在包含编译器选项的其他变量之后,这样用户就可以使用CFLAGS来覆盖其他变量。
CFLAGS应该在C编译器的每次调用中使用,包括编译的和链接的。
每个Makefile都应该定义变量INSTALL,这是将文件安装到系统中的基本命令。
每个 makefile 还应定义INSTALL_PROGRAM变量和INSTALL_DATA。INSTALL_PROGRAM 的默认值应为 $(INSTALL);INSTALL_DATA的默认值应为 ${INSTALL} -m 644。然后,它应该使用这些变量作为实际安装的命令,分别用于可执行文件和非可执行文件。以下是对这些变量的最小使用:
$(INSTALL_PROGRAM) foo $(bindir)/foo
$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a
但是,最好支持目标文件上的DESTDIR前缀。
在一个命令中安装多个文件是可以接受的,但不是必须的,最后一个参数是一个目录,如:
$(INSTALL_PROGRAM) foo bar baz $(bindir)
十七、安装目录变量
安装目录应该总是用变量命名,因此很容易安装在非标准位置。下面描述了这些变量的标准名称以及它们在 GNU 包中应该具有的值。它们基于标准的文件系统布局;它的变体用于GNU/Linux和其他现代操作系统。
安装程序应在调用 make(例如,make prefix=/usr install)或配置(例如,configure --prefix=/usr)时覆盖这些值。GNU 软件包不应该试图猜测哪个值应该适合于它们所安装的系统上的这些变量:使用这里指定的默认设置,以便所有 GNU 软件包的行为相同,从而允许安装程序实现任何所需的布局。
所有安装目录及其父目录在安装之前都应创建(如有必要)。
前两个变量设置安装的根目录。所有其他安装目录都应该是这两个目录中的子目录,并且不应将任何内容直接安装到这两个目录中。
- prefix:用于构造下面列出的变量的默认值的前缀。前缀的默认值应为 /usr/local。在构建完整的 GNU 系统时,前缀将为空,/usr 将是指向 / 的符号链接。
<! 其他命令见 16.5 Variables for Installation Directories 章节 >
十八、MAKE 变量的工作原理
递归 make 命令应始终使用变量 MAKE,而不是显式命令名称"make",如下所示:
subsystem:
cd subdir && $(MAKE)
此变量的值是调用 make 时使用的文件名。如果此文件名为 /bin/make,则执行的配方为 ‘cd subdir && /bin/make’。如果使用特殊版本的 make 来运行顶级 makefile,则将对递归调用执行相同的特殊版本。
作为一项特殊功能,在规则的配方中使用变量 MAKE 会更改 ‘-t’ (‘–touch’)、‘-n’ (‘–just-print’) 或 ‘-q’ (‘–question’) 选项的效果。使用 MAKE 变量与在配方行开头使用"+“字符具有相同的效果。仅当 MAKE 变量直接出现在配方中时,才会启用此特殊功能:如果通过扩展另一个变量来引用 MAKE 变量,则此功能不适用。在后一种情况下,您必须使用”+"令牌来获得这些特殊效果。
考虑上面示例中的命令"make -t"("-t"选项将目标标记为最新,而无需实际运行任何配方)。按照通常的"-t"定义,示例中的"make -t"命令将创建一个名为子系统的文件,而不执行任何其他操作。你真正想要它做的是运行’cd subdir && make -t’;但这需要执行配方,而"-t"表示不执行配方。
特殊功能使它可以做您想要的:每当规则的配方行包含变量MAKE时,标志"-t","-n"和"-q"都不适用于该行。包含 MAKE 的配方行正常执行,尽管存在导致大多数配方无法运行的标志。通常的 MAKEFLAGS 机制将标志传递给子make,因此您触摸文件或打印配方的请求将传递到子系统。
十九、将变量传递给子make
顶级 make 的变量值可以通过显式请求和环境传递给子 make。这些变量在子 make 中定义为默认值,但它们不会覆盖子 make 使用的 make 文件中定义的变量,除非您使用"-e"选项。
要传递或导出变量,make 会将变量及其值添加到环境中,以运行配方的每一行。反过来,子 make 使用环境来初始化其变量值表。
除非有明确的请求,否则只有在初始环境中定义或在命令行中设置,且名称仅由字母、数字和下划线组成时,才能将export设置为变量。有些shell不能处理由字母、数字和下划线以外的字符组成的环境变量名。
不导出 make 变量 SHELL 的值。相反,调用环境中 SHELL 变量的值将传递给子 make。您可以使用 export 指令强制 make 导出 SHELL 的值,如下所述。
特殊变量 MAKEFLAGS 始终被导出(除非您取消导出它)。如果将 MAKEFILES 设置为任何内容,则会将其导出。
make 通过将命令行上定义的变量值放入 MAKEFLAGS 变量中,自动传递这些变量值。
如果变量是默认情况下通过 make 创建的,则通常不会向下传递变量。子 make 将为自己定义这些。
如果要将特定变量导出到子make,请使用 export 指令,如下所示:
export variable …
如果要防止导出变量,请使用 unexport 指令,如下所示:
unexport variable …
在这两种形式中,导出和取消导出的参数都会展开,因此可能是变量或函数,它们会扩展为要(取消)导出的(变量名称列表)。
为方便起见,您可以定义一个变量并同时导出它,方法是执行以下操作:
export variable = value
具有与相同的结果:
variable = value
export variable
和
export variable := value
具有与相同的结果:
variable := value
export variable
同样地,
export variable += value
就像:
variable += value
export variable
您可能会注意到,导出和取消导出指令在 make 中的工作方式与它们在 shell sh 中的工作方式相同。
如果希望默认情况下导出所有变量,则可以单独使用导出:
export
这告诉 make,应导出或取消导出指令中未显式提及的变量。unexport 指令中给出的任何变量仍不会被导出。如果在默认情况下单独使用export来导出变量,那么除非在导出指令中特别提到,否则不会导出名称包含字母、数字和下划线以外字符的变量。
导出指令本身引发的行为是旧版 GNU make 中的默认行为。如果您的 makefile 依赖于此行为,并且您希望与旧版本的 make 兼容,则可以为特殊目标 .EXPORT_ALL_VARIABLES 编写规则,而不是使用 export 指令。这将被旧的 make 忽略,而 export 指令将导致语法错误。
同样,您可以使用 unexport 本身来告诉 make 在默认情况下不要导出变量。因为这是默认行为,所以您只需要在之前使用过export(可能在包含的makefile中)时才需要这样做。您不能单独使用导出和取消导出来为某些配方导出变量,而不能为其他配方导出变量。最后一个单独出现的导出或取消导出指令决定了整个 make 运行期间的行为。
作为一项特殊功能,当变量 MAKELEVEL 从一个级别传递到另一个级别时,该变量会发生变化。此变量的值是一个字符串,它是作为十进制数的级别的深度。顶级 make 值为 0,次级 make 值为 1,次次级 make 值为 2,以此类推。当 make 为配方设置环境时,会发生增量。
MAKELEVEL的主要用途是在条件指令中测试它。通过这种方式,您可以编写一个 makefile,如果以递归方式运行,则以一种方式运行,如果由您直接运行,则以另一种方式运行。
您可以使用变量 MAKEFILES 使所有子 make 命令使用其他 makefile。MAKEFILES 的值是以空格分隔的文件名列表。如果在外部 makefile 中定义此变量,则通过环境向下传递;然后,它充当额外的生成文件列表,供子 make 在通常或指定的 makefile 之前读取。