- 对于一般多字符变量的引用必须使用括号了标记,否则make将把变量名的首字母作为作为变量而不是整个字符串(“
P
A
T
H
”
在
M
a
k
e
f
i
l
e
中
实
际
上
是
“
PATH”在Makefile中实际上是“
PATH”在Makefile中实际上是“§ATH”)。
这一点和shell中变量的引用方式不同。shell中变量的引用可以是“ x x ” 或 者 “ {xx}”或者“ xx”或者“xx”格式。但在Makefile中多字符变量名的引用只能是“ ( x x ) ” 或 者 “ (xx)”或者“ (xx)”或者“{xx}”格式。
name1 := $(word $(words ( M A K E F I L E L I S T ) ) , (MAKEFILE_LIST)), (MAKEFILELIST)),(MAKEFILE_LIST))
include inc.mk
并且下面的定义也相当于 foo = ( P ) A T H 。 如 果 (P)ATH。如果 (P)ATH。如果P变量没有定义,则为ATH。
foo = $PATH
ch = $(wildcard
(
a
d
d
s
u
f
f
i
x
/
(addsuffix /
(addsuffix/(1),
(
s
u
b
s
t
:
,
,
(subst :, ,
(subst:,,(PATH))))
pathsearch = $(firstword $(wildcard
(
a
d
d
s
u
f
f
i
x
/
(addsuffix /
(addsuffix/(1),
(
s
u
b
s
t
:
,
,
(subst :, ,
(subst:,,(PATH)))))
name2 := $(word $(words
(
M
A
K
E
F
I
L
E
L
I
S
T
)
)
,
(MAKEFILE_LIST)),
(MAKEFILELIST)),(MAKEFILE_LIST))
all:
@echo $$(foo) #相当于在命令行执行 @echo $(f00)
@echo $(foo) #相当于 @echo ATH
value函数功能:
不对变量“VARIBLE”进行任何展开操作,直接返回变量“VARIBALE”的值。
-
这里“VARIABLE”是一个变量名,一般不包含“$”(除非计算的变量名)。
如果不是一个变量名(或者在文件中没有找到定义),则value函数返回值为空
ppp=foo
@echo $(value $(ppp)) #效果和@echo $(value foo)一样
@echo $(value foo) #相当于 @echo $PATH
@echo $(value KaTeX parse error: Expected 'EOF', got '#' at position 8: PATH) #̲这里并不会取到path的环境变…P为空,$PATH展开为ATH,而ATH不是变量名。所以value函数的返回值为空。所以相当于执行@echo -
-
美元符号在Makefile中有特殊的含义,所有在命令或者文件名中使用“$”时需要用两个美元符号表示。
@echo $$PATH #显示出PATH环境变量的值,相当于在命令行执行: @echo $PATH@echo pt = $(pathsearch) @echo t = $(ch) @echo name1 = $(name1) @echo name2 = $(name2)
-
-
一类是在这些依赖文件被更新后,需要更新规则的目标;另一类是更新这些依的,可不需要更新规则的目标。我们把第二类称为:“order-only”依赖。书写规则时,“order-only”依赖使用管道符号“|”开始,作为目标的一个依赖文件。
-
- 规则依赖列表中管道符号“|”左边的是常规依赖,管道符号右边的就是“order-only”依赖。这样的规则书写格式如下:
#TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
- 规则依赖列表中管道符号“|”左边的是常规依赖,管道符号右边的就是“order-only”依赖。这样的规则书写格式如下:
-
Makefile中统配符可以出现在以下两种场合:
- 可以用在规则的目标、依赖中,make在读取Makefile时会自动对其进行匹配处理(通配符展开);
- 可出现在规则的命令中,通配符的通配处理是在shell在执行此命令时完成的。
- 除这两种情况之外的其它上下文中,不能直接使用通配符。而是需要通过函数“wildcard”(可参考8.3 文件名处理函数一节)来实现。除这两种情况之外的其它上下文中,不能直接使用通配符。而是需要通过函数“wildcard”)来实现。
-
当规则中依赖文件列表中存在一个“-lNAME”形式的文件时。make将根据“NAME”首先搜索当前系统可提供的共享库,如果当前系统不能提供这个共享库,则搜索它的静态库(当然你可以在命令行中使用连接选项来指定程序采用动态连接还是静态连接,这里我们不讨论)。来看一下详细的过程。
-
- make在执行规则时会在当前目录下搜索一个名字为“libNAME.so”的文件;
-
- 如果当前工作目录下不存在这样一个文件,则make会继续搜索使用“VPATH”或者“vpath”指定的搜索目录。
-
- 还是不存在,make将搜索系统库文件存在的默认目录,顺序是:“/lib”、“/usr/lib”和“PREFIX/lib”(在Linux系统中为“/usr/local/lib”,其他的系统可能不同)。
-
如果“libNAME.so”通过以上的途径最后还是没有找到的话,那么make将会按照以上的搜索顺序查找名字为“libNAME.a”的文件。 假设你的系统中存在“/usr/lib/libcurses.a”(不存在“/usr 但是如果在当前工作目录下存在文件“clean”,情况就不一样了,同样我们输入“make clean”,由于这个规则没有任何依赖文件,所以目标被认为是最新的而不去执行规则所定义的命令,因此命令“rm”将不会被执行。这并不是我们的初衷。为了解决这个问题,我们需要将目标“clean”声明为伪目标。将一个目标声明为伪目标的方法是将它作为特殊目标.PHONY”的依赖。
-
make存在一个内嵌隐含变量“RM”,它被定义为:“RM = rm –f”。
-
空目标文件只是用来记录上一次执行此规则命令的时间。在这样的规则中,命令部分都会使用“touch”在完成所有命令之后来更新目标文件的时间戳,记录此规则命令的最后执行时间。
-
make时通过命令行将此目标作为终极目标,当前目录下如果不存在这个文件,“touch”会在第一次执行时创建一个空的文件(命名为空目标文件名)。
此规则所定义的命令将会被执行,如果是多行命令,那么每一行命令将在一个独立的子shell进程中被执行. -
- 通常系统中可能存在多个不同的shell。但在make处理Makefile过程时,如果没有明确指定,那么对所有规则中命令行的解析使用“/bin/sh”来完成。
-
- 变量引用置换“$(sources : .c=.d)”的功能是根据变量“source”指定的.c文件自动产生对应的.d文件
-
在Makefile中书写在同一行中的多个命令属于一个完整的shell命令行,书写在独立行的一条命令是一个独立的shell命令行。因此:在一个规则的命令中,命令行“cd”改变目录不会对其后的命令的执行产生影响。就是说其后的命令执行的工作目录不会是之前使用“cd”进入的那个目录。如果要实现这个目的,就不能把“cd”和其后的命令放在两行来书写。而应该把这两条命令写在一行上,用分号分隔。这样它们才是一个完整的shell命令行。
-
make的环境变量“SHELL”没有使用系统环境变量的定义。因为系统环境变量“SHELL”指定那个程序被用来作为用户和系统交互的接口程序,它对于不存在直接交互过程的make显然不合适。在make的环境变量中“SHELL”会被重新赋值;为了忽略一些无关命令执行失败的情况,我们可以在命令之前加一个减号“-”(在[Tab]字符之后),来告诉make忽略此命令的执行失败。
-
命令中的“-”号会在shell解析并执行此命令之前被去掉,shell所解释的只是纯粹的命令,“-”字符是由make来处理的。 通过对编译器指定参数-I
来指定头文件所在目录,可以用 #include <>来引用。例如:gcc -I./include hello.c,将从当前目录下的include目录下去寻找头文件。 同理,程序中调用的库函数在编译时也需要指定路径,同时指定库。使用-L 参数指定库文件的目录,-l指定包含的库文件。例如,要使用libXXX.so库,参数为-lXXX。 -
一般一个库编译完成后有库文件和头文件。如果要使用这个库,可以将库文件目录和头文件目录分别用-I和-L参数指定,也可以将他们拷贝到编译器的include和lib目录下。
-
在make的递归调用中,需要了解一下变量“CURDIR”,此变量代表make的工作目录。当使用“-C”选项进入一个子目录后,此变量将被重新赋值。在使用make的递归调用时,在Makefile规则的命令行中应该使用变量“MAKE”来代替直接使用“make”。
ldd:显示可执行文件或者库文件依赖的库文件。
objdump:显示elf可执行文件的内部信息。
-h:显示
-t:显示符号信息
-T:显示动态符号信息。(例如引用动态链接库中的函数名称)
-r:显示重定位入口信息。
-R:显示动态重定位入口信息。(例如:动态链接库中的变量或者函数地址)
-s:显示所有section内容。
-S:反汇编代码段。
objcopy:copy elf文件内容
-R:删除某个section
-j:仅仅复制指定的section
放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,