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

Makefile学习

lipiwang 2024-11-27 17:15 11 浏览 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导入系统环境变量?

相关推荐

前端入门——css 网格轨道详细介绍

上篇前端入门——cssGrid网格基础知识整体大概介绍了cssgrid的基本概念及使用方法,本文将介绍创建网格容器时会发生什么?以及在网格容器上使用行、列属性如何定位元素。在本文中,将介绍:...

Islands Architecture(孤岛架构)在携程新版首页的实践

一、项目背景2022,携程PC版首页终于迎来了首次改版,完成了用户体验与技术栈的全面升级。作为与用户连接的重要入口,旧版PC首页已经陪伴携程走过了22年,承担着重要使命的同时,也遇到了很多问题:维护/...

HTML中script标签中的那些属性

HTML中的<script>标签详解在HTML中,<script>标签用于包含或引用JavaScript代码,是前端开发中不可或缺的一部分。通过合理使用<scrip...

CSS 中各种居中你真的玩明白了么

页面布局中最常见的需求就是元素或者文字居中了,但是根据场景的不同,居中也有简单到复杂各种不同的实现方式,本篇就带大家一起了解下,各种场景下,该如何使用CSS实现居中前言页面布局中最常见的需求就是元...

CSS样式更改——列表、表格和轮廓

上篇文章主要介绍了CSS样式更改篇中的字体设置Font&边框Border设置,这篇文章分享列表、表格和轮廓,一起来看看吧。1.列表List1).列表的类型<ulstyle='list-...

一文吃透 CSS Flex 布局

原文链接:一文吃透CSSFlex布局教学游戏这里有两个小游戏,可用来练习flex布局。塔防游戏送小青蛙回家Flexbox概述Flexbox布局也叫Flex布局,弹性盒子布局。它决定了...

css实现多行文本的展开收起

背景在我们写需求时可能会遇到类似于这样的多行文本展开与收起的场景:那么,如何通过纯css实现这样的效果呢?实现的难点(1)位于多行文本右下角的展开收起按钮。(2)展开和收起两种状态的切换。(3)文本...

css 垂直居中的几种实现方式

前言设计是带有主观色彩的,同样网页设计中的css一样让人摸不头脑。网上列举的实现方式一大把,或许在这里你都看到过,但既然来到这里我希望这篇能让你看有所收获,毕竟这也是前端面试的基础。实现方式备注:...

WordPress固定链接设置

WordPress设置里的最后一项就是固定链接设置,固定链接设置是决定WordPress文章及静态页面URL的重要步骤,从站点的SEO角度来讲也是。固定链接设置决定网站URL,当页面数少的时候,可以一...

面试发愁!吃透 20 道 CSS 核心题,大厂 Offer 轻松拿

前端小伙伴们,是不是一想到面试里的CSS布局题就发愁?写代码时布局总是对不齐,面试官追问兼容性就卡壳,想跳槽却总被“多列等高”“响应式布局”这些问题难住——别担心!从今天起,咱们每天拆解一...

3种CSS清除浮动的方法

今天这篇文章给大家介绍3种CSS清除浮动的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。首先,这里就不讲为什么我们要清楚浮动,反正不清除浮动事多多。下面我就讲3种常用清除浮动的...

2025 年 CSS 终于要支持强大的自定义函数了?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!1.什么是CSS自定义属性CSS自...

css3属性(transform)的一个css3动画小应用

闲言碎语不多讲,咱们说说css3的transform属性:先上效果:效果说明:当鼠标移到a标签的时候,从右上角滑出二维码。实现方法:HTML代码如下:需要说明的一点是,a链接的跳转需要用javasc...

CSS基础知识(七)CSS背景

一、CSS背景属性1.背景颜色(background-color)属性值:transparent(透明的)或color(颜色)2.背景图片(background-image)属性值:none(没有)...

CSS 水平居中方式二

<divid="parent"><!--定义子级元素--><divid="child">居中布局</div>...

取消回复欢迎 发表评论: