Makefile入门-程序员宅基地

技术标签: Makefile  linux  后端  make  


Linux项目自动化构建工具-make/Makefile

  学会使用Makefile可以极大的提高了软件开发的效率,makefile的特色“自动化编译”,使得我们一旦写好makefile,只需要一个make命令,整个工程完全自动编译。同时是否会写makefile,也从一个侧面说明了一个人是否具备完成大型工程的能力。
  通过make命令,与makefile文件,两个搭配使用,完成项目自动化构建。
  讲是这么讲,makefile到底怎么就提高了我们软件开发的效率呢?
  先来看一看如果没有makefile我们编写程序到底会多麻烦
  我们有两个简单的文件,其实现如下图所示

在这里插入图片描述  现在我们要制作一个属于自己的MyMath库,并将其发布,如果没有makefile我们要怎么做?

    gcc -c my_add.c my_sub.c                      //生成可重定位二进制文件
    ar -rc libMyMath.a my_add.o my_sub.o         //生成库文件
    mkdir -p mylib/include                      //创建目录结构
    mkdir -p mylib/lib                         //创建目录结构
    cp -rf *.h mylib/include/                 //拷贝文件到对应目录
    cp -rf *.a mylib/lib/                    //拷贝文件到对应目录
    tar czf mylib.tgz mylib                 //打包

最终结果如下:
在这里插入图片描述  现在我们有了makefile就可以大大提高工作效率
在这里插入图片描述  我们在命令行运行makefile生成目标文件,make output发布我们自己的库,make clean清理文件。
在这里插入图片描述
  现在知道为什么说makefile可以极大提高开发效率了吧。
  现在我们就来正式学习如何使用makefile吧。


语法规则

目标文件:依赖文件列表  
	依赖方法    #注意依赖方法前面要有一个TAB键

  1.目标文件:我们要生成的文件。
  2.依赖文件列表:简单来讲就是目标文件需要哪些文件用来生成目标文件。
  3.依赖方法:就是目标文件如何用依赖文件列表中的文件来生成目标文件。


make/Makefile工作原理

  make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么:

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),并把这个文件识别为 终极目标
  3. 根据目标文件是否存在以及目标文件所依赖文件ACM时间来决定是否会生成目标文件。
  4. 如果目标文件的依赖文件同时也依赖其他文件生成,make就会解决目标文件依赖文件的依赖关系,这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  5. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  6. make只管文件的依赖性即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就挂掉了。

目标文件生成规则

终极目标

  对于我们的makefile可能其目的是要生成多个目标文件,但是makefile会默认从上向下扫描文件,并且把识别到的第一个文件识别为终极目标文件,且只会生成这个终极目标文件。
  如下:
 在此文件中有两个目标文件,我们运行make
在这里插入图片描述MAKE:
 如我们所预料,只生成了一个目标文件,如何生成所有目标文件呢,接着往下看
在这里插入图片描述  我们可以通过all 指定所需要生成的目标文件

在这里插入图片描述

MAKE:
在这里插入图片描述  如上图所示,存在回显问题,如果想要取消回显,可在makefile文件中在指令前面加@
在这里插入图片描述

MAKE:
在这里插入图片描述

ACM时间

  对于我们多次运行make生成目标文件,会发生什么?
  它会告知我们目标文件已经存在。
在这里插入图片描述
  如果我们touch更新目标文件时间呢?
  文件重新生成。
在这里插入图片描述  结论:当我们已经存在该目标文件时,make后目标文件是否会重新生成取决于该目标文件所依赖文件的ACM时间(严格来讲是M时间)
  那到底什么是ACM时间呢?
  1.A(access时间):即文件最后一次访问时间,对于我们频繁访问某一文件,并不是每一次访问都会更新该文件的A时间,在我们访问该文件后短时间内再次访问并不会更新A时间。
  2.C(change时间):即文件最后一次属性修改时间(一个文件由内容与属性所构成)
  3.M(modify时间):即文件最后一次内容修改时间。(修改文件内容必定引起AC时间改变)
  我们可以通过stat指令查看文件的ACM时间。
在这里插入图片描述


变量赋值

以下用A B C代指某些文件例如main.c文件或指令例如gcc main.c

直接赋值

  直接赋值是最简单的方式,只需要使用 = 符号。这种方式定义的变量被称为递归扩展变量,其值为整个Makefile中最后被指定的值。

VARIABLE_A=A
VARIABLE_B=$(VARIABLE_A) B   #$(VARIABLE_A)表示取VARIABLE_A值
VARIABLE_A=AA

  最后VARIABLE_B的值为AA B

立即赋值

  使用 := 符号进行赋值会立即扩展变量的值,这种方式定义的变量被称为简单扩展变量.

SIMPLE_VARIABLE := $(ANOTHER_VARIABLE)

  在这个例子中,SIMPLE_VARIABLE 会立即被赋值为 ANOTHER_VARIABLE 的值。如果 ANOTHER_VARIABLE 在后面被改变,SIMPLE_VARIABLE 的值不会受到影响。

条件赋值

  你可以使用条件语句来为变量赋值,例如:

ifeq ($(DEBUG),1)  #ifeq 是条件指令,用于比较两个参数是否相等
    DEBUG_FLAGS = A

else  

    DEBUG_FLAGS = B

endif

  在这个例子中,DEBUG_FLAGS 会根据 DEBUG 变量的值被赋予不同的值。
  ?=赋值

MY_VARIABLE?=default_value

  在这个例子中,如果 MY_VARIABLE 在这个 Makefile 或任何包含它的 Makefile 中之前没有被设置过值,那么它就会被设置为 default_value。但是,如果 MY_VARIABLE 在这之前已经被设置过了,那么它就不会被 default_value 覆盖。

追加赋值

  使用 += 符号可以将值追加到变量的现有值上。

OBJECTS = A B  

OBJECTS += C

  在这个例子中,OBJECTS 变量最初包含 A 和B,然后C被追加到它的值上。

使用环境变量

  Makefile 中的变量也可以从环境变量中继承。如果你想在 Makefile 中使用环境变量的值,你可以直接引用它。

CC = $(CC_ENV)

  在这个例子中,如果环境变量 CC_ENV 存在,它将被赋值给 CC 变量。


特殊变量

$@ #表示目标文件
$^ #表示依赖文件列表
&< #表示依次取依赖文件列表文件生成对应目标文件

使用变量

$符号表示取变量的值,当变量名多于一个字符时,使用"( )"


伪目标 .PHONY

  伪目标是一个特殊的目标,它不代表一个真实的文件。形象的来讲它只是一个标签,用于执行与该目标关联的命令。因为伪目标不代表任何文件,所以make工具不会检查文件系统来确定该目标是否已经是最新的。这意味着,无论何时你尝试构建这个伪目标,与其关联的命令都会被执行。
  假设当前目录下存在一个名为clean的文件和一个Makefile文件,Makefile文件内容如下:

clean:
	rm temp

  当我们执行make clean命令后,目标clean并不会被执行,因为make会首先查找名为clean的文件,而不是将clean作为目标来执行,又因为我们不会生成新的clean文件,所以使得clean文件的ACM时间一直被判定为最新时间,导致不会执行clean,为了解决这个问题,可以在Makefile文件中将clean声明为伪目标,修改后的Makefile文件内容如下:

.PHONY: clean
clean:
	rm temp

  再次执行make clean命令后,伪目标clean就会被执行,从而删除temp文件或目录(如果存在的话)。
  伪目标用途:伪目标在Makefile中的作用主要是用来定义一些不代表实际文件的目标,这些目标通常用于执行一些额外的操作,比如清理临时文件、生成文档、运行测试等。使用伪目标可以将这些操作集中到一个目标中,方便管理。同时,伪目标还可以用来定义一些常用的操作,比如编译、运行、安装等,以及定义依赖关系,确保目标的正确顺序。


嵌套执行Makefile

  嵌套 Makefile 是指在一个 Makefile 中包含另一个 Makefile。这种技术常用于大型项目中,将项目划分为多个子目录或子模块,每个子目录或子模块都有自己的 Makefile,然后在主 Makefile 中包含这些子 Makefile。
  现在有以下结构:
在这里插入图片描述  主makefile文件内容如下:
嵌套执行makefile语法规则:
在主makefile中,执行

make -C  路径

在这里插入图片描述

  两个子makefile文件内容如下(两个子makefile内容相同):
在这里插入图片描述

MAKE:
在这里插入图片描述
MAKE CLEAN:
在这里插入图片描述


本章到此结束,感谢阅读!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yuehuazyc/article/details/137091015

智能推荐

python编码问题之encode、decode、codecs模块_python中encode在什么模块-程序员宅基地

文章浏览阅读2.1k次。原文链接先说说编解码问题编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 Eg:str1.decode('gb2312') #将gb2312编码的字符串转换成unicode编码str2.encode('gb2312') #将unicode编码..._python中encode在什么模块

Java数据流-程序员宅基地

文章浏览阅读949次,点赞21次,收藏15次。本文介绍了Java中的数据输入流(DataInputStream)和数据输出流(DataOutputStream)的使用方法。

ie浏览器无法兼容的问题汇总_ie 浏览器 newdate-程序员宅基地

文章浏览阅读111次。ie无法兼容_ie 浏览器 newdate

想用K8s,还得先会Docker吗?其实完全没必要-程序员宅基地

文章浏览阅读239次。这篇文章把 Docker 和 K8s 的关系给大家做了一个解答,希望还在迟疑自己现有的知识储备能不能直接学 K8s 的,赶紧行动起来,K8s 是典型的入门有点难,后面越用越香。

ADI中文手册获取方法_adi 如何查看数据手册-程序员宅基地

文章浏览阅读561次。ADI中文手册获取方法_adi 如何查看数据手册

React 分页-程序员宅基地

文章浏览阅读1k次,点赞4次,收藏3次。React 获取接口数据实现分页效果以拼多多接口为例实现思路加载前 加载动画加载后 判断有内容的时候 无内容的时候用到的知识点1、动画效果(用在加载前,加载之后就隐藏或关闭,用开关效果即可)2、axios请求3、map渲染页面4、分页插件(antd)代码实现import React, { Component } from 'react';//引入axiosimport axios from 'axios';//引入antd插件import { Pagination }_react 分页

随便推点

关于使用CryPtopp库进行RSA签名与验签的一些说明_cryptopp 签名-程序员宅基地

文章浏览阅读449次,点赞9次,收藏7次。这个变量与验签过程中的SignatureVerificationFilter::PUT_MESSAGE这个宏是对应的,SignatureVerificationFilter::PUT_MESSAGE,如果在签名过程中putMessage设置为true,则在验签过程中需要添加SignatureVerificationFilter::PUT_MESSAGE。项目中使用到了CryPtopp库进行RSA签名与验签,但是在使用过程中反复提示无效的数字签名。否则就会出现文章开头出现的数字签名无效。_cryptopp 签名

新闻稿的写作格式_新闻稿时间应该放在什么位置-程序员宅基地

文章浏览阅读848次。新闻稿是新闻从业者经常使用的一种文体,它的格式与内容都有着一定的规范。本文将从新闻稿的格式和范文两个方面进行介绍,以帮助读者更好地了解新闻稿的写作_新闻稿时间应该放在什么位置

Java中的转换器设计模式_java转换器模式-程序员宅基地

文章浏览阅读1.7k次。Java中的转换器设计模式 在这篇文章中,我们将讨论 Java / J2EE项目中最常用的 Converter Design Pattern。由于Java8 功能不仅提供了相应类型之间的通用双向转换方式,而且还提供了转换相同类型对象集合的常用方法,从而将样板代码减少到绝对最小值。我们使用Java8 功能编写了..._java转换器模式

应用k8s入门-程序员宅基地

文章浏览阅读150次。1,kubectl run创建pods[root@master ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1[root@master ~]# kubectl get podsNAME READY STATUS REST...

PAT菜鸡进化史_乙级_1003_1003 pat乙级 最优-程序员宅基地

文章浏览阅读128次。PAT菜鸡进化史_乙级_1003“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。得到“答案正确”的条件是: 1. 字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符; 2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或..._1003 pat乙级 最优

CH340与Android串口通信_340串口小板 安卓给安卓发指令-程序员宅基地

文章浏览阅读5.6k次。CH340与Android串口通信为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio移植的具体步骤CH340串口通信驱动函数通信过程中重难点还存在的问题为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio为了在这个工程基础上进行改动,验证串口的数据和配置串口的参数,我首先在Eclipse上配置了安卓开发环境,注意在配置环境是..._340串口小板 安卓给安卓发指令