makefile概述
Makefile是一种用于自动化构建和管理程序的工具。它通常用于编译源代码、链接对象文件以生成可执行文件或库文件。Makefile以文本文件的形式存在,其中包含了一系列规则和指令,用于描述程序的依赖关系以及构建步骤,指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译。核心思想是根据文件的最后修改时间来确定哪些部分需要重新编译,以及以什么顺序来执行编译步骤。每个规则由一个目标(target)和一组依赖项(dependencies)组成,以及执行指令(commands)。
makefile带来的好处就是自动化编译,一旦写好就只需要一个make指令来实现该文件。当执行make命令时,Makefile解析并执行其中的规则。它首先检查目标文件和依赖文件的时间戳,如果目标文件不存在或其依赖项的时间戳较新,则执行该规则所定义的指令来生成目标文件。这种方式可以避免不必要的重新编译,提高构建效率。Makefile中常见的指令包括编译源代码、链接对象文件、复制文件、清理生成的文件等。通过定义变量和规则,可以使Makefile更加灵活和可维护。
Makefile广泛应用于C、C++等编程语言的项目中,但也可以用于其他类型的项目。它是一种跨平台的工具,可以在不同的操作系统上使用,例如Linux、Unix和Windows等。
总而言之,Makefile是一种用于自动化构建和管理程序的工具,通过描述依赖关系和构建步骤,可以有效地管理大型项目的编译过程,并提高开发效率。
makefile文件命名和规则
文件命名
makefile或者Makefile
makefile 规则
一个makefile文件可以有多个规则
目标 ...:依赖...
命令(shell命令)
...
目标:最终要生成的文件
依赖:生成目标所需要的文件或是目标
命令:该target要执行的命令,可以有多个命令行,每个命令行都以TAB 缩进字符开始,[Tab]告 诉 make 此行是一个命令行;
注意:
·makefile的其他规则都是为第一条规则服务的
·依赖中如果有一个以上的文件更新的话,定义的命令就会被执行
·如果一个工程有3个头文件和8个c文件,为了完成前面所述的那三个规则,我们的makefile 应该是下面的这个样子的:
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
gcc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
gcc -c main.c
kbd.o : kbd.c defs.h command.h
gcc -c kbd.c
command.o : command.c defs.h command.h
gcc -c command.c
display.o : display.c defs.h buffer.h
gcc -c display.c
insert.o : insert.c defs.h buffer.h
gcc -c insert.c
search.o : search.c defs.h buffer.h
gcc -c search.c
files.o : files.c defs.h buffer.h command.h
gcc -c files.c
utils.o : utils.c defs.h
gcc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
使用案例
app:sub.c add.c mult.c div.c main.c
gcc sub.c add.c mult.c div.c main.c -o app
在makefile文件里写入以上规则,即可执行:
lin@lin-virtual-machine:~/Linux/lesson05/calc$ make
gcc sub.c add.c mult.c div.c main.c -o app
lin@lin-virtual-machine:~/Linux/lesson05/calc$ ./app
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667
可以有多条规则,接下来我们换一种写法:
app:sub.o add.o mult.o div.o main.o
gcc sub.o add.o mult.o div.o main.o -o app
sub.o:sub.c
gcc -c sub.c -o sub.o
add.o:add.c
gcc -c add.c -o add.o
mult.o:mult.c
gcc -c mult.c -o mult.o
div.o:div.c
gcc -c div.c -o div.o
main.o:main.c
gcc -c main.c -o main.o
执行结果:
lin@lin-virtual-machine:~/Linux/lesson05/calc$ make
gcc -c sub.c -o sub.o
gcc -c add.c -o add.o
gcc -c mult.c -o mult.o
gcc -c div.c -o div.o
gcc -c main.c -o main.o
gcc sub.o add.o mult.o div.o main.o -o app
lin@lin-virtual-machine:~/Linux/lesson05/calc$ ./app
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667
在上面的规则里,当第一条规则没找到对应的依赖时,会依次往下找对应的目标规则
同时这里也反映了之前所说的,makefile里面的其他规则通常是为第一条规则服务的
对于上面的规则,如果我只对main.c函数做修改,那么我们再一次执行make,会发生什么呢:
lin@lin-virtual-machine:~/Linux/lesson05/calc$ make
gcc -c main.c -o main.o
gcc sub.o add.o mult.o div.o main.o -o app
会发现比原先少了很多。
很显然,在执行makefile文件时,会比较依赖和目标文件的时间,正常情况下main.c应该早于main.o,这样不会执行对应的编译规则,但是如果晚于,就会执行,这就是检测更新的手段。
我们编写的两个版本,第一个简短,但是第一个如果有一个.c文件发生修改,则需要重新编译所有的.c文件,效率比第二个版本其实更低。
makefile的变量
预定义的变量:
AR:归档维护程序的名称,默认值为ar
CC:c编译器的名称,默认值为cc
CXX:c++编译器名称,默认值位g++
$@:目标的完整名称
$<:第一个依赖文件的名称
$^:所有的依赖文件
获取变量的值:$(变量名)
模式匹配
%.o:%.c
–%:通配符,匹配一个字符串
–两个%匹配的是同一个字符串
函数
对makefile文件进行化简
#定义变量
src= sub.c add.c mult.c div.c main.c
target=app
$(target):$(src)
$(cc) $(src) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
如下是利用函数进行化简:
#定义变量
src= $(wildcard ./*.c)
objs=$(patsubst %.c,%.o,$(src))
target=app
$(target):$(objs)
$(cc) $(objs) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean
clean:
rm $(objs) -f
需要执行clean规则时,我们需要在make后加上clean
即命令行输入如下命令:
make clean