百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Makefile学习

lipiwang 2024-11-27 17:15 13 浏览 0 评论

权威参考: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作用

  1. 对于一些通用的变量定义、通用规则,写在一个文件中,任意目录结构中的makefile想要使用这些通用的变量或规则时,include指定的文件就好了,而不用在每个makefile中又重写一遍。
  2. 对于源文件自动生成依赖文件(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导入系统环境变量?

相关推荐

微软Office Open XML中的数字签名漏洞

MicrosoftOffice是最广泛使用的办公文档应用程序之一。对于重要文件,如合同和发票,可以对其内容进行签名,以确保其真实性和完整性。自2019年以来,安全研究人员发现了针对PDF和ODF等其...

Javaweb知识 day12 XML(javaweb中xml作用)

一、XML:1.1概念:ExtensibleMarkupLanguage可扩展标记语言*可扩展:标签都是自定义的。<user><student>1.2功能:...

易筋洗髓功——内外同修方可致远(易筋洗髓功口诀)

达摩祖师所传易筋、洗髓两经,一分为二,二实为一,无非以方便法门接引众生,而归于慈悲清净之心地。修炼《易筋经》是为强身健体,修炼《洗髓经》是为修心养性,此二者相辅相成,内外兼修,缺一不可。这是一套传统中...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 4

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 5

道家洗髓功修炼要义,洗髓功如何做到丹田聚气?

不管是道家洗髓功,还是洗髓经,其修炼的关键点就在于得气、行气、聚气...那么,作为洗髓功修炼者,具体该怎么做呢?在实际修炼中,就洗髓功的修炼方法来讲,我们可以简单的归纳为修炼三部曲,其具体表现如下:一...

「清风聊练功」师门传我易筋经:聊聊我的学习经历和正身图感受

一个人的眼界认识,是随着是自身的知识积累和水平不断成长的。开篇为什么要说这么一句呢?是从我的学习经历上感受明显的这句话:一处不到一处迷。我们学传统武术,内功功法,也是从小白到明白一步步走的,走的越远,...

内功外练功介绍(练内功 外功)

这里介绍我练习的两套动功心得体会。是老道长的八部金刚功、长寿功和增演易筋洗髓经。八部金刚功外练奇经八脉,练出健康强壮的好身体还是可以的,长寿功也是内练功法。这部功法很好的预防效果。这个大家都认同的。说...

孔德易筋洗髓大全注解(下)(孔德易筋经教学视频)

...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 1

少林空悟老师珍藏

国术典籍:《增演易筋洗髓内功图说》【2024年8月编校】

《增演易筋洗髓内功图说》系养生气功著作,全书共十八卷。清周述官编撰于光绪二十一年(1895年)。清光绪十九年(1893年),僧人静一空悟将少林功法传授于周述官,并将《增益易筋洗髓内功图说》十二卷(按,...

小说:自媒体小白的修道之路-洗髓(自媒体小白运营技巧)

谁应了谁的劫,谁又变成了谁的执念。当沧海遗忘了桑田,这世间又多了一个不回家的人!异域空间中,知生缓缓起身,目光扫了一下小帝后,又转身看向画板上的那朵白色蒲公英,自言道:“白瑛,这一世我们莫要再辜负了!...

这才是少林洗髓经真相:它是静功和导引术与八段锦暗合

不少朋友误解易筋经和洗髓经,将其简单归为强力呼吸的吐纳功以及为了提升房中的关窍功。事实上易筋经和洗髓经是两部功法:易筋经主要为炼体,包含以膜论为核心的十二月怕打筋膜法,以及辅助的呼吸、导引功法;洗髓经...

孔德易筋洗髓大全注解(上)(孔德易筋经洗髓经视频)

...

洗髓经传承与心得(二)(《洗髓经》)

...

取消回复欢迎 发表评论: