Linux学习:makefile介绍
一、为什么使用 makefile?
makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令, 整个工程完全自动编译, 极大的提高了软件开发的效率。
同时,makefile 文件中可以定义一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。
二、makefile 的命名规则
(1)规则:
目标...: 依赖... // 注意:一个 makefile 中可以有多个规则
(tab)命令 // 注意:tab 缩进不能是 4 个空格.....
(2)三要素:
目标:要生成的目标文件。
依赖:目标文件由哪些文件生成。
命令:如何通过执行该命令使依赖文件生成目标文件。
三、makefile 的设计思路
(1) 需求:
1)含有头文件、加减乘除的实现文件、测试 main 文件。
(include 目录包含 head.h 、add.c div.c mul.c sub.c 、main.c) 。
2)将这 3 类文件制作成 makefile 文件,实现自动编译,生成 app 可执行文件。
1、第一版本:最简单
app: add.c div.c mul.c sub.c main.cgcc add.c div.c mul.c sub.c main.c -o app -I include
(1)说明:
目标:app 文件
依赖:用于生成目标(add.c div.c mul.c sub.c main.c)
命令:gcc 编译(-o 指定名称 app 因为有头文件,所以要有 –I)
(2) 缺陷:
改变一个依赖文件(例:只 touch add.c 甚至不改变其内容),所有依赖文件都要重新更新编译
2、第二版本:依赖于.o 文件
app: main.o add.o div.o mul.o sub.ogcc main.o add.o div.o mul.o sub.o -o app
(1) 相较于第一个版本,依赖于.o 文件。
(2) 命令依然是 gcc,区别是由.o 生成 app。
(3)第一个目标(app)称为终极目标。因为终极目标依赖于.o 文件,所以需要依赖于“.c 文件”生成“.o 目标”,因此,有以下内容:
main.o: main.c
gcc -c main.c -I include
add.o: add.c
gcc -c add.c -I include
div.o: div.c
gcc -c div.c -I include
mul.o: mul.c
gcc -c mul.c -I include
sub.o: sub.c
gcc -c sub.c -I include
(4)相较于第一版的好处是改变一个依赖文件,只有 改变的依赖文件和终极目标需要重新生成,其他不动。
(5) 缺陷:
相似代码体太多
(6)铺垫知识:
1)makefile 中的变量:
makefile 中的变量有点类似于 C 语言中的宏定义,使用该变量相当于内容替换,使用变量可以使 makefile 易于维护,修改起来变得简单。
2)变量的分类:普通变量、自动变量
普通变量 (严格区分大小写),定义 key = val 引用 val $(key)。举例 foo = a.o b.o c.o $(foo) 就相当于 a.o b.o c.o
自动变量:特别注意:自动变量只能在规则的命令中使用.
$@ 表示规则中的目标
$< 表示规则中的第一个依赖条件
$^ 表示规则中的所有的依赖条件
3、第三版本: “模式规则”(利用 makefile 变量 和 占位符% 实现)
app: main.o add.o div.o mul.o sub.o
gcc $^ -o $@ // $^ 指所有的.o文件 //$@ 指app ,编译所有的.o文件生成目标,并指定为app
%.o:%.c // % 是占位符
gcc -c $< -o $@ -I include // $< 第一个的.c 文件 ,编译一个.c 文件($<)生成.o 文件($@)
(1)缺陷:
终极目标 app 的依赖是完全定死的,扔到另一个项目中就不能用了,可移植性差。
(2)铺垫知识:makefile 函数(所有的函数都有返回值,我们基本都是需要它的返回值)
1)wildcard :查找指定目录下的指定类型的文件
src = $(wildcard ./*.c) //找到当前目录下所有后缀为.c 的文件,引用返回值给 src
2)patsubst :匹配替换
obj = $(patsubst %.c , %.o , $(src) ) //把 src 变量里所有后缀为.c 的文件替换成.o ,$(src) == *.c
4、第四版本:利用 makefile 函数
// makefile 函数
src = $(wildcard *.c) // 当前目录下,所有 .c 文件
obj = $(patsubst %.c , %.o , $(src) ) // 当前目录下,所有 以.c 文件生成的.o 文件
// makefile 普通变量
target = app // 如果主体多次使用 app,想修改终极目标,只需要在这里改一次就行了
cc = gcc
// makefile 自动变量(模式规则)
$( target): $(obj)
$(cc) $^ -o $@
%.o:%.c
$(cc) -c $< -o $@ -I include
(1)缺陷:每次重新编译都需要手工清理中间.o 文件和最终目标文件
(2)铺垫知识: clean / make clean
用途:清除编译生成的中间.o 文件和最终目标文件
1)出现的问题:make clean 如果当前目录下有同名 clean 文件,则不执行用于清除的 clean 命令,这时解决方法为:.PHONY:clean(伪目标声明)。
效果:声明伪目标之后, makefile 将不会检查该目标是否存在或者该目标是否需要更新。
2) clean 命令中的特殊符号:
– 此条命令出错,make 也会继续执行后续的命令。如:-rm main.o
。
rm –f :强制执行,主要解决:如果要删除的文件不存在使用 –f 不会报错。
3)@不显示命令本身,只显示结果。如:@echo clean done
(3)其他:
1)make 默认执行终极目标,可通过“make 目标名”指定要执行的目标,例如 make clean
。
2)make –f:例如,有 makefile、makefile1,使用 make 命令,默认执行 makefile,若想指定运行makefile1,则 make –f makefile1
5、第五版本:最终版本
// makefile 函数
src = $(wildcard *.c)
obj = $(patsubst %.c , %.o , $(src) )
// makefile 普通变量
target = app
cc = gcc
// makefile 自动变量(模式规则)
$( target): $(obj)$(cc) $^ -o $@
%.o:%.c $(cc) $< -c -I include -o $@
// 清理工作
.PHONY: clean //添加伪目标,防止歧义 // 注意以 “." 开头
clean:rm -f $(target) rm -f $(obj)
四、 makefile 的工作原理
1、目标的生成
若想生成目标,首先检查规则中的所有的依赖文件是否都存在:
如果有的依赖文件不存在, 则向下搜索规则,看是否有生成该依赖文件的规则:
(1)如果有规则用来生成该依赖文件,则执行规则中的命令生成依赖文件,再生成终极目标。
(2)如果没有规则用来生成该依赖文件,则报错
例如:
第一版本:依赖文件.c 都存在,直接生成目标。
第二版本:依赖文件.o 不存在,向下搜索。
有生成该依赖文件的规则(依赖.c 生成目标.o)则也可以生成目标。
2、目标的更新:
如果所有依赖都存在,想要检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则有关目标必须更新。
(1)说明:
第一版本中,一个依赖被更新,所有依赖都更新,然后更新终极目标。
第二版本中,一个依赖被更新,只有该依赖对应的目标更新,然后再更新终极目标。
(2)是否更新的判断方法:看“依赖的最后访问时间”是否晚于“目标的最后访问时间”。
依赖的最后访问时间 < 目标的最后生成时间 早于 不更新。
依赖的最后访问时间 > 目标的最后生成时间 晚于 更新。
Linux学习:makefile介绍相关推荐
- Linux学习-01-Linux介绍
1 Linux简介 1.1 操作系统介绍 操作系统(Operating System,OS):也是软件的一种,是硬件基础上的第一层软件,位于硬件和应用程序之间的底层的软件,是硬件和其它软件沟通的桥梁( ...
- linux下Makefile学习--注释很好
什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都 为你做了这个工作,但我觉得要作一个好的和 professional的程序员,makefile还 ...
- linux添加自己的库,Linux学习笔记——例叙makefile 增加自定义共享库
Linux学习笔记--例说makefile 增加自定义共享库 0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己 ...
- Linux学习笔记 文件服务Vsftp详细介绍
Linux学习笔记 文件服务Vsftp详细介绍 知识点: 1.FTP使用TCP连接和TCP端口 2.在进行通信时,FTP需要建立两个TCP连接: 一个用于控制信息,TCP端口号缺省为21 一个用于数据 ...
- Linux学习笔记之——Linux系统内部相关介绍
Linux学习笔记之--Linux系统内部相关介绍 摘要:主要记录一些比较有用的能够帮助理解和使用Linux的知识.比如一些相关概念.没兴趣的看看就好.知道有这么个东西.注意事项.和一些常用目录的作用 ...
- 我的Linux学习记录(蓝桥)————入门环境介绍
我的Linux学习之旅(蓝桥) 嘿,首先让我们看看Linux的页面: 差不多长这个样,其中呢: 这个玩意就是你windows的这个玩意 这个东西,就是你windows下win+R然后输入cmd跳出来的 ...
- linux下makefile
概述 -- 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都 为你做了这个工作,但我觉得要作一个好的和 professional的程序员,mak ...
- linux 内核 企鹅,Linux 内核 Makefile 体系简单分析
众所周知,Linux内核是使用make命令来配置并编译的,那必然少不了Makefile.在内核目录树中我们可以看到内核编译系统的顶层Makefile文件.但是如此复杂.庞大的内核源码绝不可能使用一个或 ...
- Linux学习笔记 驱动开发篇
ARM Linux 驱动开发篇 本篇我们将会详细讲解 Linux 中的三大类驱动:字符设备驱动.块设备驱动和网络设备驱动. 字符设备最多,从最简单的点灯到 I2C.SPI.音频等都属于字符设备驱动的类 ...
- linux 学习之路
很多同学接触Linux不多,对Linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机IT行业从业人员, 掌握Linux是一种很重要的谋生资源与手段. 下来我将 ...
最新文章
- dockefile nginx php,dockerfile自动部署nginx+php7
- 微信拦截URL,使用自己内置的web组件打开URL,为什么没人声讨?
- 如果要和外国人做项目,加入一个teams是第一步,就跟我们的企业微信,钉钉差不多
- win32程序启用控制台-- 调试输出
- Linux命令学习(三):文件操作命令(1)
- STL--lower_bound()upper_bound();
- 如何使用Angular rxjs进行优雅限流
- Java中的迭代与递归
- sha256加密_有加密传输数据的需求?来试试stunnel
- bat 调用class文件_[Golang实现JVM第五篇]静态方法调用的实现
- 普中科技51单片机_【笔记】-普中科技-51单片机-按键
- 诺基亚n8系统更新服务器模式,新年新版本 诺基亚N8最新固件PR1.1亮相
- 汤国安:GIS教育可能要崩盘
- 惠普电脑u盘重装系统步骤_惠普电脑怎么用u盘重装系统步骤
- 迅雷离线下载脚本 — LinuxTOY
- CVPR 2022 Oral|PoseConv3D开源: 基于人体姿态的动作识别新范式
- 由“微博”的发展史预测“轻博客”的命途
- 项目review会议的步骤_8个步骤,使您的下一次会议更有效率
- linux如何设置开启在指定的tty下自启动程序
- windos 为什么会突然服务停止了_Win7系统print spooler服务总是自动停止怎么办?
热门文章
- 来试试读论文的新神器!AMiner发布“论文背景文献”一键生成工具,帮你搞清一篇论文的“来龙去脉”...
- ACL 2018论文解读 | 基于路径的实体图关系抽取模型
- python怎么批量处理数据的优点_Python数据处理干货,一文带你深入理解pandas的批量处理方式...
- ceph-deploy mod add_GTA5 1.50NPC自杀 MOD [支持1.411.50版本] 覆盖版【5.19MB】
- java的jbutton啥意思,Jbutton和Jpanel和JFrame之间的区别?
- jmeter mysql 连接复用_JMeter 连接MySQL
- 使用回溯算法分析八皇后问题
- 「中间件系列一」kafka消息中间件
- 微服务架构下的安全认证与鉴权
- 牛客题霸 NC30 数组中未出现的最小正整数