嵌入式软件开发培训笔记——Makefile编写

1makemakefile 概念和作用

在大型的开发项目中,通常有几十到上百个的源文件,如果每次均手工键入gcc命令进行编译的话,则会非常不方便。

利用make工具来自动完成编译工作,包括:a)如果仅修改了某几个源文件,则只重新编译这几个源文件;b)如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。make工具通过makefile文件来实现自动化编译。Make工具不仅应用于编程,也可以用于描述一些文件改变时,需要自动更新另一些文件的任务。

make机制的运行需要一个命令行程序make和一个名为makefileMakefile的文本文件。make是一个命令工具,具体来说是一个解释makefileMakefile中的指令的命令工具。

make程序执行时,若不通过“-f”选项明确指定,它会在当前目录下先搜索名为makefile的文件,若找不到,就查找名为Makefile的文件。按照传统,许多Linux选择文件名Makefile,这样的话,若Makefile所在目录下其他的文件名均为小写,则在显示该目录的文件列表时,Makefile会出现在第一个。(参数‘-f name’‘--file=name’

2)以下是一个简单的makefile使用示例:

程序功能:用户输入一个字符串,内有若干个字符,然后再输入一个字符,要求程序将字符串中的该字符删去,最后打印显示处理后的字符串。为演示make工具编译多个源程序文件的方法,将程序分为4个源文件:main.cf1.cf2.cf3.cf1.c实现字符串的输入;f2.c负责删除字符串中的某个特定字符(该字符由用户输入)f3.c输出处理后的字符串;main.c负责对各个程序模块的调用。源程序如下图:

嵌入式软件开发培训笔记——Makefile编写_第1张图片

嵌入式软件开发培训笔记——Makefile编写_第2张图片

嵌入式软件开发培训笔记——Makefile编写_第3张图片

嵌入式软件开发培训笔记——Makefile编写_第4张图片

为了使用make自动编译这些源文件,程序员需要编写make工具所需遵循的编译规则,即Makefile文件。Makefile文件内容如:

all: main.c foo1.c foo2.c foo3.c(冒号与main.c及各.c文件之间有空格)

gcc main.c foo1.c foo2.c foo3.c -o all

注意,4.c源程序文件及Makefile文件应存放在同一个目录下,当使用make进行自动编译时,它会在该目录下找到Makefile文件,并按照Makefile文件中的内容(编译规则的集合)进行自动编译。用make自动编译。在前面提及的目录下输入make命令,产生的输出结果如下:

嵌入式软件开发培训笔记——Makefile编写_第5张图片

Make命令后面带参数(-s cc=gcc all等等),其中cc=gcc属于外部全局变量赋值,在这里这个全局变量是一个命令行宏定义且具有最高优先级的,(命令行宏定义->makefile定义->shell定义->C文件中预定义)。

此外,该例使用另两种写法的makefilez<最好先看完步骤(3>

a) 嵌入式软件开发培训笔记——Makefile编写_第6张图片

b) 嵌入式软件开发培训笔记——Makefile编写_第7张图片

3)再通过一个示例讲解Makefile文件的书写规则,以及make命令如何遵循Makefile的内容来进行编译工作。事实上,我们可以把以下几个源代码文件想象成任何可行的代码。

嵌入式软件开发培训笔记——Makefile编写_第8张图片 

在前面所示的Makefile文件中,目标(target)包含以下内容:最终的可执行文件edit以及8个中间目标(*.o文件);依赖文件(prerequisites)即每个冒号后面的那些文件,每个.o文件都有一组依赖文件(.c文件和.h文件),而这些.o文件又是最终目标edit的依赖文件。注意:代表清除动作的目标clean(清除可执行文件及所有目标文件)没有依赖文件。

依赖关系的实质是说明目标文件由哪些文件生成,定义了依赖关系后,后续的代码定义了生成目标文件的有关命令(即生成目标的方法),注意这些命令一定要以一个Tab键作为它的开头。

make命令会比较target文件和prerequisites文件的修改日期,如果prerequisites文件的日期比target文件的日期要新,或者target不存在,make就会执行后续定义的命令。

嵌入式软件开发培训笔记——Makefile编写_第9张图片

make命令会比较target文件和prerequisites文件的修改日期,如果prerequisites文件的日期比target文件的日期要新,或者target不存在,make就会执行后续定义的命令。

显式规则:makefile的书写者显式地指出要生成的目标文件、目标文件的依赖文件以及生成目标文件的命令。

隐式规则:make有自动推导的功能,会选择一套默认的方法进行make,所以隐式的规则可以让开发者比较简略地书写Makefile,这是由make所支持的。

4)变量的定义:在Makefile中我们可以定义一系列的变量,变量的值一般都是字符串,像C语言中的宏,当Makefile被执行时,其中的变量就会被扩展到相应的引用位置上。

文件指示:makefile的书写者显式地指出要生成的目标文件、目标文件的依赖文件以及生成目标文件的命令。包括三个部分:

a)在一个Makefile中引用另一个Makefile,就像C语言中的#include一样包含进来;

b)根据某些情况指定Makefile中的有效部分,就像C语言中的预编译宏#ifdef一样;

c)定义一个多行的命令。

注释:Makefile中只有行注释,注释以“#”字符开头。

Makefile中的变量,就像是C/C++语言中的宏一样,代表文本字符串,在Makefile中执行的时候会自动原样地展开在所使用的地方。

其与C/C++的宏所不同的是可以在Makefile中改变其值。在Makefile中,变量可以使用在目标、依赖目标、命令或是Makefile的其它部分中。

变量的命名可以包含字符、数字、下划线(可以是数字开头),但不应该含有“:”“#”“=”或是空白字符(空格、回车等)

变量名对大小写敏感,传统的变量名是全大写的命名方式。

变量的定义格式

              变量名 赋值符号(可数字开头) 变量的值

赋值符号有三种:

(空格)=(空格)直接将后面的字符串赋给变量

(空格):= (空格)后面跟变量,将它的内容赋给变量

(空格)+=(空格)变量原来的值+空格+后面的字符串=>新的变量值。如:cc = gcc \ dd = arm \ cc += $(dd)

变量引用的三种格式:

 a)$(变量名)  b)${变量名} c)当变量名为单个字符时,可以省略括号

make处理变量时会扫描一遍整个Makefile,确定所有变量的值,因此变量的使用可以在定义之后,而且使用的是最后一次赋予的值。

例:      objects = program.o foo.o utils.o

program : $(objects)

           gcc -o program $(objects)

变量的定义可以出现在三个地方

makefile中定义;在make命令行中定义;使用shell环境中的定义。优先级:见(1

       5make有许多预定义的变量,这些变量具有特殊的含义,可在规则中直接使用。 重点掌握下表中红圈标注。

嵌入式软件开发培训笔记——Makefile编写_第10张图片

6)两个常用函数:

a)wildcard函数(通配符函数),其形式是:

         $(wildcard _pattern)

通过该函数可得到当前工作目录中满足_pattern模式的文件或目录名列表。如:

         SRCS:=$(wildcard *.c)

b) patsubst函数,格式为:

  $(patsubst , , )

查找中的单词(单词以空格“Tab”回车分隔)是否符合模式,若匹配的话,则以模式替换,可以包含通配符”%”,表示任意长度的字符串。若中也包含“%”,则其所代表的的即为中的那个“%”所代表的的字符串。如:

         OBJS:=$(patsubst %.c, %.o, x.c.c bar.c)

  函数返回结果为:x.c.o bar.o

例:srcs = $(wildcard *.c)            #所有.c文件

    dd = $(patsubst %.c, %.o, $(src))   #src.c文件生成.o文件

#其中%.c, %.o代表任意.c,.o文件;

嵌入式软件开发培训笔记——Makefile编写_第11张图片

7)伪目标.PHONY(见下例)

嵌入式软件开发培训笔记——Makefile编写_第12张图片

嵌入式软件开发培训笔记——Makefile编写_第13张图片

嵌入式软件开发培训笔记——Makefile编写_第14张图片

       注:行前加 ’-‘’@’;加 ’-’表示编译时即使该行有错误也会被忽略,加 ’@’表示编译时该行若有错误则只编译到该行就不再往下继续编译了。

你可能感兴趣的:(嵌入式linux操作系统的使用)