欢迎大家关注笔者,你的关注是我持续更博的最大动力

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文件的编写规则相关推荐

  1. Makefile文件的编写

    文章目录 前言 第一个最简单的 Makefile 文件举例 第二个Makefile示例 第三个Makefile示例 第四个Makefile示例 第五个Makefile示例 总结 前言 Makefile ...

  2. Linux平台Makefile文件的编写基础篇和GCC参数详解

    问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...

  3. Makefile文件的编写(实例详解)

    1.什么是Makefile? 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译 ...

  4. CUDA、MPI和SU混编,MakeFile文件的编写

    本人研究地震勘探的全波形反演,最近在用CUDA+MPI加速反演过程. 写代码过程中最关键的是Makefile文件的编写,也是最难的.下面给出基于SU(Seismic Unix)的CUDA+MPI开发过 ...

  5. 解析Makefile文件的构建规则

    2019独角兽企业重金招聘Python工程师标准>>> Makefile 编辑一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则 ...

  6. makefile文件的书写规则(make和makefile)

    对于makefile,掌握一个规则,两个变量和三个函数.下面介绍一个规则. makefile的作用:一个项目代码的管理工具.当一个项目的代码文件数(如.c文件)太多,用gcc编译会太麻烦,如果全部文件 ...

  7. Makefile 文件的编写

    学习前的准备 需要准备的工程目录结构如下: . ├── add │ ├── add_float.c │ ├── add.h │ └── add_int.c ├── main.c └── sub├── ...

  8. Linux下makefile文件的编写

    在学习如何编写makefile文件之前,我们首先需要了解什么是makefile文件: makefile描述了整个工程的编译和链接等规则.它指明了哪些文件需要先编译,哪写文件需要后编译,哪些文件需要重新 ...

  9. Linux系统中编译大型C语言项目必备技能之:Makefile文件的编写

    文章目录 Makefile的介绍 Makefile的编写规范--简单举例 Makefile的编写规范--复杂举例 项目描述 编译需求 编译思路 Makefile的介绍 我们在阅读一些大型的C语言项目时 ...

最新文章

  1. Intellij IDEA 2018.2 搭建Spring Boot 应用
  2. 电脑硬件知识学习_学习计算机基础必读的4本经典入门书籍,自学编程必备书单!...
  3. python计算最大回撤_Python进阶量化交易场外篇3——最大回撤评价策略风险
  4. python+Django学习资源汇总-更新中
  5. 自动行政审批流程组件的审批流程节点定义【民间称为工作流组件、官方称为审批流程组件】...
  6. java 在主方法中定义两个变量 调用方法进行加10_计算机考试二级考试Java模拟试题附答案...
  7. NLP简报(Issue#9)
  8. iOS地图之MapKit框架
  9. 业绩快报|Facebook Q4营收净利润亮眼,利好影响盘后股价大涨12%
  10. Kubernetes 一键部署实践
  11. java基础代码详解
  12. 学生计算机编程比赛获奖感言,学生比赛获奖感言4篇
  13. Docker Are you trying to connect to a TLS-enabled daemon without TLS?
  14. 低功耗蓝牙开发权威指南--第三部分 主机 (第9-12章)
  15. nginx反向代理文件下载失败
  16. Python环境搭建系列
  17. 一个程序员码农的迷茫期
  18. python股票交易编程最好的书_向大家介绍我的新书:《基于股票大数据分析的Python入门实战》...
  19. 专有网VPC---使用
  20. 2023年深圳CPDA数据分析师认证将于2/25正式开班,快来报名

热门文章

  1. sql server 用户'sa'登录失败(错误18456)
  2. relative和absolute的区别
  3. c# tcp备忘及networkstream.length此流不支持查找解决
  4. BZOJ-1027 [JSOI2007]合金
  5. 组装简历必备的9大要件
  6. 熟练掌握python是什么概念-想要熟练掌握Python元组?你需要了解这10件应知事项...
  7. 零基础入门学python 第二版-《零基础入门学习Python》第二版和第一版的区别在哪里呢?...
  8. python操作系统-Python操作系统
  9. python要自学多长时间-怎么自学python,大概要多久?
  10. python怎么导入包-python模块之导入包及模块发布