神秘的Makefile(原创)

您所在的位置:网站首页 makefile输出信息 神秘的Makefile(原创)

神秘的Makefile(原创)

#神秘的Makefile(原创)| 来源: 网络整理| 查看: 265

神秘的Makefile

我想,咱们学习和从事嵌入式系统设计的,对于Linux和GCC都应该不陌生吧!Linux和GCC工具的强大也是大家所有目共睹的,它们对嵌入式系统设计的发展起着关键性的作用,是目前用的最多的嵌入式操作系统和嵌入式软件开发工具,它们二者都是基于GNU和GPL的,可以免费获得源代码和使用。下面,我就自己这一年多来学习Linux和GCC的一些经验总结和学习感悟与大家分享。

在本文中,我先给大家介绍一下GCC工具的使用,然后是Makefile相关知识。重点在于介绍Makefile相关知识。

在学习Linux和GCC的过程中我遇到过许多困难和诱惑,好在都在网上和相关书籍上找到了答案和解决,这里在此,首先要对他们的工作和付出表示感谢,本文的最终成文和我现在的学习成果都离不开他们(它们)!也希望大家在遇到困难的时候,能够多到网络上查一查,问一问。

好了,闲话少说,下面开始进入本文的正题。

运行于Linux 操作系统下的自由软件GNU gcc 编译器,不仅可以编译Linux 操作系统下运行的应用程序,还可以编Linux内核本身,甚至可以作交叉编译,编译运行于其它CPU上的程序。所以,在进行嵌入式系统应用程序开发时,这些工具得到了日益广泛的应用。 

GCC 编译器 

GCC 是GNU 组织的免费C 编译器,Linux 的很多发布缺省安装的就是这种。很多流行的自由软件源代码基本都能在GCC 编译器下编译运行。 所以掌握GCC 编译器的使用无论是对于编译系统内核还是自己的应用程序都是大有好处的。 

下面通过一个具体的例子,学习如何使用GCC 编译器。 

在Linux 操作系统中,对一个用标准C 语言写的源程序进行编译,要使用GNU 的gcc编译器。   

例如下面一个非常简单的Hello 源程序(hello.c): 

/******************************************************* 

 * Chongqing University,College of Communication and Engineering  

 * File Name :     hello.c 

 * Description : eg for how to compile a source file with gcc   

 * Author :   hu enwei

 * Date :   23th,April,2010     

 *******************************************************/ 

 #includes 

 int main(void)  

    {  

       printf("Hello the world\n");

       return 0;   

     } 

首先在在Linux 的bash 提示符下输入命令:

$vi hello.C

即可启动Linux下的vi编辑器,然后按i键进入插入编辑模式,输入上面的代码,最后按ESC键退出vi的输入模式进入命令模式,并输入:qw或者:x存盘退出。接下来,要编译这个程序,我们只要在Linux 的bash 提示符下输入命令:   

$ gcc -o hello hello.c   

gcc编译器就会生成一个hello的可执行文件。在hello.c 的当前目录下执行命令 ./hello 就可以看到程序的输出结果,在屏幕上打印出“Hello the world”的字符串来。 

命令行中gcc 表示是用gcc 来编译源程序; 

-o    outputfilename 选项表示要求编译器生成文件名为outputfilename 的可执行文件,如

果不指定-o 选项,则缺省文件名是  a.out。在这里生成指定文件名为hello 的可执行文件,而hello.c 是我们的源程序文件。 

gcc  是一个多目标的工具。gcc 最基本的用法是: 

gcc [options] file...  , 

其中的option 是以-开始的各种选项,file 是相关的文件名。在使用gcc 的时候,必须要给出必要的选项和文件名。gcc 的整个编译过程,实质上是分四步进行的,每一步完成一个特定的工作,这四步分别是:预处理,编译,汇编和链接。它具体完成哪一步,是由gcc 后面的开关选项和文件类型决定的。 

清楚的区别编译和连接是很重要的。编译器使用源文件编译产生某种形式的目标文件(object  files)。在这个过程中,外部的符号引用并没有被解释或替换,然后我们使用链接器来链接这些目标文件和一些标准的头文件,最后生成一个可执行文件。在这个过程中,一个目标文件中对别的文件中的符号的引用被解释,并报告不能被解释的引用,一般是以错误信息的形式报告出来。 

gcc 编译器有许多选项,但对于普通用户来说只要知道其中常用的几个就够了。在这里为大家列出几个最常用的选项: 

-o 选项表示要求编译器生成指定文件名的可执行文件; 

-c 选项表示只要求编译器进行编译,而不要进行链接,生成以源文件的文件名命名但把其后缀由.c 或.cc 变成.o 的目标文件; 

-g 选项要求编译器在编译的时候提供以后对程序进行调试的信息; 

-E 选项表示编译器对源文件只进行预处理就停止,而不做编译,汇编和链接; 

-S 选项表示编译器只进行编译,而不做汇编和链接; 

-O  选项是编译器对程序提供的编译优化选项,在编译的时候使用该选项,可以使生成的执行文件的执行效率提高; 

-Wall  选项指定产生全部的警告信息。 

如果你的源代码中包含有某些函数,则在编译的时候要链接确定的库,比如代码中包含了某些数学函数,在Linux 下,为了使用数学函数,必须和数学库链接,为此要加入-lm  选项。也许有大家会问,前面那个例子使用printf 函数的时候为何没有链接库呢?在gcc 中对于一些常用函数的实现,gcc 编译器会自动去链接一些常用库,这样用户就没有必要自己去指定了。有时候在编译程序的时候还要指定库的路径,这个时候要用到编译器的-L  选项指定路径。比如说我们有一个库在  /home/hoyt/mylib  下,这样我们编译的时候还要加上 -L/home/hoyt/mylib。对于一些标准库来说,没有必要指出路径。只要它们在起缺省库的路径下就可以了,gcc 在链接的时候会自动找到那些库的。 

GNU 编译器生成的目标文件缺省格式为elf(executive linked file)格式,这是Linux 系统所采用的可执行链接文件的通用文件格式,elf格式由若干段(section)组成,如果没有特别指明,由标准c源代码生成的目标文件中包含以下段:.text(正文段)包含程序的指令代码,.data(数据段)包含固定的数据,如常量,字符串等,.bss(未初始化数据段)包含未初始化的变量和数组等。大家若想知道更多的选项及其用法,可以查看gcc的帮助文档,那里有许多对其它选项的详细说明。(方法:在bash命令行输入man gcc 或者 info gcc即可。)   

当改变了源文件hello.c后,需要重新编译它: 

$gcc -c hello.c   

然后重新链接生成: 

$gcc –o hello.o 

对于本例,因为只含有一个源文件,所以当改动了源码后,进行重新的编译链接的过程显得并不是太繁琐,但是,如果在一个工程中包含了若干的源码文件,而这些源码文件中的某个或某几个又被其他源码文件包含,那么,如果一个文件被改动,则包含它的那些源文件都要进行重新编译链接,工作量是可想而知的。  幸运的是,GNU 提供了使这个步骤变得简单的工具,就是下面要介绍给大家的GNU Make工具。 

   GNU Make

make是负责从项目的源代码中生成最终可执行文件和其他非源代码文件的工具。make命令本身可带有四种参数:标志、宏定义、描述文件名和目标文件名。其标准形式为: 

make [flags] [macro definitions] [targets] 

Unix系统下标志位flags 选项及其含义为: 

-f  file  指定file 文件为描述文件,如果file 参数为  "-" 符,那么描述文件指向标准输入。如果没有  "-f" 参数,则系统将默认当前目录下名为makefile 或者名为Makefile 的文件为描述文件。在Linux 中,  GNU make  工具在当前工作目录中按照GNUmakefile、makefile、Makefile 的顺序搜索  makefile 文件。 

-i   忽略命令执行返回的出错信息。 

-s   沉默模式,在执行之前不输出相应的命令行信息。 

-r   禁止使用隐含规则。 

-n   非执行模式,输出所有执行命令,但并不执行。 

-t   更新目标文件。 

-q   make 操作将根据目标文件是否已经更新返回"0"或非"0"的状态信息。 

-p   输出所有宏定义和目标文件描述。 

-d   Debug 模式,输出有关文件和检测时间的详细信息。 

Linux 下make 标志位的常用选项与Unix 系统中稍有不同,下面只列出了不同部分: 

-c dir  在读取  makefile  之前改变到指定的目录dir。 

-I dir  当包含其他  makefile 文件时,利用该选项指定搜索目录。 

-h  help 文挡,显示所有的make 选项。 

-w  在处理  makefile  之前和之后,都显示工作目录。 

通过命令行参数中的target,可指定make 要编译的目标,并且允许同时定义编译多个目标,操作时按照从左向右的顺序依次编译target 选项中指定的目标文件。如果命令行中没有指定目标,则系统默认target 指向描述文件中第一个目标文件。 

make 如何实现对源代码的操作是通过一个被称之为makefile 的文件来完成的,接下来,详细的向大家介绍一下makefile 的相关知识。 

makefile 基本结构 

GNU Make的主要工作是读一个文本文件 makefile。makefile 是用bash 语言写的,bash语言是很像BASIC 语言的一种命令解释语言。这个文件里主要描述了有关哪些目标文件是从哪些依赖文件中产生的,是用何种命令来进行这个产生过程的。有了这些信息,make会检查磁盘的文件,如果目标文件的日期(即该文件生成或最后修改的日期)至少比它的一个依赖文件日期早的话,make就会执行相应的命令,以更新目标文件。makefile 一般被称为“makefile”或者“Makefile”。还可以在make的命令行中指定别的文件名。如果没有特别指定的话,make就会寻找“makefile”或“Makefile”,所以为了简单起见,建议大家使用这两名字。如果要使用其他文件作为  makefile,则可利用类似下面的make  命令选项指定makefile文件: 

     $ make -f    makefilename 

 一个  makefile  主要含有一系列的规则,如下: 

     目标文件名  :  依赖文件名 

     (tab 键)    命令 

第一行称之为规则,第二行是执行规则的命令,必须要以tab 键开始(切忌)。下面举一个简单的makefile 的例子。 

executable : main.o io.o 

     gcc main.o  io.o  -o executable 

main.o : main.c   

     gcc -Wall -O -g  -c main.c -o main.o 

io.o : io.c  

     gcc -Wall -O -g  -c io.c -o io.o   

这是一个最简单的 makefile,make从第一条规则开始,executable是makefile 最终要生成的目标文件。给出的规则说明executable 依赖于两个目标文件main.o 和io.o,只要executable 比它依赖的文件中的任何一个旧的话,下一行的命令就会被执行。但是,在检查文件main.o和io.o的日期之前,它会往下查找那些把main.o或 io.o做为目标文件的规则。make先找到了关于main.o的规则,该目标文件的依赖文件是main.c。makefile 后面的文件中再也找不到生成这个依赖文件的规则了。此时,make 开始检查磁盘上这个依赖文件的日期,如果这个文件的日期比main.o日期新的话,那么这个规则下面的命令  gcc -c main.c –o main.o 就会执行,以更新文件main.o。同样make对文件io.o做类似的检查,它的依赖文件是io.c,对io.o 的处理和main.o 类似。 

 现在,再回到第一个规则处,如果刚才两个规则中的任何一个被执行,最终的目标文件executable 都需要重建(因为executable 所依赖的其中一个 .o  文件就会比它新),因此链接命令就会被执行。有了makefile,对任何一个源文件进行修改后,所有依赖于该文件的目标文件都会被重新编译(因为.o  文件依赖于.c  文件),进而最终可执行文件会被重新链接(因为它所依赖的.o文件被改变了),再也不用手工去一个个修改了。 

 编写make 

接下来的内容,为大家详细介绍如何编写makefile。内容包括,Makefile中的宏定义、Makefile的隐含规则、伪目标和函数等。

1、Makefile 宏定义 

makefile里的宏是大小写敏感的,一般都使用大写字母。它们几乎可以从任何地方被引用,可以代表很多类型,例如可以存储文件名列表,存储可执行文件名和编译器标志等。 

要定义一个宏,在makefile 中,任意一行的开始写下该宏名,后面跟一个等号,等号后面是要设定的这个宏的值。如果以后要引用到该宏时,使用  $  (宏名),或者是${宏名},注意宏名一定要写在圆或花括号之内。把上一小节所举的例子,用引入宏名的方法,可以写成下面的形式: 

OBJS = main.o io.o 

CC = gcc 

CFLAGS = -Wall -O -g 

 

executable: $(OBJS) 

     $(CC) $(OBJS) -o executable 

 

main.o : main.c 

     $(CC) $(CFLAGS) -c main.c -o main.o 

 

io.o : io.c 

$(CC) $(CFLAGS) -c io.c -o io.o 

在这个makefile 中引入了三个宏定义,所以如果当这些宏中的某些值发生变化时,开发者只需在要修改的宏处,将其宏值修改为要求的值即可,makefile 中用到这些宏的地方会自动变化。在 make  中还有一些已经定义好的内部变量,有几个较常用的变量是$@,  $



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3