在Linux环境下,我们完成一个文件的编译,只需要一个gcc [filename]的命令;但是,当我们在编译一个项目的时候,如果还想使用一个命令来完成整个项目的编译工作,只有借助于makefile,来完成“自动编译”;
makefile/Makefile存放着我们自己编写的编译规则;而make 是一个解释 makefile中指令的命令工具
makefile的编写规则:
目标对象:依赖对象
编译命令
eg:我们有一个test.c文件,编译生成可执行文件test,我们的makefile的编写如下所示:
test:test.c //目标对象(可执行文件test):依赖对象(源文件test.c)
gcc -c test.c -o test //编译命令(编译规则)
倘若我们拥有多个依赖对象例如 test.c add.c sub.c 等,此时我们的makefile应如下
test:test.c add.c sub.c
gcc -c test.c add.c sub.c -o test
预定义变量:
犹如我们上面已经明确了目标对象和依赖对象,所以我们在编译规则中可以使用makefile预定义变量:
^@表示目标对象
^$表示生成目标对象的所有依赖对象
^<表示第一个依赖对象
上面的makefile我们可以改写为
test:test.c add.c sub.c
gcc -c ^$ -o ^@ -g (倘若我们希望可执行程序是可以调试的,即Debug版本,需要在编译命令中加入-g选项)
自定义变量:
在上面我们了解了三个makefile的预定义变量,其实在makefile中,我们也可以自定义变量
但是在使用自定义变量的时候,我们需要使用变量的时候要用到$()
以上面的makefile为例
SRC=test.c add.c sub.c //自定义变量SRC表示生成test所需要的依赖对象,使用变量的好处是,当以后需要更改依赖对象的时候,我们只需要在定义变量的时候进行更改,更加的方便
test:$(SRC)
gcc -c $(SRC) -o test
$()除了用于使用变量,还可以引用shell命令 ,获取命令的结果
$(shell mkdir include) //创建一个include文件夹
PATH=$(shell pwd) //将当前所在的目录存于PATH变量中
函数:
wildcard:
该函数调用出为已经存在的、使用空格分开的、匹配此模式的所有文件列表
通常搭配通配符;
eg:SRCS=$(wildcard *.c)
将当前目录下所有的.c文件赋给变量SRCS
倘若当前目录下我们存放有add.h add.c main.c 三个文件
这面的那行命令对应为SRCS=add.c main.c
addprefix:
该函数用于添加前缀
eg:
BIN=main //定义了一个变量BIN,用于保存执行文件
BUILD_ROOT=/root/work //定义了一个变量,用于保存路径
BIN := $(addprefix $(BUILD_ROOT)/, $(BIN)) //给可执行文件添加路径
//BIN=/root/work/main
符号:
@ :表示在make执行的时候,在输出的信息中,不显示此行命令
- :如果执行当前行时,出现错误,则忽略
注释:
为他人或自己日后能够快速地了解,编写的makefile,注释是必不可少的
makefile文件中 "#"字符时注释的开始,就相当于C语言的 " // "
eg:
#定义了一个变量BIN,用于保存执行文件
BIN=main
#定义了一个变量,用于保存路径
BUILD_ROOT=/root/work
#给可执行文件添加路径 BIN=/root/work/main
BIN := $(addprefix $(BUILD_ROOT)/, $(BIN))
包含其他的makefile
在一个项目中,我们一定会有多个目录,存放不同的文件;每个目录下,我们都有可能要编写一个makefile,将这些makefile关联起来,是十分重要的一件事;
完成这件事情,我们一定会遇到一个老朋友include ,我们在使用include包含其余makefile的时候,最好要把路径加上,确保能够被找到
eg:
BUILD_ROOT=/root/work
include $(BUILD_ROOT)/common.mk
注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!