本文主要是介绍(第22章)LinuxC本质中Makefile基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 一、基本规则
- 1.多个.c和.h文件的eg
- 2.Makefile文件的规则
- (1)Makefile文件每条规则的格式
- (3)make 会自动选择那些受影响的源文件重新编译,不受影响的源文件则不重新编译
- (4)Makefile文件什么情况下更新?
- (5)Makefile文件的clean规则:-rm,@rm,第一条规则的目标(缺省目标)
- (a)把clean声明为伪目标:.PHONY clean
- (b)Makefile过程的两阶段
- (c)其他目标名字:all,install,clean,distclean
- 二、隐含规则和模式规则:Makefile灵活写法
- 1.将上面目标的所有依赖条件拆开写
- (1)make在内建的隐含规则数据库中查找适用的规则
- (c)%.o:%.c是一种特殊的规则,称为模式规则
- (2)以条件为中心,改写Makefile文件
- 三、变量
- 1.三种定义变量的运算符
- (1)=等号定义变量
- (2):=运算符,变量的定义
- (3)?=运算符
- (4)+=运算符
- 3.常见的特殊变量:$ @,$ <,$ ?,$ ^,
- 4.其他变量
- 四、自动处理头文件的依赖关系
- 1.gcc -M和gcc -MM
- 2.GNU Makefile文件的官方手册要求
- 五、常用的make命令行选项:-n,-C
一、基本规则
1.多个.c和.h文件的eg
(1)下面的代码由深度优先搜索解迷宫问题改写而成
- 我们把堆栈和迷宫的代码分别转移到模块 stack.c 和 maze.c 中, main.c 包含它们提供的头文件 stack.h 和 maze.h
- main.c文件
- main.h文件,在 main.h 中定义了一个类型和两个常量, main.c 、 stack.c 和 maze.c 都要用到这些定义,都要包含这个头文件
- stack.c文件,stack.h文件
- 堆栈中放 item_t 类型的数据的说明如下: tem_t 可以定义为任意类型,只要它能够通过函数的参数和返回值传递并且支持赋值操作就行。 这也是一种避免硬编码的策略,stack.c 中多次使用 item_t 类型,要改变它的定义只需改变 main.h 中的一行代码
- maze.c和maze.h文件
- maze.c 中定义了一个 maze 数组和一个 print_maze 函数,需要在头文件 maze.h 中声明,以便提供给 main.c 使用,注意 print_maze 的声明可以不加 extern ,而 maze 的声明必须加 extern
(2)编译方法1:
(3)编译方法2:
- 可见手动处理这些问题非常容易出错,那有没有自动的解决办法呢?
- 有,就是写一个 Makefile 文件和源代码放在同一个目录下
2.Makefile文件的规则
(1)Makefile文件每条规则的格式
- Makefile由一组规则(Rule) 组成,每条规则的格式是:
eg:
- main 是这条规则的目标(Target) , main.o 、 stack.o 和 maze.o 是这条规则的条件
(Prerequisite)。 - 目标和条件之间的关系是:欲更新目标,必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。
- 所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个Tab开头,注意不能是空格, Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab开头的命令, make 会创建一个Shell进程去执行它。
(2)对上面的eg的make执行步骤解释如下
(3)make 会自动选择那些受影响的源文件重新编译,不受影响的源文件则不重新编译
(4)Makefile文件什么情况下更新?
- 如果一条规则的目标属于以下情况之一,就称为需要更新,最好结合上面的eg去理解
(5)Makefile文件的clean规则:-rm,@rm,第一条规则的目标(缺省目标)
(a)把clean声明为伪目标:.PHONY clean
- 这里还有一个问题,如果当前目录下存在一个文件叫 clean 会怎么样呢?
(b)Makefile过程的两阶段
- gcc 处理一个C程序分为预处理和编译两个阶段,类似地, make 处理Makefile的过程也分为两个阶段:
(c)其他目标名字:all,install,clean,distclean
(d)建议使用Makefile做文件名
二、隐含规则和模式规则:Makefile灵活写法
1.将上面目标的所有依赖条件拆开写
- 现在可以把提出来的三条规则删去(红框),写成:
- 可是现在 main.o 、 stack.o 和 maze.o 这三个目标连编译命令都没有了,怎么编译的呢?试试看:
(1)make在内建的隐含规则数据库中查找适用的规则
解释说明如如下:
(a)CFLAGS, CPPFLAGS和TARGET_ARCH变量
(b)$@, $<变量
- $@ 和 $< 是两个特殊的变量, $@的取值为规则中的目标, $<的取值为规则中的第一个条件
(c)%.o:%.c是一种特殊的规则,称为模式规则
- %.o:%.c是一种特殊的规则,称为模式规则(Pattern Rule)
(d)对上述流程的总结
- 在我们的Makefile中以main.o为目标的规则都没有命令列表,所以make会查找隐含规则,发现隐含规则中有这样一条模式规则适用, main.o符合%.o的模式,现在%就代表main(称为main.o这个名字的Stem),再替换到%.c中就是main.c。所以这条模式规则相当于:
(2)以条件为中心,改写Makefile文件
三、变量
1.三种定义变量的运算符
(1)=等号定义变量
- 这种特性有好处也有坏处。好处是我们可以把变量的值推迟到后面定义
- 坏处,就是有可能写出无穷递归的定义,但是make有能力检测出这样的错误而不会陷入死循环
- eg
(2):=运算符,变量的定义
- 有时候我们希望make在遇到变量定义时立即展开,可以用:=运算符
- eg
如果把这两行倒过来,
那么当make读到y := $(x) bar时, x还没有定义,展开为空值,所以y的取值是 bar,注意bar前面有个空格。 - 一个变量的定义从=后面的第一个非空白字符开始(从$(x)的 $ 开始),包括后面的所有字符,直到注释或换行之前结束。 如果要定义一个变量的值是一个空格,可以这样
(3)?=运算符
(4)+=运算符
- +=运算符可以给变量追加值
- 如果变量还没有定义过就直接用+=赋值,那么+=相当于=
- eg
3.常见的特殊变量:$ @,$ <,$ ?,$ ^,
- 这些变量的特点是不需要给它们赋值,在不同的上下文中它们自动取不同的值。常用的特殊变量有:
- eg
4.其他变量
- 在上一节我们看到make的隐含规则数据库中用到了很多变量,有些变量没有定义(例如CFLAGS),有些变量定义了缺省值(例如CC)
- 我们写Makefile时可以重新定义这些变量的值,也可以在缺省值的基础上追加
四、自动处理头文件的依赖关系
1.gcc -M和gcc -MM
如Makefile文件这么写,找出依赖的头文件,这很容易出错
- 可以用gcc的-M选项自动生成目标文件和源文件的依赖关系;-M选项把stdio.h以及它所包含的系统头文件也找出来了
- 如果我们不需要输出系统头文件的依赖关系,可以用-MM选项
2.GNU Makefile文件的官方手册要求
- sources变量
- 注意,虽然在Makefile中这个命令写了四行,但其实是一条命令, make只创建一个Shell进程执行这条命令,这条命令分为5个子命令,用;号隔开, 并且为了美观,用续行符\拆成四行来写。
执行步骤为:
- 不管是Makefile本身还是被它包含的文件,只要有一个文件在make过程中被更新了, make就会重新读取整个Makefile以及被它包含的所有文件
五、常用的make命令行选项:-n,-C
这篇关于(第22章)LinuxC本质中Makefile基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!