文章目录
1 总览
Makefile 是一段 “declarative” 的代码
- 描述了构建目标之间的依赖关系和更新方法
- 同时也是和 Shell 结合紧密的编程语言
- 能够生成各种字符串
- 支持 “元编程” (#include, #define, …)
以上内容将在下面的例子中加以体现
2 例子
# Code part1 := -> C #define
NAME := $(shell basename $(PWD))
export MODULE := Lab1
# Code part2 变量 -> 字面替换
all: $(NAME)-64 $(NAME)-32
# Code part3 include -> C #include
include ../Makefile
2.1 immediate assignment vs. recursive assignment
2.1.1 recursive assignment =
Using =
causes the variable to be assigned a value. If the variable already had a value, it is replaced. This value will be expanded when it is used. For example:
HELLO = world
HELLO_WORLD = $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# This echoes "hello world!"
echo $(HELLO_WORLD)
2.1.2 immediate assignment :=
Using :=
is similar to using =
. However, instead of the value being expanded when it is used, it is expanded during the assignment. For example:
HELLO = world
HELLO_WORLD := $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# Still echoes "world world!"
echo $(HELLO_WORLD)
HELLO_WORLD := $(HELLO) world!
# This echoes "hello world!"
echo $(HELLO_WORLD)
2.2 $(shell basename $(PWD))
basename
:basename
is a shell command that extracts the base name (last component) of a path.
$(shell ...)
:$(shell ...)
is a Make function that allows you to execute shell commands within a Makefile.
2.3 export MODULE := Lab1
- This line exports the variable
MODULE
with the value “Lab1.” - The export keyword makes the variable available to sub-makes (subdirectories) when they are invoked.
- It makes
MODULE
a global constant. - Code part1 is equivalent to a C
#define
statement
2.4 all: $(NAME)-64 $(NAME)-32
- This line defines a target named all that depends on two other targets:
$(NAME)-64
and$(NAME)-32
. - It is similar to a function call in C, where all is the function, and
$(NAME)-64
and$(NAME)-32
are the arguments. - 进行了字面替换(Literal Substitution)
2.5 include ../Makefile
- This line includes the contents of the
Makefile
in the parent directory. - It is equivalent to a C
#include
statement, allowing the Makefile to include additional rules and definitions from another file.
3 说明
- Generating Strings(字符串生成) and Metaprogramming(元编程)
- Makefiles are not just for specifying build rules; they are also a form of programming language. Makefiles can generate various strings dynamically during the build process.
- Makefiles support a form of “metaprogramming” where you can use constructs like
#include
and#define
to include external files or define macros, respectively.
4 在Makefile复杂时,如何应对
- 先观察
make
命令实际执行了什么 (trace)- make的主要功能:首先是Makefile描述了一个有向无环图,然后make工具会按照对应的拓扑排序的顺序去构建,同时忽略哪些不需要构建的目标
- 那么我们可以按照trace去阅读Makefile,即可做到有的放矢,也可以知道Makefile中哪些执行了,哪些没有
- 再利用make 提供的两个有用的选项
-n
or--just-print
只打印命令不运行-B
or--always-make
强制 make 所有目标
make -nB \
| grep -ve '^\(\#\|echo\|mkdir\)' \
| vim -
- 在进入了vim之后,就拥有了丰富的手段,用来调整文本,使得其可读性增加
:set nowrap
让一行文本避免折叠,连续一行显示
4.1 grep
-
-v
(or--invert-match
):- This option inverts the sense of matching, meaning it selects lines that do not match the specified pattern for the example above.
- For example,
grep -v pattern
will display lines that do not contain the specified pattern.
-
-e
(or--regexp
):- This option allows you to specify a pattern or regular expression to search for in the input.
- You can use multiple
-e
options to specify multiple patterns, and grep will match lines that contain any of the specified patterns.
-
grep -ve '^\(\#\|echo\|mkdir\)
\
Backslash serves as an escape character.^
Anchors the pattern to the beginning of a line. It ensures that the pattern only matches lines where the specified sequences occur at the start()
Define a grouping in the regular expression. The escaped parentheses (\(
and\)
) are used to group multiple patterns together.\
Acts as a logical OR in the regular expression. It allows the pattern to match lines that contain any of the alternatives separated by |.- This is a regular expression that matches lines starting with ‘#’, ‘echo’, or ‘mkdir’.
4.2 vim
-
tells vim to read from standard input.
4.3 总结
在对make实际执行的结果进行grep的选择和vim的规整之后,可以发现(或者说是推测出)Makefile其实并不复杂(详见后续博客),就是一堆 gcc -c
(编译) 和一个 gcc
(链接) 。原来大部分 Makefile 都是编译选项