前言
本文是关于 makefile文件制作的相关介绍,makefile文件制作是很重要的需要熟练掌握的方法,熟练掌握可以很大的提供工作效率。本文所使用的环境为虚拟机 Ubuntu系统,使用 xshell 进行远程连接调试,所有示例均经过测试无误。
Makefile的使用
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,
Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。
如果后续程序更新了,就可以通过修改 makefile 文件来重新进行编译等操作,可以大大节省程序员的操作
make 是一个命令工具,是一个解释Makefile 文件中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如 Delphi 的 make, Visual C++ 的 nmake, Linux 下 GNU 的 make
一般makefile文件的命名可以是makefile也可以是Makefile
makefile规则
一个 Makefile 文件中可以有一个或者多个规则
目标 ...: 依赖 ...
命令(Shell 命令)
⚫ 目标:最终要生成的文件(伪目标除外)
⚫ 依赖:生成目标所需要的文件或是目标
⚫ 命令:通过执行命令对依赖操作生成目标(命令前必须 Tab 缩进)
Makefile 中的其它规则一般都是为第一条规则服务的。
在实际进行书写时一定要注意缩进格式
实例演示
下面使用这个程序来进行演示 makefile文件的使用
文件
首先是需要用到的文件列表如下,可能在以后的实际开发中,会涉及到更多的文件,是很难进行手动单个依次进行编译的,这里就需要用到makefile文件,进行统一的编译运行,下面是文件结构:
我们需要对这几个文件进行编译链接运行
由于头文件在预编译阶段就已经把内容都复制到代码中了,并且头文件就在当前路径下,也不需要特别去加它的路径了
制作makefile文件
使用命令
vim Makfile
来制作makefile文件,注意文件名,一定是 Makefile
下面是该文件的内容
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文件
使用命令
make
该命令会自动寻找该文件夹下的 Makefile 文件,然后进行执行,就可以生成 可执行程序,运行就可以得到程序运行结果了
工作原理
命令在执行之前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
- 如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,
如果找到了,则执行该规则中的命令
基于这个原理,我们可以使用如下的Makefile文件,依赖需要的 .o 文件还未生成,程序就会自动到下面去找 .o 文件,然后生成
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:add.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
检查更新
检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- 如果依赖的时间比目标的时间晚,需要重新生成目标
- 如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行
在写完 Makefile 文件之后,如果 .c 文件进行了更改,只要文件名没有发生变化,再次使用 make 命令的时候,就会自动比较生成时间,然后再次生成新的 可执行文件
在实际开发中,更推荐使用功能第二种 Makefile文件的写法,因为如果发生更改的话,可以快速找到被修改的文件,然后进行重新编译,而不会像第一种方法那样需要对整个项目进行重新编译生成
变量使用
为了使 Makefile文件使用更加方便,可以使用各种变量来实现快捷书写
自定义变量
变量名=变量值
var=hello
预定义变量
系统已经定义好的变量,可以直接使用
AR : 归档维护程序的名称,默认值为 ar
CC : C 编译器的名称,默认值为 cc
CXX : C++ 编译器的名称,默认值为 g++
$@ : 目标的完整名称
$< : 第一个依赖文件的名称
$^ : 所有的依赖文件
获取变量的值
$(变量名)
在使用变量之后,就可以大大简化书写过程了,现在讲上述文件修改为:
# 定义变量
src=sub.o add.o mult.o div.o main.o
target=app
$(target):$(src)
$(CC) $(src) -o $(target)
sub.o:sub.c
gcc -c sub.c -o sub.o
add.o:add.c
gcc -c add.c -o add.o
mult.o:add.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
clean:
rm $(src)
模式匹配
使用通配符 作为匹配的字符串
% 作为通配符使用,可以匹配一个字符串
两个 % 匹配的是同一个字符串
add.o:add.c
gcc -c add.c
可以替换为:
%.o:%.c
gcc -c $< -o $@
所以这样的话,Makefile文件就可以修改为如下这样:
# 定义变量
src=sub.o add.o mult.o div.o main.o
target=app
$(target):$(src)
$(CC) $(src) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
函数使用
使用
$(wildcard PATTERN...)
//获取指定目录下指定类型的文件列表
参数: PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
$(pathsubst <pattern>,<replacement>,<text>)
//查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换
可以包括通符
%
,表示任意长度的字串。如果中也包含%
,那么, 中的这个%
将是中的那个%
所代表的字串。 (可以用\
来转义,以\%
来表示真实含义的%
字符)
返回:函数返回被替换过后的字符串
实例:
以及:
在使用上述文件进行修改之后,再进行加入清理操作之后,该 Makefile 文件如下
# 定义变量
2 src=$(wildcard ./*.c)
3 objs=$(patsubst %.c,%.o,$(src))
4 target=app
5
6 $(target):$(src)
7 $(CC) $(src) -o $(target)
8
9 %.o:%.c
10 $(CC) -c $< -o $@
11
12 clean:
13 rm $(objs) -f
如下是执行结果:
可以对 clean 命令添加尾执行 命令,使其在最后执行
.PHONY:clean
clean:
rm $(objs) -f
最后
感谢观赏,一起提高,慢慢变强