makefile是GUN执行make调用的程序,用来组织项目中的文件按照一定的规则被编译,其核心是规则

程序的编译过程

先来看看程序的编译过程

大体上分为四步:

  • 预处理
  • 编译,生成.s文件
  • 汇编,生成.o文件,是二进制文件
  • 链接,将多个.o文件链接在一起,生成可执行文件ELF文件

file命令查看文件格式:

makefile语法

Makefile的基本格式很简单:

目标 : 依赖1 依赖2 ...
[TAB]命令

执行命令的条件:

  • 当目标文件不存在
  • 或者某个依赖比目标文件新

makefile通配符

  • %.o 表示某个.o文件
  • *.o 表示所有的.o文件
  • $@ 表示目标
  • $< 表示第1个依赖文件
  • $^ 表示所有依赖文件

makefile变量的两个特色

Makefile中变量分为两类,一类是即时变量,另一类是延时变量,这在GUN make中文手册中被翻译为Makefile变量的两个特色

A := xxx

  • A的值即刻确定,在定义时即确定

B = xxx

  • B的值使用到时才确定

:= 即时变量
= 延时变量
?= 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句
+= 附加, 它是即时变量还是延时变量取决于前面的定义

makefile函数

使用这些函数的目的是为了替代手动输入大量的.c或者.o文件组成的字符串(大项目中可能有成千上万个文件),因此这些函数的输出都是字符串

makefile所有的函数都有返回值,我们使用函数也是为了读取它的返回值

  • 查找所有

    查找当前目录下所有的.c文件

src = $(wildcard ./*.c)

返回一个字符串,如下:

  • 按格式替换

    替换当前目录下的.c为.o的形式,.c来源于上面的src变量,注意这里是一对一替换,因此是%而不是*

obj = $(patsubst ./%.c, ./%.o, $(src))

返回也是一个字符串,注意这只是修改了字符串中每个文件的后缀生成一个新的字符串,并不生成文件,结果如下:

  • 替换所有

    将obj里面的文件依次取出并放在f中,并改成f.d的形式,注意f是变量,要加上$(f),输出这个字符串

oobj=$(foreach f, $(obj), $(f).d)

结果如下:

  • 过滤文件

    将src里面的符合xx.c形式的文件取出来,注意这里是依次取出,因此是%

obj=$(filter %.c, $(src))

输出结果:

  • 反过滤函数

filter-out用法与filter相反,不再介绍

完整代码

这个代码会生成两个目标,适用于编译多个可执行文件,上面的输出信息写在终极目标的命令中,因为终极目标不需要执行任何gcc指令
.PHONY : clean,声明一个伪目标,在文件夹下有文件名为clean的文件时,依然会执行makefile里面的clean指令,否则会执行这个clean文件,做个试验测试一下即可

CC = gcc
CFLAGS = -Wall -g

# 查找,获取的也是一个字符串
src = $(wildcard ./*.c)
# 替换指定格式的文件
obj = $(patsubst ./%.c, ./%.o, $(src))
# 替换所有
dbj=$(foreach f, $(obj), $(f).d)
# 过滤文件
fbj=$(filter %.c, $(src))


target : client server
	echo $(fbj)
	
client : client.o sckutil.o 
	$(CC) $(CFLAGS) -o $@ $^
	
server : server.o sckutil.o 
	$(CC) $(CFLAGS) -o $@ $^

%.o:%.c 
	$(CC) -c -o $@ $<

# 伪目标
.PHONY : clean
clean:
	rm -rf *.o client server

以上是学习makefile必备的基础知识,知识来源于积累,,,


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

mmap 上一篇
Linux下的静态库与动态库 下一篇