Makefile文件的编写规则
欢迎大家关注笔者,你的关注是我持续更博的最大动力
Makefile文件编写规则
文章目录:
- 1 makefile文件介绍
- 2 makefile文件编写
1 makefile文件介绍
makefile是一个
项目代码管理工具
,是管理我们程序的源代码
的 ,makefile只是一个文件
,在这个文件中记录了我们程序编译的步骤(和gcc命令编译一样,只是方便管理),
为什么需要makefile呢?
例如我们有一个项目,项目中有100个文件,项目做完之后需要编译成一个可执行文件
,这样在编译程序的时候gcc
就会写的很长
,如果你只修改某个文件中的一个符号,就要gcc
重新编译,这样就很容易出错,而且找错不太好找。因此,我们可以使用代码管理工具makefile,把代码的所有编译命令
都写到makefile
中,然后执行一些makefile中的命令,程序就会编译生成一个可执行文件
2 makefile文件编写
一、makefile文件命名的两种方式:
- 全部小写:makefile
- 首字母大写:Makefile
二、makefile里命令的规则
1、规则中的三要素
- 目标:最终生成可执行程序的名字
- 依赖:生成可执行程序的
条件
(即源代码
) - 命令:使用依赖生成对应的可执行程序
2、第一个版本的makefile
目标:依赖条件命令 (前面有一个Tab空格)# 文件的目录结构
├── add.c
├── head.c
├── main.c
├── makefile
├── mul.c
└── sub.c# 1、先新建一个makefile文件,里面的内容如下
# (make编译的时候,默认是在当前目录下找这些.c文件,如果有不在当前目录下的需要制定路径位置)
myapp:main.c add.c sub.c mul.cgcc main.c add.c sub.c -o myapp# 编辑好makefile内容,保存退出,然后用make进行编译
>>>make makefile
3、第二个版本的makefile
上面的这种makefile是最low的,也存在一个问题,如果我们有一个.c
文件发生了修改,那么所有的文件都要重新编译一次,如果文件特别多这样就会浪费很多的时间,效率非常低。想要提高效率:就是只对修改的文件进行重新编译,没有修改的就不编译,就对.c
文件分开来编译
,就需要生成.o
文件
# myapp终极目标:可执行程序,因为依赖是一些 .o文件, 而我们是没有这些文件
# 因此就需要在下面的子目标中生成这些依赖的 .o文件
myapp:main.o add.o sub.o mul.ogcc main.o add.o sub.o mul.o -o myapp# main.o是子目标
main.o:main.cgcc -c main.cadd.o:add.cgcc-c add.cmul.o:mul.cgcc -c mul.csub.o:sub.cgcc -c sub.c
解释:
当生成可执行程序
myapp
时,查找依赖发现没有main.o,add.o等文件,就会向下查找规则,有没有生成这些.o文件
的规则
(编译生成这些.o文件依赖的命令
),找到如果有就会执行下面的规则,全部执行完之后,再执行我们生成终极目标的规则。(下面的子目标规则,都是为了生成终极目标可执行文件服务的
)
注意:
- 1)写在开头的是终极目标
- 2)makefile子目标有没有更新,为什么可以只编译修改的,是根据文件的
修改时间对比
来实现的(这也是makefile的工作原理
) - 3)makefile中的注释用
#
4、makefile文件简化
上面的文件有两个地方可以进行简化:
- main.o add.o sub.o mul.o 上下都出现了写文件,对于这种多次使用的可以用
变量赋值
,makefile不需要变量类型 - 下面的四个子目标的的规则一样,可以用
修改如下:
obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj)gcc $(obj) -o $(target)# main.o是子目标
%.o:%.cgcc -c $< -o $@
在vi底行模式下的替换 : 3,4s/app/$(target)
把第3,4行的app 替换成$(target)
说明,模式规则的三个自动变量
使用:
- %.o:相当于是对上面依赖的一个占位天空,当需要依赖main.o它就会变成main.o,后面与前面匹配就是main.c
- $<:规则中的第一个依赖,如果把其套到第一个规则中,第一个依赖就是main.o,如果套到第一个子规则中,它的第一个依赖就是main.c
- $@:规则中的目标 ,如果套到第一个子规则中,其目标就是main.o
- $^:规则中所有的依赖
上面的三个模式规则
只能在规则的命令中使用,即只能写到第二行中
eg:根据上面的规则:
- gcc main.o add.o sub.o mul.o -o myapp 可以修改如下
- gcc $^ -o $@
5、makefile中有一些系统自己维护的变量
makefile中有一些系统自己维护的变量,一般
大写
,例如:CC=cc, CC的默认值就是cc,cc其实就是gcc,你也可以修改为CC=gcc
常用的一些系统维护变量:
- CC=gcc : 编译命令gcc,用户可以修改这些默认变量的值
- CPPFLAGS=-I :编译命令的预编译参数
-I
- CFLAGS=-WALL -g -c :编译的时候使用的参数
- LDFALGS=-L -l :链接库使用的选项
6、makefile中函数
makefile中函数调用都是有返回值的,我们函数调用的目的就是为了拿到返回值,然后获取一些信息。
上面我们的所有.o
文件的名字都是我们手动指定的obj=main.o add.o sub.o mul.o,如果有很多.o
文件,我们不可能全部手动指定,这样会很繁琐。此时我们就可以通过makefile中的一个函数获取当前目录中的.o
文件,但是这些.o
文件在程序没有执行的时候是不存在的,是我们在编译程序的时候生成的中间文件,但是这个.o
文件是通过.c
文件生成的,因此需要获取指定目录下的.c文件,这样才能够生成对应的.o文件
,因此,这里需要用到两个函数:
- 获取指定目录下的
.c
文件
src=$(wildcard ./*.c)
:wildcard
是函数名
,表示从某目录下查找文件,./*.c
是函数参数
,表示在当前目录下查找所有的.c
文件,然后获取返回值
,再函数前面加一个$
符号即可(加括号就是为了使用$符号取返回值)(返回的结果就是:m ain.c add.c sub.c mul.c)。
- 把对应的
.c
文件换成.o
文件
obj=$(patsubst ./%.o, ./%.c, $(src))
:patsubst
是函数名,该函数是一个匹配替换函数
。把当前目录下的所有.c
文件替换为同名的.o
文件,.c
文件来自$(src)
使用上面的两个函数之后,不管当前目录下有多少文件,它会自动搜索所有的.c
文件,然后做一个字符串替换成对应的.o
文件,返回到obj。
#obj=main.o add.o sub.o mul.o
target=app#src返回的内容就是我们从指定目录下查找的.c文件
src=$(wildcard ./*.c)
#把所有的.c替换成.o,这样得到的obj和我们手动指定的一样
obj=$(patsubst ./%.o, ./%.c, $(src))
# makefile自己维护的变量
CC = gcc
CPPFLAGS = -I
$(target):$(obj)$(CC) $(obj) -o $(target)# main.o是子目标
%.o:%.cgcc -c $< -o $@
7、清除makefile编译生成的一些文件
当我们需要重新编译
的时候,可以删除之前生成的一些中间文件。
target=appsrc=$(wildcard ./*.c)
obj=$(patsubst ./%.o, ./%.c, $(src))
# makefile自己维护的变量
CC = gcc
CPPFLAGS = -I
$(target):$(obj)$(CC) $(obj) -o $(target)# main.o是子目标
%.o:%.cgcc -c $< -o $@# 删除我们生成的中间.o文件和可执行文件,当我们需要重新编译的时候使用
clean:rm $(obj) $(target)hello:echo "hello, makefile"
然后在命令行中使用:
>>>make clean
:即可清除之前编译生成的中间文件。此时只会执行clean
这个子目标。
当要删除的文件在不存在的时候就会在命令行中提示:无法删除,或没有那个文件/目录,此时可以在后面加一个-f
参数,表示无论存在与否,都会强制删除
,也不会提示不存在信息。
clean:rm $(obj) $(target) -f
注意:
- clean是要生成的目标
- clean没有依赖
- 在命令行下直接输入
make
编译生成的是终极目标 - 在命令行中输入
make 子目标
,此时只会执行子目标中的命令
。例如:上面我们随便定义一个hello子目标,也没有依赖,此时可以直接在命令行中输入make hello
,此时只会执行(编译)该子目标中的命令
。
8、声明伪目标
我们在执行make clean的时候并不会在当前目录下生成一个clean文件,当我们在当前目录创建一个叫clean名字的文件的时候,此时的clean文件就是最新的,当我们在去执行make clean的时候,就会提示clean是最新的
,因为子目标会的clean会与clean文件的时间做对比。解决方式就是不让其做对比,把clean子目标声明为一个伪目标
。
# 使用.PHONY:clean 把clean声明为一个伪目标
.PHONY:clean
clean:rm $(obj) $(target)
声明为伪目标之后,再做make clean的时候就不会再做更新比较了。
9、makefile的一些其他细节
命令执行失败,直接忽略
clean:mkdir /aa rm $(obj) $(target)
作为普通用户再根目录下创建mkdir /aa
一个文件肯定会失败,要先获取权限才可以。
解决方式,执行的命令前加-
,当命令执行失败之后会忽略,然后继续向下执行,如下:
clean:-mkdir /aa rm $(obj) $(target)
♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠
Makefile文件的编写规则相关推荐
- Makefile文件的编写
文章目录 前言 第一个最简单的 Makefile 文件举例 第二个Makefile示例 第三个Makefile示例 第四个Makefile示例 第五个Makefile示例 总结 前言 Makefile ...
- Linux平台Makefile文件的编写基础篇和GCC参数详解
问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...
- Makefile文件的编写(实例详解)
1.什么是Makefile? 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译 ...
- CUDA、MPI和SU混编,MakeFile文件的编写
本人研究地震勘探的全波形反演,最近在用CUDA+MPI加速反演过程. 写代码过程中最关键的是Makefile文件的编写,也是最难的.下面给出基于SU(Seismic Unix)的CUDA+MPI开发过 ...
- 解析Makefile文件的构建规则
2019独角兽企业重金招聘Python工程师标准>>> Makefile 编辑一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则 ...
- makefile文件的书写规则(make和makefile)
对于makefile,掌握一个规则,两个变量和三个函数.下面介绍一个规则. makefile的作用:一个项目代码的管理工具.当一个项目的代码文件数(如.c文件)太多,用gcc编译会太麻烦,如果全部文件 ...
- Makefile 文件的编写
学习前的准备 需要准备的工程目录结构如下: . ├── add │ ├── add_float.c │ ├── add.h │ └── add_int.c ├── main.c └── sub├── ...
- Linux下makefile文件的编写
在学习如何编写makefile文件之前,我们首先需要了解什么是makefile文件: makefile描述了整个工程的编译和链接等规则.它指明了哪些文件需要先编译,哪写文件需要后编译,哪些文件需要重新 ...
- Linux系统中编译大型C语言项目必备技能之:Makefile文件的编写
文章目录 Makefile的介绍 Makefile的编写规范--简单举例 Makefile的编写规范--复杂举例 项目描述 编译需求 编译思路 Makefile的介绍 我们在阅读一些大型的C语言项目时 ...
最新文章
- Intellij IDEA 2018.2 搭建Spring Boot 应用
- 电脑硬件知识学习_学习计算机基础必读的4本经典入门书籍,自学编程必备书单!...
- python计算最大回撤_Python进阶量化交易场外篇3——最大回撤评价策略风险
- python+Django学习资源汇总-更新中
- 自动行政审批流程组件的审批流程节点定义【民间称为工作流组件、官方称为审批流程组件】...
- java 在主方法中定义两个变量 调用方法进行加10_计算机考试二级考试Java模拟试题附答案...
- NLP简报(Issue#9)
- iOS地图之MapKit框架
- 业绩快报|Facebook Q4营收净利润亮眼,利好影响盘后股价大涨12%
- Kubernetes 一键部署实践
- java基础代码详解
- 学生计算机编程比赛获奖感言,学生比赛获奖感言4篇
- Docker Are you trying to connect to a TLS-enabled daemon without TLS?
- 低功耗蓝牙开发权威指南--第三部分 主机 (第9-12章)
- nginx反向代理文件下载失败
- Python环境搭建系列
- 一个程序员码农的迷茫期
- python股票交易编程最好的书_向大家介绍我的新书:《基于股票大数据分析的Python入门实战》...
- 专有网VPC---使用
- 2023年深圳CPDA数据分析师认证将于2/25正式开班,快来报名
热门文章
- sql server 用户'sa'登录失败(错误18456)
- relative和absolute的区别
- c# tcp备忘及networkstream.length此流不支持查找解决
- BZOJ-1027 [JSOI2007]合金
- 组装简历必备的9大要件
- 熟练掌握python是什么概念-想要熟练掌握Python元组?你需要了解这10件应知事项...
- 零基础入门学python 第二版-《零基础入门学习Python》第二版和第一版的区别在哪里呢?...
- python操作系统-Python操作系统
- python要自学多长时间-怎么自学python,大概要多久?
- python怎么导入包-python模块之导入包及模块发布