Makefile的作用
可以节省每个C文件都包含头文件的麻烦,还可以更改makefile包含的文件,来改变编译的选项
常用符号
$@ – 目标文件
$^ – 所有的依赖文件
$< – 第一个依赖文件。
#为注释
%.o (模式规则)
%.c 以上两个命令将.c文件转换为同名的.o 文件
shell命令,用来找到所有的.c和.h文件
deps = $(shell find ./ -name “.h")
src = $(shell find ./ -name ".c”)
https://blog.csdn.net/qq_31811537/article/details/82892128
在目录中删除文件
clean :
rm edit $(objects)
实际应用中,防止因为存在名为’clean’的文件而混乱,所以使用.PHONYz作为伪目标,
这样输入命令make clean时,会执行clean描述的指令,而不是名字叫clean的文件
.PHONY : clean
clean :
-rm edit $(objects)
makefile文件的命名
默认使用:GNUmakefile, makefile, Makefile
或者使用非标准的文件名,使用 -f 或 --file 指定makefile文件,比如使用 -f name 或者 --file = name告诉make读name这个文件作为makefile文件。
如果-f 或 --flie的参数不止一个,所有的makefile文件会按具体的顺序作用
-c指令
对C文件进行编译,产生.o文件
.o文件是 relocatable 文件,是不可执行文件
例,
gcc -c main.c -o main
-o指令
对 .o文件进行链接,生成可执行文件,不需要按照依赖顺序
gcc -o main main.o
file指令
用来查看文件格式
file main
ar rc指令
libadd_minus.a add_minus.o
将会生成libadd_minus.a 静态库文件
.a静态库文件只是.o文件的合集,本质上还是relocatable文件
-l指令
例如,
gcc -o main2 main.o -L./ -ladd_minus
使用-l指令时,要省略前缀 “lib” 和后缀 “.a”
-f指令
指定路径
将.c文件编译成动态库
gcc multi_div.c -fPIC -shared -o libmulti_div.so
生成 libmulti_div.so文件
makefile操作规则
- makefile根据源文件 和 目标文件的更新时间,来判断是否进行重新编译(若源文件比目标文件更新),提高编译效率
- 若全部都没编译过,则所有C文件都要被编译和链接
- 假若工程的几个文件被修改,则只需编译这几个文件,并重新链接工程
- 若头文件被修改,那么所有包含头文件的源文件都要重新编译和链接。
makefile规则格式
makefile按照栈的关系生成,最先入栈的最后生成(因为前面的文件需要后面的文件支持来生成)
clean命令不会自动执行,只有输入clean时才会执行
makefile的简化
一、使用变量来简化
此处用$(object)表示objects变量的值
二、让make自动推导依赖关系
此处使用的是隐含规则
.PHONY是伪命令,就算输入make clean时,也不会执行clean.exe
edit : $(objects)
gcc -o edit $(objects)
此处使用了makefile隐含规则,因为生成edit文件需要各个.o文件,所以make根据隐含规则,自动根据.c文件生成.o文件
makefile隐含规则
一、
二、 同时生成多个可执行文件
注: 使用 ./文件名 执行可执行文件
命令出错
- 当make检测到命令执行的返回码为不成功时,则终止
- 在makefile命令行前加一个"-"号,此时不管命令是否出错,都认为是成功的
比如:
.PHONY: all
all: p1 p2 p3
p1: p1.c
-gcc p1.c -o p1
此时就算p1.c中语句错误,也认为是成功的
Make的嵌套执行
注: @是没有回显的意思
MakeFile中使用变量
有两种定义方式
第一种为先使用后定义,使用 = 表示,即赋给左值的值是没有定义的也可以,使用时会去找这个未定义的值(全局的找)
第二种为先定义再使用,使用 := 表示,假如还是按照下图例一,foo的值会为空,因为第一行赋值时,bar还没有定义。
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
左上的运行结果为 huh?
右上无法运行,因为a的值为b的值,b的值为a的值,如此递归引用导致无法运行
左下为 foo bar
右下为 bar,因为赋值给y时,x还为空,所以输出为 bar
其他变量
系统环境变量
环境变量(路径)可以在make开始运行的时候载入
all:
@echo $(PATH)
输出: a/b/c/sss
但如果makefile定义了这个变量,则环境变量的值被覆盖(除非make运行时指定了 -e 参数)
PATH := " home"
all:
@echo $(PATH)
输出: home
自动化变量
$@ 表示规则中的目标文件集
hello : 1.c 2.c 3.c
@echo $@
输出: hello
$< 表示规则中依赖目标的第一个目标名字
hello: 1.c 2.c 3.c
@echo $<
输出: 1.c
预定义变量
宏定义
可以控制编译路径
函数功能介绍
ifeq函数
ifeq的意思表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。相当于条件编译中的#if,判断参数1和参数2是否相等,相等的话,就执行以下语句,以endif结尾
例如,
ifeq ($(CC),gcc)
define 命令
将一些语句,定义成一个变量,相当于一个命令包,以endef结尾
例如:
define GET_MCAL_COMP_CONFIG_PATH
具体代码
endef
命令块的参数传递,以下是示例代码
# Get config path for each component
MCAL_COMP_DIR_LIST = Mcu Port Gpt Dio Wdg Spi Can Ipc Pwm Adc
define GET_MCAL_COMP_CONFIG_PATH
ifeq ($(wildcard $(mcal_PATH)/$(1)/config/config_$(MCAL_CONFIG)/.*),)
# Specified config directory not found, default to base config directory
$(1)_CONFIG_PATH += $(mcal_PATH)/$(1)/config
else
$(1)_CONFIG_PATH += $(mcal_PATH)/$(1)/config/config_$(MCAL_CONFIG)
endif
endef
$(foreach MCAL_COMP,$(MCAL_COMP_DIR_LIST),$(eval $(call GET_MCAL_COMP_CONFIG_PATH,$(MCAL_COMP))))
其中$ (1)为参数1,当命令块被调用时(使用call函数调用时),传入的第一个参数,将会代替 ( 1 ) , (1), (1), ( 2)是第二个参数
addsuffix函数
$(addsuffix SUFFIX,NAMES…) 函数名称:加后缀函数—addsuffix。
函数功能:为“NAMES…”中的每一个文件名添加后缀“SUFFIX”。参数“NAMES…”
为空格分割的文件名序列,将“SUFFIX”追加到此序列的每一个文件名 的末尾。
返回值:以单空格分割的添加了后缀“SUFFIX”的文件名序列。 函数说明: 示例: $(addsuffix .c,foo bar)返回值为“foo.c bar.c”
$为引用展开变量展开的值
addprefix函数
加前缀
filter函数
把想要的留下
https://blog.csdn.net/zhoudengqing/article/details/41777957
filter-out函数
把不想要的剔除掉
if函数
https://www.jianshu.com/p/d4ce01b75ddb
subst函数
$(subst _defconfig,,$(b)),意思是将字符串$(b)中的_defconfig去掉
https://blog.csdn.net/pure_dreams/article/details/79976367
patsubst函数
带有规则的替换
strip
去掉最后一个字符后的空格
wildcard函数
功能: 拓展通配符
例如
*是通配符的意思
$(wildcard *.c)
以上这个函数会返回当前目录的所以.c文件的名字,每个名字由空格隔开
Foreach函数
** 格式 ** $(foreach ,,
Eval函数
功能: 展开并运行
其余函数参考地址:
https://blog.csdn.net/ustc_dylan/article/details/6963248
https://blog.csdn.net/yangxuan0261/article/details/52060582#dir-names
CFLAGS 为编译器选项
程序的运行过程:
预处理->编译->汇编->链接
预处理 gcc -E hello.c -o hello.i
编译,生成汇编代码 gcc -S hello.i -o hello.s
汇编,生成.o汇编文件 gcc -c hello.s -o hello.o
链接生成可执行文件 gcc hello.o -o hello
exe文件可以放在makefile里面,可以执行之
函数中用 %不用 *号
export 相当于环境变量,其他文件也可以调用
CURDIR 执行makefile的路径
makefile的层级?
-include 忽略错误