网站首页 > 编程文章 正文
权威参考:
http://www.gnu.org/software/make/manual
make是一个能自动的判断一个大型程序的哪些源代码需要重新编译的工具,并且能够根据判断结果自动调用编译器编译源代码,按照一定的顺序,将编译结果整合成可执行程序。
makefile不是一行一行顺序执行的
Makefile根据写的规则会构建一个依赖树,根据时间戳判断是否需要编译。
隐含规则:
Makefile会自动寻找.c文件生成对应的.o文件
基础知识
目标:依赖列表
命令列表(可以多条)
目标可以是文件,也可以是标签(ALL、clean等),
每一条规则中,目标后的依赖可以为空(目标不一定要有依赖),每一条规则后面也不一定需要命令。但是目标和依赖不能同时没有。
当想要自己指定Makefile文件名时,在执行时,需要使用make -f 文件名
在命令前加上@符号,可以取消打印这条命令本身@gcc test.c -o test
一般在echo语句前加@,加不加@区别如下:
src=$(wildcard ./*.c)#src=myadd.c mysub.c mymyth.c
obj=$(patsubst %.c,%.o,$(src))#obj =myadd.o mysub.o mymyth.o
ALL:mymath
mymath:$(obj)
gcc $^ -o $@
@echo "hello world"
$(obj):%.o:%.c
gcc -c lt; -o $@
clean:
-rm -rf $(obj) mymath
.PHONY:clean ALL
makefile中注释是#,但是不能在命令开始用#,不然他会连着#一起打出来
src=$(wildcard ./*.c)#src=myadd.c mysub.c mymyth.c
obj=$(patsubst %.c,%.o,$(src))#obj =myadd.o mysub.o mymyth.o
ALL:$(obj)
gcc $^
#echo "hello world"
$(obj):%.o:%.c
gcc -c lt; -o $@
clean:
-rm -rf $(obj) mymath
.PHONY:clean ALL
神奇的a.out,在上面的all命令语句中没有指定生成的目标,它就自己生成了a.out。
变量赋值方式:
A:=B:立即展开赋值,
A=B:延迟展开赋值
A?=B :条件赋值,若A之间没有被附过值,将B的值赋值给A,否则A保持原值
A+=B:追加赋值,将B的值连接在A之后,空格分开。
B:=$A
A=10
all:
@echo "A=$A"
@echo "B=$B"
@echo "C=$C"
@echo "D=$D"
@echo "E=$E"
C=$A
A=20
D?=$A
E=5
E+=$A
特殊变量$@、$^、
特殊变量$@、$^、lt;、$、$*、$?
lt;、$、$*、$?
$:当前执行的进程的进程编号
all:f1 f2 f3
@echo '$@ = ' $@
@echo '$^ = ' $^
@echo '$< = ' lt;
@echo '$$ = ' $$ #单引号不进行解析
@echo "$$ = " $$ #双引号进行解析
@echo $@
f1:
@touch f1
f2:
@touch f2
f3:
@touch f3
隐含规则
make -p:查看make的隐含规则
上面的规则其实就是隐含规则。
如果我们没有显示写明某些规则,make会去隐含规则中去查询是否有生成这个规则中的目标的规则存在,如果有就会调用,如果没有就会报错。
$(SRC:%.c=%.o)的含义:将SRC变量中所有以.c结尾的文件名替换成对应的以.o结尾的文件名,然后赋回给SRC。
%可以省略:$(SRC:.c=.o)
SRC=a.c b.c c.h d.h
all:
@echo $(SRC:.c=.o)
@echo $(SRC)
头文件更新与include
Makefile中头文件的更新不会导致make重新编译,可以通过include把目标需要的依赖(gcc -MM -I 源文件.c)包含进Makefile中,让头文件更新后,make时,对应的目标文件重新编译生成。
Makefile中include作用
- 对于一些通用的变量定义、通用规则,写在一个文件中,任意目录结构中的makefile想要使用这些通用的变量或规则时,include指定的文件就好了,而不用在每个makefile中又重写一遍。
- 对于源文件自动生成依赖文件(makefile之目录搜索&自动依赖)时,将这些个依赖关系保存成文件,在需要使用时include进来,这样少了人为的干预,同时也减少的错误的发生。
包含的目标如果没有,会在Makefile中找对应的规则去生成。
例如查看main.o需要的头文件源文件依赖:记住要加-I指定头文件位置,不然会报错。
TARGET = mymath
SRC=$(wildcard ./*.c)#src=myadd.c mysub.c mymyth.c
#obj=$(patsubst %.c,%.o,$(src))#obj =myadd.o mysub.o mymyth.o
CUR_DIR = $(shell pwd)#指定当前目录(变量定义的时候注意不要在变量后面多输入空格,否则空格也会被当作变量的内容,好坑阿)
HEAD_DIR = $(CUR_DIR)/../inc #头文件位置
#HEAD_DIR = $(shell pwd)/../inc #头文件位置
#CROSS_COMPILER = arm-linux- #指定交叉编译环境
CC = $(CROSS_COMPILER)gcc #编译器
CFLAGS=-I$(HEAD_DIR) #编译参数
ALL:$(TARGET)
$(TARGET):$(SRC:.c=.o)
gcc $^ -o $@ $(CFLAGS)
$(obj):%.o:%.c
gcc -c lt; -o $@ $(CFLAGS)
%.d:%.c
# @echo $(HEAD_DIR)
$(CC) -MM -I$(HEAD_DIR) lt; >$@ #查看.c文件对应的.o文件所依赖的头文件,源文件,重定向到.d文件。
#下面这三行作用一样,把.o文件的依赖包含进来,显示指明了.o文件所依赖的头文件,所以头文件改变后,对应的目标文件会进行重新编译。
#include $(SRC:.c=.d)
#-include $(SRC:.c=.d)
sinclude $(SRC:.c=.d)
clean:
-rm -rf $(SRC:.c=.o) $(SRC:.c=.d) $(TARGET)
.PHONY:clean ALL
当修改头文件myadd.h后,make时会进行对应的更新
include中包含的内容可能会影响最终生成的目标,如果include中包含了有目标内容的话。
https://blog.csdn.net/q_z_r_s/article/details/80790560
include包含的内容如下:
myadd.o:myadd.c
gcc -c myadd.c -o myadd.o -I../inc
@echo "helloworld"
Makefile中内容如下:
include test.d
all:mymath.o
mymath.o:mymath.c
gcc -c mymath.c -o mymath.o -I../inc
include放在all前面,就会生成myadd.o,放在all后面就会生成mymath.o
Makefile中变量定义时空格问题
在Makefile中定义变量的时候,注意不要在变量值后面敲空格,否则,它会把空格也当成变量内容的一部分。
a = helloworld
b = helloworld #这里我敲了一个空格
all:
@echo $(a)/
@echo $(b)/
Makefile中变量变量前括号问题
MakeFile中的变量定义 一般在我们书写Makefile时,各部分变量引用的格式我们建议如下:
1. make变量(Makefile中定义的或者是make的环境变量)的引用使用“$(VAR)”格式。
2. 出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的“$tmp”格式。
3. 对出现在命令行中的make变量我们同样使用“$(CMDVAR)” 格式来引用。
层级Makefile
主Makefile:制定规则来说明如何在当前目录下生成最终目标文件。
加一个伪目标clean SUB _DIR
很奇怪,为什么上面程序中$(.^:=/$(SUB_TGT)),不是将原来的值覆盖了,而是接在了后面。
sub=/hello
test=/hello
test:=/world
all:$(sub)
@echo $(^:=/world)
@echo $(sub:=/world)
@echo $(test)
$(sub):
@echo "123"
#顶层Makefile
TARGET = a.out#指定最终生成的目标文件
SUB_DIR = mymath myadd#指定子目录
export SUB_TGT = built-in.o#指定子目标
export TOP_DIR = $(shell pwd)#当前工作目录
export HEAD_DIR = $(TOP_DIR)/inc#指定头文件路径
#export CROSS_COMPILER = arm-linux-#指定交叉编译环境
export CC = $(CROSS_COMPILER)gcc#指定编译器
export CFLAGS = -I$(HEAD_DIR) -Wall#指定编译参数
export LD = ld#指定链接器
export LDFLAGS =#指定链接选项
#生成终极目标规则
$(TARGET):$(SUB_DIR)
$(CC) $(CFLAGS) $(^:=/$(SUB_TGT))
#子目标生成规则,告诉make,进入到对应的子目录中去生成字目标
$(SUB_DIR):
make -C $@
#-C,让make进入到后面的指定目录中
clean:
-rm -vf $(TARGET)
for dir in $(SUB_DIR); do \
make -C $dir clean;\
done
.PHONY: clean $(SUB_DIR)#记得加上子目标,不然子目录已经存在,可能不会去生成子目标
#mymath-Makefile
SRCS = mymath.c
SUB_DIR =
#生成当前目录下子目标规则,由当前目录下的.c文件生成的.o文件和当前目录下的子目录中的目标生成
$(SUB_TGT):$(SRCS:.c=.o) $(SUB_DIR)
$(LD) $(LDFLAGS) $(SRCS:.c=.o) $(SUB_DIR:=/$(SUB_TGT))\
-r -o $@
%.o:%.c
$(CC) $(CFLAGS) lt; -c
%.d:%.c
$(CC) $(CFLAGS) lt; -MM > $@
sinclude $(SRCS:.c=.d)
$(SUB_DIR):
make -C $@
clean:
-rm -vf $(SUB_TGT) $(SRCS:.c=.o) $(SRCS:.c=.d)
for dir in $(SUB_DIR); do\
make -C $dir clean;\
done
.PHONY: clean $(SUB_DIR)
#myadd-Makefile
SRCS = myadd.c
SUB_DIR = mysub
#生成当前目录下子目标规则,由当前目录下的.c文件生成的.o文件和当前目录下的子目录中的目标生成
$(SUB_TGT):$(SRCS:.c=.o) $(SUB_DIR)
$(LD) $(LDFLAGS) $(SRCS:.c=.o) $(SUB_DIR:=/$(SUB_TGT))\
-r -o $@
%.o:%.c
$(CC) $(CFLAGS) lt; -c
%.d:%.c
$(CC) $(CFLAGS) lt; -MM > $@
sinclude $(SRCS:.c=.d)
$(SUB_DIR):
make -C $@
clean:
-rm -vf $(SUB_TGT) $(SRCS:.c=.o) $(SRCS:.c=.d)
for dir in $(SUB_DIR); do\
make -C $dir clean;\
done
.PHONY: clean $(SUB_DIR)
#mysub-Makefile
SRCS = mysub.c
SUB_DIR =
#生成当前目录下子目标规则,由当前目录下的.c文件生成的.o文件和当前目录下的子目录中的目标生成
$(SUB_TGT):$(SRCS:.c=.o) $(SUB_DIR)
$(LD) $(LDFLAGS) $(SRCS:.c=.o) $(SUB_DIR:=/$(SUB_TGT))\
-r -o $@
%.o:%.c
$(CC) $(CFLAGS) lt; -c
%.d:%.c
$(CC) $(CFLAGS) lt; -MM > $@
sinclude $(SRCS:.c=.d)
$(SUB_DIR):
make -C $@
clean:
-rm -vf $(SUB_TGT) $(SRCS:.c=.o) $(SRCS:.c=.d)
for dir in $(SUB_DIR); do\
make -C $dir clean;\
done
.PHONY: clean $(SUB_DIR)
Makefile中export作用
Makefile中有两种export,一种是Makefile中自己的,一种是shell的。
Makefile中自己的export就是用来export变量,让子Makefile中可以使用这个变量,同级的Makefile中不能使用
export varibale=hello#或者
varibale=hello
export variable
export导入系统环境变量?
猜你喜欢
- 2025-04-24 微软首次回答 HoloLens 相关问题,终于爆料了
- 2025-04-24 异步编程系列第04章 编写Async方法
- 2025-04-24 Win10桌面/手机版最深层次开发功能挖掘
- 2025-04-24 Think in Mingdao——人人都是全栈工程师
- 2025-04-24 为什么我选择C#?
- 2025-04-24 引用和变量声明在不同语言中的实作
- 2025-04-24 C# list 转换为sql in的where条件
- 2025-04-24 Java 泛型使用教程
- 2025-04-24 LINQPad:.NET 开发者的交互式编程乐园
- 2025-04-24 桌面程序嵌套Web项目实践之WPF和Blazor混合应用开发
你 发表评论:
欢迎- 05-142014年最流行前端开发框架对比评测
- 05-14七爪源码:如何使用 Next.js 构建 Shopify 店面
- 05-14Web 前端怎样入门?
- 05-14我为什么不建议你使用框架
- 05-14推荐几个好用的React UI 框架
- 05-14PDFsharp:强大的 .NET 跨平台 PDF 处理库
- 05-14一组开源免费的Web动画图标,荐给需要的设计师和程序员
- 05-14salesforce 零基础学习(二十九)Record Types简单介绍
- 最近发表
- 标签列表
-
- spire.doc (59)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- sqljdbc4.jar下载 (56)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- 苹果ios字体下载 (56)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)