C语言makefile文件详解,makefile讲解

仅供自己学习使用

一、Makefile介绍

Makefile 或 makefile: 告诉make维护一个大型程序, 该做什么。Makefile说明了组成程序的各模块间的相互 关系及更新模块时必须进行的动作, make按照这些说明自动地维护这些模块。

执行make命令时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。 Makefile是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件。这些规则主要是描述哪些文件(称为target目标文件,不要和编译时产生的目标文件相混淆)是从哪些别的文件(称为dependency依赖文件)中产生的,以及用什么命令(command)来执行这个过程。

二、Makefile里包含什么?

Makefile里主要包含了五个部分内容:显式规则、隐式规则、变量定义、文件指示和注释。

1、显式规则。显式规则说明了如何生成一个或多个目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。

2、隐晦规则。由于make有自动推导的功能,所以隐式规则可以让我们比较粗糙地简略地书写Makefile,这是由make支持的。

3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上

4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样。

5、注释。和UNIX的Shell脚本一样Makefile中只有行注释, 其注释是用“#”字符,这个就像C/C++中的“//”或者“ /*”。

在Makefile中的命令,必须要以[Tab]键开始!!!

Makefile的默认文件名为GNUmakefile、makefile或Makefile,多数Linux程序员使用第三种。 执行make命令时,会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间至少比它的一个依赖文件还旧的话,make就执行相应的命令,以更新目标文件。目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。

引用其它的Makefile

Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。

include的语法是:

include 

filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符)

Make支持三种通配符: “*”、“?”、“[…]”

include foo.make *.mk $(bar)等价于: include foo.make a.mk b.mk c.mk e.mk f.mk

三、Makefile的规则

Makefile文件主要含有一系列的规则,每条规则包含以下内容:

一个目标(target),即make最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“clean”。

一个或多个依赖文件(dependency)列表,通常是编译目标文件所需要的其他文件。

一系列命今(command),是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为TAB字符。

例如,有以下的Makefile文件:

# 一个简单的Makefile的例子

# 以#开头的为注释行

test:prog.o code.o

gcc –o test prog.o code.o

prog.o:prog.c prog.h code.h

gcc –c prog.c –o prog.o

code.o:code.c code.h

gcc –c code.c –o code.o

clean:

rm –f *.o

上面的Makefile文件中共定义了四个目标:test、prog.o、code.o和clean。目标从每行的最左边开始写,后面跟一个冒号(:),如果有与这个目标有依赖性的其他目标或文件,把它们列在冒号后面,并以空格隔开。然后另起一行开始写实现这个目标的一组命令。在Makefile中,可使用续行号(\)将一个单独的命令行延续成几行。但要注意在续行号(\)后面不能跟任何字符(包括空格和键)。

一般情况下,调用make命令可输入:

# make target

target是Makefile文件中定义的目标之一,如果省略target,make就将生成Makefile文件中定义的第一个目标。对于上面Makefile的例子,单独的一个“make”命令等价于:

# make test

因为test是Makefile文件中定义的第一个目标,,所有make首先将其读入,然后从第一行开始执行,把第一个目标test作为它的最终目标后面的目标的更新都会影响到test的更新。第一条规则说明只要文件test的时间戳比文件prog.o或code.o中的任何一个旧,下一行的编译命令将会被执行。

但是,在检查文件prog.o和code.o的时间戳之前,make会在下面的行中寻找以prog.o和code.o为目标的规则,在第三行中找到了关于prog.o的规则,该文件的依赖文件是prog.c、prog.h和code.h。同样,make会在后面的规则行中继续查找这些依赖文件的规则,如果找不到,则开始检查这些依赖文件的时间戳,如果这些文件中任何一个的时间戳比prog.o的新,make将执行“gcc –c prog.c –o prog.o”命令,更新prog.o文件。

以同样的方法,接下来对文件code.o做类似 的检查,依赖文件是code.c和code.h。当make执行完所有这些套嵌的规则后,make将处理最顶层的test规则。如果关于prog.o和code.o的两个规则中的任何一个被执行,至少其中一个.o目标文件就会比test新,那么就要执行test规则中的命令,因此make去执行gcc命令将prog.o和code.o连接成目标文件test。 在上面Makefile的例子中,还定义了一个目标clean,它是Makefile中常用的一种专用目标,即删除所有的目标模块。

现在来看一下make做的工作:

首先make按顺序读取makefile中的规则,然后检查该规则中的依赖文件与目标文件的时间戳哪个更新,如果目标文件的时问戳比依赖文件还早,就按规则中定义的命令更新目标文件。如果该规则中的依赖文件又是其他规则中的目标文件,那么依照规则链不断执行这个过程,直到Makefile文件的结束,至少可以找到一个不是规则生成的最终依赖文件,获得此文件的时间戳,然后从下到上依照规则链执行目标文件的时间戳比此文件时间戳旧的规则,直到最顶层的规则。

四、Makefile中的变量

Makefile里的变量就像一个环境变量。事实上,环境变量在make中也被解释成make的变量。这些变量对大小写敏感,一般使用大写宇母。几乎可以从任何地方引用定义的变量,变量的主要作用如下:

保存文件名列表。在前面的例子里,作为依赖文件的一些目标文件名出现在可执行文件的规则中,而在这个规则的命令行里同样包含这些文件并传递给gcc做为命令参数。如果使用一个变量来保存所有的目标文件名,则可以方便地加入新的目标文件而且不易出错。

保存可执行命令名,如编译器。在不同的Linux系统中存在着很多相似的编译器系统,这些系统在某些地方会有细微的差别,如果项目被用在一个非gcc的系统里,则必须将所有出现编译器名的地方改成用新的编译器名,比如编译器的版本不同,arm-linux 3.4.1、4.3.2等。如果使用一个变量来代替编译器名,那么只需要改变该变量的值。其他所有地方的命令名就都改变了。

保存编译器的参数。在很多源代码编译时,gcc需要很长的参数选项,在很多情况下,所有的编译命令使用一组相同的选项,如果把这组选项使用一个变量代表,那么可以把这个变量放在所有引用编译器的地方。当要改变选项的时候,只需改变一次这个变量的内容即可。

五、定义变量

Makefile中的变量是用一个文本串在Makefile中定义的,这个文本串就是变量的值。只要在一行的开始写下这个变量的名字,后面跟一个“=”号,以及要设定这个变量的值即可定义变量,下面是定义变量的语法:

VARNAME=string

使用时,把变量用括号括起来,并在前面加上$符号,就可以引用变量的值: ${VARNAME}

make解释规则时,VARNAME在等式右端展开为定义它的字符串。变量一般都在Makefile的头部定义。按照惯例,所有的Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile的维护。

现在利用变量把前面的Makefile重写一遍:

OBJS=prog.o code.o

CC=gcc

test:${ OBJS }

${ CC } –o test ${ OBJS }

prog.o:prog.c prog.h code.h

${ CC } –c prog.c –o prog.o

code.o:code.c code.h

${ CC } –c code.c –o code.o

clean: rm –f *.o

如:源程序为

2c4edf657b46d8a6bcf65497152385f8.png

经过变量替换过后的makefile文件:

501695ad36d1f74a8ad78eee2eac8a26.png

六、Makefile的隐含规则

在上面的例子中,几个产生目标文件的命令都是从“.c”的C语言源文件和相关文件通过编译产生“.o”目标文件,这也是一般的步骤。实际上,make可以使工作更加自动化,也就是说,make知道一些默认的动作,它有一些称作隐含规则的内置的规则,这些规则告诉make当用户没有完整地给出某些命令的时候,应该怎样执行。

例如,把生成prog.o和code.o的命令从规则中删除,make将会查找隐含规则,然后会找到并执行一个适当的命令。由于这些命令会使用一些变量,因此可以通过改变这些变量来定制make。象在前面的例子中所定义的那样,make使用变量CC来定义编译器,并且传递变量CFLAGS(编译器参数)、CPPFLAGS(C语言预处理器参数)、TARGET_ARCH(目标机器的结构定义)给编译器,然后加上参数-c,后面跟变量$

$ {CC} $ {CFLAGS} $ {CPPFLAGS} $ {TARGET_ARCH} –c $< -o $@

09d93b534247088b6cf490856719dfab.png

在上面的例子中,利用隐含规则,可以简化为:

OBJS=prog.o code.o

CC=gcc

test:${ OBJS }

${ CC } –o $@ $^

prog.o:prog.c prog.h code.h

code.o:code.c code.h

clean: rm –f *.o

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/471375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二、MySQL连接查询学习笔记(多表连接查询:内连接,外连接,交叉连接详解)

MySQL连接查询&#xff08;多表连接查询&#xff1a;内连接&#xff0c;外连接&#xff0c;交叉连接详解&#xff09; 6&#xff1a;多表连接查询 笛卡尔乘积&#xff1a;如果连接条件省略或无效则会出现 解决办法&#xff1a;添加上连接条件连接查询的分类&#xff1a; 1.按…

android 本机号码一键登录,什么是本机号码一键登录?APP本机号码一键登录如何实现?...

三大运营商推出一键登录的服务后&#xff0c;由于其便捷性和安全性都好于传统短信验证码&#xff0c;越来越多的APP注册登录环节都在使用本机号码一键登录验证方式。本文主要介绍了本机号码一键登录特点以及实现方法。一、什么是本机号码一键登录&#xff1f;平时我们填手机号接…

LeetCode 2116. 判断一个括号字符串是否有效(栈)

文章目录1. 题目2. 解题1. 题目 一个括号字符串是只由 ( 和 ) 组成的 非空 字符串。 如果一个字符串满足下面 任意 一个条件&#xff0c;那么它就是有效的&#xff1a; 字符串为 ().它可以表示为 AB&#xff08;A 与 B 连接&#xff09;&#xff0c;其中A 和 B 都是有效括号字…

NavigationController

前面的一篇文章《iOS开发16&#xff1a;使用Navigation Controller切换视图》中的小例子在运行时&#xff0c;屏幕上方出现的工具栏就是Navigation Bar&#xff0c;而所谓UINavigationItem就可以理解为Navigation Bar中的内容&#xff0c;通过编辑UINavigationItem&#xff0c;…

android studio windows,AndroidStudio的使用(Windows)

演示模式View---Enter presentation mode演示代码快捷提示commondshfita最近修改的文件ctrlshfite代码书签在一行代码处使用F11也可以在navigate--bootmarkPaste_Image.png回退到上一个浏览的地方ctrlaltleft/right快速进入方法内ctrlb查看方法的参数定义commondpPaste_Image.p…

LeetCode 2119. 反转两次的数字

文章目录1. 题目2. 解题1. 题目 反转 一个整数意味着倒置它的所有位。 例如&#xff0c;反转 2021 得到 1202 。反转 12300 得到 321 &#xff0c;不保留前导零 。 给你一个整数 num &#xff0c;反转 num 得到 reversed1 &#xff0c;接着反转 reversed1 得到 reversed2 。 …

三、MySQL子查询学习笔记(标量子查询、列子查询、行子查询、表子查询 详解)

三、MySQL子查询学习笔记 7&#xff1a;子查询 含义&#xff1a; 一条查询语句中又嵌套了另一条完整的select语句&#xff0c;其中被嵌套的select语句&#xff0c;称为子查询或内查询&#xff1b;在外面的查询语句&#xff0c;称为主查询或外查询 分类&#xff1a; 一、按子查…

LeetCode 2120. 执行所有后缀指令(模拟)

文章目录1. 题目2. 解题1. 题目 现有一个 n x n 大小的网格&#xff0c;左上角单元格坐标 (0, 0) &#xff0c;右下角单元格坐标 (n - 1, n - 1) 。 给你整数 n 和一个整数数组 startPos &#xff0c;其中 startPos [startrow, startcol] 表示机器人最开始在坐标为 (startrow…

android代理生命周期,了解 Activity 生命周期

当用户浏览、退出和返回到您的应用时&#xff0c;您应用中的在生命周期回调方法中&#xff0c;您可以声明用户离开和再次进入 Activity 时 Activity 的行为方式。例如&#xff0c;如果您正构建流媒体视频播放器&#xff0c;当用户切换至另一应用时&#xff0c;您可能要暂停视频…

LeetCode 2121. 相同元素的间隔之和(前缀和)

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始、由 n 个整数组成的数组 arr 。 arr 中两个元素的 间隔 定义为它们下标之间的 绝对差 。更正式地&#xff0c;arr[i] 和 arr[j] 之间的间隔是 |i - j| 。 返回一个长度为 n 的数组 intervals &#xff0c;其中 interva…

在android添加数据采集,一种基于Android系统的地理信息数据采集方法与流程

本方法属于采集地理信息数据的发明&#xff0c;是一种基于android操作系统和gis地理信息系统进行户外地理信息数据采集的方法。背景技术&#xff1a;众所周知地理信息数据采集在很多行业中都有应用&#xff0c;比如说农业中的土地普查、城市管理中的地下管线普查、工业中的地质…

LeetCode 2124. 检查是否所有 A 都在 B 之前

文章目录1. 题目2. 解题1. 题目 给你一个 仅 由字符 a 和 b 组成的字符串 s 。 如果字符串中 每个 ‘a’ 都出现在 每个 ‘b’ 之前&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;s "aaabbb" 输出&#x…

设计模式—桥接模式

前言 这里以电视遥控器为例子引出桥接模式&#xff0c;首先每个牌子的电视都有一个遥控器&#xff0c;可以设计吧遥控器作为一个抽象类&#xff0c;抽象类中提供遥控器的所有实现&#xff0c;其他具体电视品牌的遥控器都继承这个抽象类 这样的实现使得每个不同型号的电视都有自…

LeetCode 2125. 银行中的激光束数量

文章目录1. 题目2. 解题1. 题目 银行内部的防盗安全装置已经激活。 给你一个下标从 0 开始的二进制字符串数组 bank &#xff0c;表示银行的平面图&#xff0c;这是一个大小为 m x n 的二维矩阵。 bank[i] 表示第 i 行的设备分布&#xff0c;由若干 ‘0’ 和若干 ‘1’ 组成。…

LeetCode 2126. 摧毁小行星(贪心)

文章目录1. 题目2. 解题1. 题目 给你一个整数 mass &#xff0c;它表示一颗行星的初始质量。 再给你一个整数数组 asteroids &#xff0c;其中 asteroids[i] 是第 i 颗小行星的质量。 你可以按 任意顺序 重新安排小行星的顺序&#xff0c;然后让行星跟它们发生碰撞。如果行星…

bzoj:2018 [Usaco2009 Nov]农场技艺大赛

Description Input 第1行&#xff1a;10个空格分开的整数: N, a, b, c, d, e, f, g, h, M Output 第1行&#xff1a;满足总重量最轻&#xff0c;且用度之和最大的N头奶牛的总体重模M后的余数。 Sample Input 2 0 1 5 55555555 0 1 0 55555555 55555555Sample Output 51HINT 样例…

LeetCode 2129. 将标题首字母大写

文章目录1. 题目2. 解题1. 题目 给你一个字符串 title &#xff0c;它由单个空格连接一个或多个单词组成&#xff0c;每个单词都只包含英文字母。请你按以下规则将每个单词的首字母 大写 &#xff1a; 如果单词的长度为 1 或者 2 &#xff0c;所有字母变成小写。否则&#xf…

LeetCode 2130. 链表最大孪生和(链表快慢指针+反转链表+双指针)

文章目录1. 题目2. 解题1. 题目 在一个大小为 n 且 n 为 偶数 的链表中&#xff0c;对于 0 < i < (n / 2) - 1 的 i &#xff0c;第 i 个节点&#xff08;下标从 0 开始&#xff09;的孪生节点为第 (n-1-i) 个节点 。 比方说&#xff0c;n 4 那么节点 0 是节点 3 的孪…

Splay初步【bzoj1503】

做了一道水题&#xff0c;把bzoj1503用Splay重新写了一下。 1 #include <bits/stdc.h>2 #define rep(i, a, b) for (int i a; i < b; i)3 #define REP(i, a, b) for (int i a; i < b; i)4 #define drep(i, a, b) for (int i a; i > b; i--)5 #define mp make…

原生html5时间组件,JFinal遇到了原生Html5时间组件格式转换问题怎么处理?

今天JBolt种子用户群里有人提问&#xff0c;JFinal针对原生Html5的日期时间选择组件的格式转换支持有问题&#xff0c;报错。于是我在JBolt的Demo中加入了这些去测试一下&#xff0c;这里使用的都是原生Html组件。Input type“text”默认就是一个简单的单行文本输入框。如果修改…