姓名:杨乔 学号:19020100280 学院:电子工程学院
转自:
https://max.book118.com/html/2016/1207/69449578.shtm
【嵌牛导读】嵌入式一般指嵌入式系统。嵌入式系统由硬件和软件组成。是能够独立进行运作的器件。Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布,它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。
【嵌牛鼻子】make 工程管理器
【嵌牛提问】make 工程管理器如何使用?
【嵌牛正文】
前面几节主要介绍如何在Linux环境下使用文本编辑器,如何使用GCC编译出可执行文件,以及如何使用GDB来调试程序。既然所有的工作都已经完成了,为什么还需要make这个工程管理器呢?
工程管理器可以用来管理较多的文件。读者可以试想一下:一个由上百个源文件构成的项目,如果其中只有一个或少数几个文件进行了修改,按照之前所学的 GCC 的用法,就不得不把所有的文件重新编译一遍。原因就在于编译器并不知道哪些文件是最近更新的,所以,程序员就不得不处理所有的文件来完成重新编译工作。
显然,开发人员需要一个能够自动识别出那些被更新的代码文件并实现整个工程自动编译的工具。
实际上,make就是一个自动编译管理器,能够根据文件时间戳自动发现更新过的文件从而减少编译的工作量。同时,它通过读入Makefile文件的内容来执行大量的编译工作,用户只需编写一次简单的编译语句即可。它大大提高了项目开发和维护的工作效率,几乎所有嵌入式Linux下的项目编程均会涉及make管理器,希望读者能够认真学习本节内容。
1.5.1 Makefile基本结构
Makefile用来告诉make如何编译和链接一个程序,它是make读入的唯一配置文件。本小节主要讲解Makefile的编写规则。在一个Makefile中通常包含如下内容。① 需要由 make 工具创建的目标体(target),目标体通常是目标文件、可执行文件或是一个标签。② 要创建的目标体所依赖的文件(dependency_file)。③ 创建每个目标体时需要运行的命令(command)。它的格式为target: dependency_filescommand例如,有两个文件分别为“hello.c”和“hello.h”,希望创建的目标体为“hello.o”,执行的命令为 GCC 编译指令“gcc –c hello.c”,那么,对应的 Makefile 就可以写为以下形式。#The simplest examplehello.o: hello.c hello.hgcc –c hello.c –o hello.o接着就可以使用make了。使用make的格式为“make target”,这样make就会自动读入Makefile (也可以是首字母小写makefile)执行对应target的command语句,并会找到相应的依赖文件,如下所示。[root@localhost makefile]# make hello.ogcc –c hello.c –o hello.o[root@localhost makefile]# lshello.c hello.h hello.o Makefile可以看到,Makefile执行了“hello.o”对应的命令语句,并生成了“hello.o”目标体。
在Makefile中的每一个command前必须有“Tab”符,否则在运行make命令时会出错。上面实例中的Makefile在实际中是几乎不存在的,因为它过于简单,仅包含两个文件和一个命令,在这种情况下完全不需要编写Makefile,只需在Shell中直接输入命令即可。在实际中使用的Makefile往往是包含很多命令的,一个项目也会包含多个Makefile。
下面就对较复杂的Makefile进行讲解。以下这个工程包含有3个头文件和8个C文件,其Makefile如下:
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.ogcc -o edit main.o kbd.o command.o display.o \insert.o search.o files.o utils.omain.o : main.c defs.hgcc -c main.c –o main.o
kbd.o : kbd.c defs.h command.hgcc -c kbd.c –o kbd.ocommand.o : command.c defs.h command.hgcc -c command.c –o command.odisplay.o : display.c defs.h buffer.hgcc -c display.c –o display.o
insert.o : insert.c defs.h buffer.hgcc -c insert.c –o insert.osearch.o : search.c defs.h buffer.hgcc -c search.c –o search.ofiles.o : files.c defs.h buffer.h command.hgcc -c files.c –o files.outils.o : utils.c defs.hgcc -c utils.c –o utils.oclean :rm edit main.o kbd.o command.o display.o \insert.o search.o files.o utils.o
这里的反斜杠“\”是换行符的意思,用于增加Makefile的可读性。读者可以把这些内容保存在文件名为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成可执行文件“edit”。如果想要删除可执行文件和所有的中间目标文件,只需要简单地执行一下“make clean”即可。
在这个“makefile”中,目标文件(target)包含以下内容:可执行文件“edit”和中间目标文件“*.o”,依赖文件(dependency_file)就是冒号后面的那些“*.c”文件和“*.h”文件。
每一个“.o”文件都有一组依赖文件,而这些“.o”文件又是可执行文件“edit”的依赖文件。依赖关系表明目标文件是由哪些文件生成的。换言之,目标文件是由哪些文件更新的。在定义好依赖关系后,后面的一行命令定义了如何生成目标文件。请读者注意,这些命令都是以一个“Tab”键作为开头的。
值得注意的是,make工程管理器并不关心命令是如何工作的,它只负责执行用户事先定义好的命令。同时,make还会比较目标文件和依赖文件的最后修改日期,如果依赖文件的日期比目标文件的日期新,或者目标文件并不存在,那么,make就会执行后续定义的命令。
这里要说明一点,clean不是一个文件,它只不过是一个动作名称,也可称其为标签,不依赖于其他任何文件。若用户想要执行其后的命令,就要在 make 命令后显式地指出这个标签的名字。这个方法非常有用,通常用户可以在一个Makefile中定义一些和编译无关的命令,比如程序的打包、备份或删除等。
1.5.2 Makefile变量
为了进一步简化Makefile的编写和维护,make允许在Makefile中创建和使用变量。变量是在Makefile中定义的名字,用来代替一个文本字符串,该文本字符串称为该变量的值。变量的值可以用来代替目标体、依赖文件、命令以及Makefile文件中的其他部分。在Makefile中的变量定义有两种方式:一种是递归展开方式,另一种是简单扩展方式。
递归展开方式定义的变量是在引用该变量时进行替换的,即如果该变量包含了对其他变量的引用,则在引用该变量时一次性将内嵌的变量全部展开。虽然这种类型的变量能够很好地完成用户的指令,但是它也有严重的缺点,如不能在变量后追加内容,因为语句“CFLAGS =$(CFLAGS)–O”在变量扩展过程中可能导致无穷循环。
为了避免上述问题,简单扩展型变量的值在定义处展开,并且只展开一次,因此它不包含任何对其他变量的引用,从而消除了变量的嵌套引用。递归展开方式的定义格式为VAR=var。简单扩展方式的定义格式为VAR:=var。Make中的变量使用格式为$(VAR)。
变量名是不包括“:”,“#”,“=”、结尾空格的任何字符串。同时,变量名中包含字母、数字以及下划线以外的情况应尽量避免,因为它们可能在将来被赋予特别的含义。变量名是大小写敏感的,例如变量名“foo”、“FOO”和“Foo”代表不同的变量。推荐在Makefile内部使用小写字母作为变量名,预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。
在上面的例子中,先来看看edit这个规则。edit : main.o kbd.o command.o display.o \insert.o search.o files.o utils.ogcc -o edit main.o kbd.o command.o display.o \insert.o search.o files.o utils.o
读者可以看到“.o”文件的字符串被重复了两次,如果在工程需要加入一个新的“.o”文件,那么用户需要在这两处分别加入(其实应该是有3处,另外一处在clean中)。当然,这个实例的Makefile并不复杂,所以在这两处分别添加也没有太多的工作量。但如果Makefile 变得复杂,用户就很有可能会忽略一个需要加入的地方,从而导致编译失败。所以,为了使Makefile易维护,推荐在Makefile中尽量使用变量这种形式。
这样,用户在这个实例中就可以按以下的方式来定义变量。OBJS = main.o kbd.o command.o display.o \insert.o search.o files.o utils.o这里是以递归展开的方式来进行定义的。在此之后,用户就可以很方便地在 Makefile 中以“$(objects)”的方式来使用这个变量了。