Makefile文件:Makefile介绍

本文介绍Makefile的一些基本概念以及简单的用法。本文所用的编译器是Hightec tricore v4.9.1.0。

1 Makefile的作用

简单来说,Makefile的作用是告诉make如何编译和链接程序。我们在Eclipse界面中写好代码后,会点击一下rebuild按钮来将工程重新编译和链接,这背后就是通过Makefile来实现的。本文会结合编译器的帮助文档make.pdf,并且自己编写Makefile,来学习Makefile的基本概念和用法。

2 Makefile的规则

Makefile的规则如下所示:
在这里插入图片描述
其中的含义如下:

  1. target是生成的文件的名称,可以是编译器生成的目标文件,或者链接器生成的可执行文件。另外也可以是执行的动作,例如clean;
  2. prerequisite是用于生成文件的输入,例如生成目标文件的输入是C文件和头文件,生成可执行文件的输入是目标文件;
  3. recipe是需要执行的动作,可以理解成命令。recipe前面要加上一个Tab制表符。

知道了以上规则,就可以写一个简单的Makefile了。

3 一个简单的Makefile

3.1 帮助文档中的例子

Hightec的帮助文档中举了个例子来演示Makefile,如下图所示。
在这里插入图片描述
该Makefile主要做了一下几件事:

  • 将8个源文件编译成目标文件;
  • 将8个目标文件链接成一个可执行文件edit
  • clean清除掉目标文件和可执行文件。

3.2 例1:一个简单的Makefile

帮助文档中只是个演示,并没有附带源文件供我们练习。因此博主自己写了简单的源文件头文件和Makefile,研究Makefile的执行过程和结果。另外,由于链接过程需要编写复杂的链接脚本,所以在下面的例子中只尝试编译的过程。

1)首先在同一个路径下建立三个文件:hello.c,hello.h,Makefile。
在这里插入图片描述
2)在hello.c中写入简单的变量和函数定义,如下所示。

/* hello.c */
#include "hello.h"

int a = 10;

int main(void)
{
	return 0;
}

在hello.h中写入对应的变量和函数声明,如下所示。

/* hello.h */
extern int a;
extern int main(void);

根据上文提到的规则,在Makefile中尝试写入编译hello.c的命令语句,如下所示。

hello.o : hello.c hello.h
	tricore-gcc -c hello.c
	
clean : 
	rm hello.o

Makefile中包含了两个功能:调用tricore-gcc把hello.c编译成hello.o,以及移除hello.o。

3)打开命令提示符,切换到这三个文件所在的路径。然后输入make并回车,如下图所示。
在这里插入图片描述
命令窗口会显示tricore-gcc -c hello.c这一行命令语句。然后回到文件夹路径下,看到成功生成了hello.o文件。
在这里插入图片描述
4)在窗口中输入make clean并回车,就会执行Makefile中的clean命令,如下图所示。
在这里插入图片描述
命令窗口会显示rm hello.o这一行命令语句。然后回到文件夹路径下,之前的hello.o文件就被移除了。clean的功能在软件编译的过程中很常用。在这里,clean不是一个目标文件,而是一个动作。clean的冒号后面没有跟其他的文件,因而被称为伪目标。

5)当路径下已经有了hello.o文件的时候,再去执行make命令会发生什么呢?尝试执行两次make命令,如下图所示。
在这里插入图片描述
第二次执行make命令的时候,编译器返回了"make: ‘hello.o’ is up to date"这句话,表示hello.o文件已经是最新的了。这里就要提到一个Makefile的机制,就是如果target文件(冒号前的文件)的时间晚于prerequisite文件(冒号后的文件)的时间,就表示输入文件没有被更新过,所以不会进行重新编译。
在这里插入图片描述

4 make是如何执行Makefile的

4.1 默认目标

默认情况下,make从第一个target开始,这个target被称为默认目标。

例如在3.1中所述的帮助文档中的例子。当我们敲下了make指令的时候,会从第一条规则开始,也就是重链接出edit文件。但是在链接之前,make必须首先处理edit文件所依赖的输入文件,也就是.o文件。所以make会先编译所有需要重新编译的源文件,直到.o文件齐全。这有点像是一个金字塔结构,底层的target完成以后才能做顶层的target。

clean伪目标是个例外,因为它不是edit所依赖的输入,需要使用make clean指令来处理clean。

4.2 例2:使用默认目标

把例1中的Makefile进行修改,在编译hello.c之前做一个默认目标project.elf,依赖于输入文件hello.o文件,如下。

project.elf : hello.o
	tricore-gcc -o project.elf hello.o

hello.o : hello.c hello.h
	tricore-gcc -c hello.c
	
clean : 
	rm project.elf hello.o

首先运行make clean,将当前路径的hello.o清除掉,只剩下hello.c,hello.h,Makefile三个文件。
在这里插入图片描述
然后,运行make。
在这里插入图片描述
在路径下就会生成project.elf和hello.o两个文件。
在这里插入图片描述
这个Makefile中就是以开头的project.elf作为默认目标。make先检测到默认目标所依赖的hello.o在当前路径中不存在,所以先去以hello.o为目标进行编译。编译完成后再以project.elf为目标去链接。

注意,这里的链接elf文件只是做一个演示,是为了说明默认目标的概念。实际上,链接过程非常复杂,不要被这个例子中的只言片语所误导。

5 使用变量让Makefile更简洁

5.1 变量的简单用法

在3.1帮助文档中的例子中,edit所依赖的.o文件有很多。如果Makefile中重复出现大量相同的字段,会很容易写错。这时就可以用一个变量来指代这一系列.o文件,如下图所示。
在这里插入图片描述
然后,在后文用到这一系列.o文件的地方,就可以用$(objects)来替换,如下图所示。
在这里插入图片描述

5.2 例3:在Makefile中使用变量

把例1中的Makefile进行修改,将hello.c和hello.h赋值给变量inputfile,然后再后面用到的地方换成$(inputfile),如下。

inputfile = hello.c hello.h
	
hello.o : $(inputfile)
	tricore-gcc -c hello.c
	
clean : 
	rm hello.o

然后打开命令行运行make,效果和例1相同,都能生成hello.o文件。

6 通过make推导规则

6.1 隐式规则

在Makefile文件中可以不用把编译的所有规则写出来,因为make中有个概念叫隐式规则,可以自动推导依赖关系。例如,在make看到了一个.o文件的时候,会自动推导它的源文件是同名的.c文件,就不需要把.c文件也写进去了。所以3.1 帮助文档中的例子也可以写成下面这样。
在这里插入图片描述
main.o文件后面就不再写上输入文件main.c了,下面的cc规则也省略了。

6.2 例4:省略源文件

将例1中的Makefile修改,冒号后面的输入文件不带hello.c了,只带一个hello.h,如下。

hello.o : hello.h
	tricore-gcc -c hello.c
	
clean : 
	rm project.elf hello.o

然后打开命令行,用make执行,效果和例1相同。

7 另一种风格的Makefile

由于有了Makefile的隐式规则,就可以不用把源文件清楚地写出来了。因此,诞生了另一种风格的Makefile,如下。
在这里插入图片描述
在编译规则中,冒号左边的目标是很多个.o文件,右边是头文件。这样的Makefile也是可以正确地执行的,但是依赖关系非常复杂,写的时候很容易出错。

8 清空路径的规则

上面的例子也说到,可以用make clean来清空路径下的文件。实际应用中最好按照以下方式来写clean。
在这里插入图片描述
这里包含了两个要素。首先,.PHONE表示clean是个伪目标,这样就不会把clean和名为clean的文件搞混淆。其次,在rm前面添加一个减号,表示即使rm出现错误也可以使make继续。

注意,诸如clean这样的规则不应放在makefile的开头,因为我们不希望它成为默认目标。

9 总结

本文学习了Makefile的基本概念,并且通过一些实例的操作,熟悉了Makefile的基本用法。

>>返回个人博客总目录

  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Makefile文件是一种文本文件,用于定义和管理软件项目的编译和构建过程。它包含了一系列规则和指令,用于告诉构建工具如何编译源代码、链接库文件以及生成可执行文件等。 下面是一个简单的Makefile文件的示例: ```makefile # 定义变量 CC = gcc CFLAGS = -Wall -g # 定义目标及其依赖关系和指令 myprogram: main.o func1.o func2.o $(CC) $(CFLAGS) -o myprogram main.o func1.o func2.o main.o: main.c $(CC) $(CFLAGS) -c main.c func1.o: func1.c $(CC) $(CFLAGS) -c func1.c func2.o: func2.c $(CC) $(CFLAGS) -c func2.c # 定义伪目标和指令 .PHONY: clean clean: rm -f myprogram *.o ``` Makefile文件由多个规则构成,每个规则包含目标、依赖关系和指令。以下是对Makefile文件中常见的语法元素的解析: - 变量定义:使用 `变量名 = 值` 的形式定义变量。在示例中,`CC` 定义了编译器命令,`CFLAGS` 定义了编译选项。 - 目标规则:目标规则指定了生成的目标文件及其依赖关系。示例中,`myprogram` 是最终生成的可执行文件,依赖于 `main.o`、`func1.o` 和 `func2.o` 这三个目标文件。 - 依赖规则:依赖规则指定了目标文件所依赖的源代码文件,并定义了生成目标文件的指令。示例中,`main.o` 依赖于 `main.c`,并使用指令 `$(CC) $(CFLAGS) -c main.c` 进行编译。 - 伪目标规则:伪目标规则指定了一些特殊的目标,如示例中的 `.PHONY: clean`。伪目标不代表真实的文件,而是定义了一系列指令,用于执行一些特定操作,如清理生成的文件等。 - 指令:每个规则中都包含了一组指令,用于构建目标文件。指令前面需要使用制表符或者多个空格进行缩进。 通过运行 `make` 命令,构建工具会读取Makefile文件并根据规则执行相应的操作,从而实现源代码的编译和构建过程。例如,在示例中运行 `make myprogram` 将会编译源代码并生成可执行文件 `myprogram`。运行 `make clean` 可以执行清理操作,删除生成的文件。 这只是一个简单的Makefile示例,实际项目中的Makefile可能更复杂,包含更多的规则和指令来管理更复杂的构建过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值