0%

一些关于GNU make/Makefile的记录

在平时瞎搞中,经常会遇到GNU工具的一些知识,毕竟GNU和Linux关系紧密。这些工具和知识点对于开发Linux是必不可少的基础,每次忘记了都要谷歌一把,不如记在自己的空间里,方便检索。

Makefile

先来看Makefile。

Makefile基本形式

1
2
target: dependencies
command

Makefile隐式规则

GNU Makefile包含一些默认的规则,通常被称作隐式规则(implicit rules)。

一些常见的隐式规则如下:

  • .o files can be obtained from .c files by compilation. 也就是说可以不用显式的为生成 “XX.o” 文件编写规则,make 会自动的从对应的 “XX.c” 文件编译得到 “.o” 文件
  • an executable can be made by linking together .o files
  • clean has no dependency
  • clean and all are special targets
  • when call make with no arguments, the first target in the makefile is built
  • CC === C compiler
  • CXX === C++ compiler
  • CFLAGS === the compilation options for C programs
  • CXXFLAGS === the compilation options for C++ programs
  • CPPFLAGS === the C PreProcesser options

下面是一个最简单的Makefile示例:

1
2
3
4
5
6
7
8
9
10
CC=gcc
CFLAGS=-Wall

main: hello.o main.o
#这里用到了上面提到的2条隐式规则
#1. hello.o和main.o由hello.c和main.c编译生成,这里没有显式给出编译规则
#2. 可执行文件main通过连接hello.o和main.o得到,这里没有显式给出链接命令

clean:
rm -f main main.o hello.o

变量赋值

Makefile中提供了多种变量赋值方式,来看下常用的几种以及它们的区别。

语法 含义 说明
:= Simple assignment 赋值一次,到处使用;首次遇到变量的时候进行初始化,初始化后变量值保持不变
= Recursive assignment 次次使用,次次更新;每次遇到变量,都重新对变量的值进行评估(赋值中使用了其他变量),变量的值会发生变化
?= Conditional assignment 只有当变量没有值的时候,才会将给定的值赋给变量
+= Appending 追加文本到已有的变量

Makefile通配符和特殊变量

为了使Makefile更通用,在实际编写中会大量使用通配符和特殊变量,来替代Makefile中与某个特定项目相关的文件名、目标名等。这样,Makefile就不受源代码文件的增减、重命名等的影响了,这就是通配符的神奇作用了。

通配符

  • 通配符 % 用于文件名模式匹配,提供通用的targets

    1
    2
    3
    4
    5
    6
    %.o: %.c
    actions

    # When % appears in the dependency list,
    # it is replaced with the same string that was used to
    # perform substitution in the target.
  • 出现在依赖列表中的 % 会被替换为目标中 % 对应的字符串 (单看.o和.c的话,根据前面的隐式规则,是不是就需要写了?)

特殊变量

在 actions/commands 中,通常使用特殊变量来匹配文件名。常用的特殊变量如下:

Special variables Meaning
$@ full target name of the current target
$? returns the dependencies that are newer than the current target
$* returns the text that corresponds to % int the target
$< name of the first dependency
$^ name of all the dependencies with space as the delimiter

PHONY用法

前面提到 allclean 是Makefile中的特殊目标,但是如果当前项目目录中恰好有文件的名字是 all 和 clean呢?

这个时候就需要使用 .PHONY 指令来指定哪些目标不能做被当作文件:

1
.PHONY all clean

模拟执行

有时候需要调试Makefile,但仅仅想跟踪make的执行来查看log,并不想真正运行相关的动作,毕竟编译还是很耗时的。

通过简单的执行 make -n 来做一次“dry run”就可以了。

在变量中使用shell命令

有时我们需要使用shell命令的输出结果,形式如下:

1
LS_OUT = $(shell ls)

未完待续…