红旗Linux系统开发技术(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-20 15:38:47

点击下载

作者:北京中科红旗软件技术有限公司

出版社:石油工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

红旗Linux系统开发技术

红旗Linux系统开发技术试读:

前言

Linux操作系统是可运行在多种硬件平台的个人计算机和工作站上的类Unix操作系统,它继承了Unix的全部优点,是真正的多用户、多任务、多平台的操作系统。在个人计算机和工作站上使用 Linux操作系统,能充分发挥硬件的功能,使个人计算机能够作为工作站和服务器使用,提高工作站效率;Linux符合POSIX标准,能同时支持i386、MIPS、SPARC和PowerPC等处理器;对于Unix上运行的软件,不用改动或稍加改动就可以运行在Linux操作系统上。

同Unix相比,Linux要灵活得多。Linux的用户界面非常友好,用户使用很方便。组成Linux操作系统的Linux内核以及各类开源组建受自由软件委员会指定的GPL( GeneralPublicLicense)公用许可协议保护,Linux系统内核及其大多应用软件的源代码都是向用户公开的。各地区系统发布商,根据各自地域文化和技术理念,在遵循GPL等开源软件协议的Linux内核与组件的基础上,加以工程化打造而成为可产品化的 Linux操作系统,服务于社会应用需求。用户可使用Linux操作系统中自带的C/C++等编程语言编译器修改并编译自己喜欢的程序,同时也可以在GNU的许可下使用这些源程序的部分或全部。这种利用Linux源程序的可能性大大激发了世界范围内热衷于计算机事业的人们的兴趣和创造力,吸引了众多程序员为 Linux工作。目前,所有 Unix的主要功能都已经有相应的Linux工具和程序,大量的自由软件被移植到Linux操作系统上,世界各地流行着越来越多的Linux发行版本,如Red HatLinux、Red FlagLinux等。在这些发行版本中,不仅包含Linux操作系统的内核,还包含各种编程语言的编译程序、数据库管理系统、图形用户界面、通信联网工具以及大量的其他应用软件。可见,Linux已经是一个相当优秀的应用软件开发平台。

同Windows相比,Linux也一样具有优势。Linux强大的网络功能使Internet以及许许多多局域网中的服务器都被Linux占据,这不仅是由于Linux的稳定性相当出色,也是由于Linux的系统效率极高;与同类型的Windows服务器相比,

Linux对硬件的要求可以降低一到两个档次,一台普通的PC机就能胜任复杂的网络服务工作;另外,Linux下的TCP/IP网络方面的应用软件更是应有尽有,能实现许多在普通系统中无法实现的网络功能。在超级计算机应用领域中,以500强网站公布的数据可以看出,近92%的超级计算机系统是基于Linux构建的,这其中也得益于开源领域的集群技术的优势,为当今云计算技术架构的发展提供了坚实的技术基础。

不可否认,Linux具有较Unix和Windows更卓越的性能,但价格却低得多。因此,如果想提高自己的计算机使用和编程水平,学习Linux确实是一条捷径。

在国家“核心电子器件、高端通用芯片及基础软件产品”重大专项进程中,作为基础软件主要承载平台的Linux操作系统得到极大重视,为此,需要更多的开发人员熟悉和了解基于Linux系统技术体系的开发技术。为促进Linux在我国的推广应用,让开发人员更快地步入Linux的奇妙世界,少走一些弯路,北京中科红旗软件技术有限公司红旗教育学院组织经验丰富的Linux编程人员,参考国际经典Linux、Unix编程书籍,编写本书,旨在充分发挥我国软件工作人员的积极性和创造力,振兴我国的软件事业。本书内容涵盖了Linux/Unix编程的主要方面,具有一定的深度,具体内容如下:(1) 第1章详细介绍Linux的软件开发环境,包括编译、调试、维护工具以及广泛应用的集成开发环境。(2) 第2、3、4、5章介绍Linux的文件系统、I/O系统调用、系统数据文件方面的内容,本部分不仅详细介绍了传统Unix的文件、I/O系统调用,还专门介绍了Linux文件、I/O系统的特点。(3) 第6、7、8、9章介绍Linux进程模型,包括进程关系、进程控制、进程间通信、信号处理等方面的内容。(4) 第10章介绍终端I/O编程,它的用途主要包括:终端、计算机之间的连接、调制解调器、打印机等方面,因此非常复杂。(5) 第11章介绍网络套接字编程,socket是最广泛使用和最成熟的网络编程接口规范,用来实现网络的互联。(6) 第12章介绍守护进程、系统服务等方面的内容,可以编写自己的守护进程来增加、增强系统服务。(7) 第13章介绍多线程编程,在操作系统层面上讲述了线程的层次和模型,还包括线程同步、互斥等方面的内容。

本书结合大量实例,概念清晰、内容丰富翔实、特色鲜明、实用性强。本书由北京中科红旗软件技术有限公司红旗教育学院组织编写,对参与本书编写的人员,在此表示感谢。由于本书涉及的内容丰富,加之篇幅、时间有限,书中难免存在纰漏和不足,欢迎读者批评指正。

北京中科红旗软件技术有限公司

2012年10月

1 Linux软件开发工具

1.1 gcc和g++

gcc和g++分别是GNU的C及C++编译器,是Linux系统中将C及C++语言源文件生成可执行程序的工具。

一个可执行的C或C++程序需要经过如下四步生成:

第一步:由预处理程序对C或C++语言源文件(*.c或*.cpp、*.C、*.cxx等)进行宏扩展和条件处理,并导入前导文件,生成以.i为后缀的文件;

第二步:由编译程序将预处理后的文件(*.i)中的C或C++语言源代码转换成汇编语言代码,生成以.s为后缀的汇编文件;

第三步:由汇编程序将汇编文件(*.s)中的汇编语言代码转换成目标代码(机器代码,*.o),生成以.o为后缀的目标文件;

第四步:由连接程序将目标文件(*.o)同指定的库文件进行连接,生成可执行程序。若非特别指定,gcc或g++将自动调用上述工具,生成可执行程序。

gcc和g++命令的调用格式为:

gcc

[options]

filenames

g++

[options]

filenames

其中:options为gcc和g++命令的选项,可以为空;多个选项必需分开写,如“-dr”不同于“-d-r”。filenames是gcc和g++命令的输入文件列表,多个文件之间以空格分隔。

gcc和g++命令的选项很多,它们规定着gcc和g++命令的行为;掌握gcc和g++命令的关键就是正确使用它们的选项。

gcc和g++命令的选项大致可分为如下几类:(1)全局选项:影响编译的全过程(从预处理到连接);(2)语言选项;(3)预处理程序选项;(4)汇编程序选项;(5)连接程序选项;(6)目录选项;(7)优化选项;(8)调试选项;(9)警告选项。

下面分别介绍各类的常用选项(除非特殊声明,选项将同时适用于gcc和g++命令)。1.1.1 全局选项

1.1.1.1-x languagefilenames

-xlanguagefilenames选项指明filenames文件的编程语言( C语言、C++语言等)及gcc/g++编译的起始阶段(预处理、编译、汇编、连接)。

language的可选值为C、C++、assembler-with-cpp等。其中:C、C++指明输入文件为C语言、C++语言文件,编译过程从预处理阶段开始;assembler、assembler-with-cpp指明编译过程从汇编阶段开始。

-xlanguage选项对其后的多个文件都有效,直至遇到下一个-x为止。

在不使用此选项时,gcc/g++利用文件名后缀来确定语言及编译的起始阶段。如:输入文件名以.c或.cpp为后缀时,从预处理阶段开始编译;以.i为后缀时,从编译阶段开始编译;以.s为后缀时,从汇编阶段开始编译;以.o为后缀时,从连接阶段开始编译。使用-x选项后,文件名后缀将不再对编译的起始阶段起作用。

1.1.1.2-x nonefilenames

-xnonefilenames选项使-xlanguage选项失去作用,其后文件以名字后缀决定语言及编译的起始阶段。

1.1.1.3-c、-S、-E选项

-c、-S、-E这三个选项决定编译过程到哪一个阶段(预处理、编译、汇编、连接)结束,它们不能同时使用。

-c选项激活预处理、编译及汇编程序,不执行连接程序;编译过程到汇编阶段结束;输出文件为目标文件(*.o),可用-o选项另行指定输出文件名。

-S选项激活预处理及编译程序,不执行汇编和连接程序;编译过程到编译阶段结束;输出文件为汇编文件(*.s),可用-o选项另行指定输出文件名。

-E选项激活预处理程序,不执行编译、汇编和连接程序;编译过程到预处理阶段结束;输出被送到标准输出,可用-o选项重新定向到文件输出。

1.1.1.4-o filename

-ofilename选项以 filename覆盖 gcc/g++缺省的输出文件名;它可以同-c、-S、-E中的任何一个选项一同使用,为各阶段的输出文件(可执行文件、目标文件、汇编文件、预处理后的C/C++语言源文件)改名。

因为-o选项只能指定一个输出文件名,所以当有多个输出文件产生时,-o选项不起作用。

如不使用此选项,缺省情况下,可执行程序以a.out命名,目标文件以*.o命名,汇编文件以*.s命名,预处理后的C/C++语言源文件定向到标准输出。

1.1.1.5-pipe

-pipe选项用管道代替临时文件来处理不同编译阶段(预处理、编译、汇编、连接)—2—

间的通信。这个选项在某些不支持管道操作的系统上不工作,但在 GNU编译器上不会有问题。1.1.2 语言选项

1.1.2.1-ansi

-ansi选项关闭GNUC中与ANSIC不兼容的特性,是ANSIC的专有特性。当使用此选项时,预编译器定义了一个宏_STRICT_ANSI_,用户可在源程序中加入对此宏的判断来避免使用ANSI标准不兼容的特性。

比如:在ANSIC中,禁止使用 asm、inline和 typeof关键字及 unix、vax等预定义宏,取而代之的是_asm_、_ inline_、_ typeof_、_ unix_和_vax_;这些被释放出来的关键字和宏可由用户赋予新的含义。

注意:-ansi选项并不拒绝非ansi程序。

1.1.2.2-fno-asm

-fno-asm选项实现-ansi选项功能的一部分,它禁止将asm、inline和typeof用作关键字。使用此选项的目的是程序已经为 asm、inline和 typeof赋予新的含义,不希望编译器(gcc、g++)将它们解释为关键字。

1.1.2.3-fno-strict-prototype

-fno-strict-prototype选项只对g++起作用,对gcc没有影响。

通常情况下,g++编译器将不带参数的函数声明理解为没有参数;使用此选项后,g++认为不带参数的函数声明是没有显式地对参数的个数及类型进行声明,而不是没有参数。

不论是否使用此选项,gcc编译器总是将不带参数的函数声明理解成没有对参数的个数及类型进行声明。

1.1.2.4-fthis-is-variable

-fthis-is-variable选项只对g++有效。

缺省情况下,C++语言中的类已经将其对象指定给this指针,因此不能再将this用作一般变量;为了同传统C++语言兼容,此选项允许将this用作一般变量。

1.1.2.5-fcond-mismatch

-fcond-mismatch选项允许条件表达式的第二和第三参数类型不匹配。这样的表达式的值为void类型。

1.1.2.6-funsigned-char、-fno-signed-char、-fsigned-char、-fno-unsigned-char

-funsigned-char、-fno-signed-char、-fsigned-char、-fno-unsigned-char这四个选项对char类型进行设置。char类型可能为signed-char,也可能为unsigned char。每种机器对char类型都有缺省设置,使用这四个选项可以重新指定char类型的设置。其中前两个选项将char类型指定为unsigned char,后两个选项将char类型指定为signed char。1.1.3 预处理程序选项

预处理程序选项用于设定gcc/g++在预处理阶段的行为。前文曾经讲过,-E选项使gcc/g++只执行预处理程序;此类中的部分选项必须同-E选项一起使用,因为它们使预处理程序的输出不适合继续编译。

1.1.3.1-includefile、-imacrosfile、-Dmacro、-Dmacro=defn、-Umacro

上述五个选项的作用相当于C/C++语言源文件中的#include、# define和#undef语句,但是优先于gcc/g++的输入文件被处理。当gcc/g++的命令行中有上述选项出现时,gcc/g++不论-Dmacro、-Umacro选项的位置如何,总是最先处理它们;然后再按照命令行中的顺序处理-include和-imacros选项;只有在命令行中的预处理选项都被处理完之后,gcc/g++才去处理输入文件中的预处理语句。

在上述五个选项中:-includefile选项的作用相当于 C/C++语言源文件中的“#in-clude”语句,导出file文件内容到gcc/g++的输入文件中;-imacrosfile选项的作用是将file文件中的宏定义扩展到 gcc/g++的输入文件中,宏定义本身并不出现在输入文件中;-Dmacro选项的作用相当于C/C++语言源文件中的“#definemacro”语句,定义macro宏为串“1”或“TRUE”;-Dmacro=defn选项的作用相当于C/C++语言源文件中的“#de-finemacrodefn”语句,定义macro宏为串defn;-Umacro选项的作用相当于C/C++语言源文件中的“#undefmacro”语句,取消对macro宏的预定义。

1.1.3.2-undef

-undef选项取消对任何非标准宏的定义。附表

这些选项限定gcc/g++搜索头文件(前导文件)的路径。

C/C++语言源文件中约定使用#include<file.h>语句来包含任何由C编译系统提供的标准前导文件,使用#incldue“file.h”语句来包含用户自己目录中的前导文件。

在不使用上述选项的情况下,gcc/g++按照如下顺序搜索前导文件:

对于在#include<file.h>中给出的前导文件:gcc/g++只到系统的标准位置(通常是/usr/include)中搜索;

对于在#include“file.h”中给出的前导文件:gcc/g++先在包含#include“file.h”语句的C/C++源文件所在的目录中搜索(这个目录通常是用户的当前目录),若未找到,再到标准位置(通常为/usr/include)下搜索。

如在命令行中使用-Idir选项,gcc/g++将按如下顺序搜索头文件:—4—

对于在#include<file.h>中给出的头文件:先在-I选项所指定的dir中查找,再到标准位置中查找;

对于在#include“file.h”中给出的头文件:先在含此语句的源文件所在的目录下查找,再到-I选项所指定的dir中查找,最后到标准位置下查找。

如在命令行中使用-I-选项,且有-Idir选项出现在-I-之前,则gcc/g++按如下顺序搜索头文件:

对于在#include<file.h>中给出的头文件:只在标准位置中查找,不到-I选项所指定的dir中查找,除非-Idir选项出现在-I-选项之后;

对于在#include“file.h”中给出的头文件:先在含此语句的源文件所在的目录下查找,再到-I选项所指定的dir中查找,最后到标准位置下查找;不受-I-选项的影响。

如在命令行中使用-idirafterdir选项,则当gcc/g++在-I选项指定的dir中搜索失败后,将继续在此选项指定的dir中搜索。

-iprefix选项和-iwithprefix选项总是在一起使用,它们规定当gcc/g++在-I选项指定的dir中搜索失败后,继续在由-iprefixprefix和-iwithprefixdir共同指定的路径“prefix+dir”下搜索。

1.1.3.3-nostdinc

-nostdinc选项规定gcc/g++不在系统标准位置(通常为/usr/include)下搜索头文件。联合使用-nostdinc选项和-I选项,用户可以明确限定头文件的搜索路径。

1.1.3.4-nostdinc++

-nostdinc++选项规定不在 g++指定的标准路径中搜索,但仍在其他标准路径中搜索。

此选项在创建libg++库时使用。

1.1.3.5-C

-C选项使预处理程序不删除C/C++语言源文件中的注释语句;此选项必须同-E选项一起使用。

1.1.3.6-M、-MM、-MD、-MMD

-M、-MM、-MD、-MMD这四个选项为每一目标文件生成依赖关系,以方便make使用。

-M选项使预处理程序为每一C/C++源码文件输出一条规则,规则的目标是源码文件(*.c,*.cpp)的目标文件(*.o),依赖关系是所有包含在#include语句中的头文件。每条规则可能只有一行,也可能用续行符分写成多行,规则清单被送到标准输出。此选项包含-E选项的功能。

-MM选项类似于-M选项,但依赖关系中只包含在#include"file.h"语句中的头文件,而忽略在#include<file.h>中的头文件。

-MD选项类似于-M选项,但规则清单不送到标准输出,而是写入.d文件中,以方便md工具将多个.d文件合并成一个文件,提供给make使用。

-MMD选项综合了-MD选项和-MM选项的功能。1.1.4 汇编程序选项:-Wa,option

-Wa,option选项传递option给汇编程序;如果option中含有逗号,就将option分隔成多个选项后传递给汇编程序。1.1.5 连接程序选项

1.1.5.1-Wl,option

-Wl,option选项传递option给连接程序;如果option中含有逗号,就将option分隔成多个选项后传递给连接程序。

1.1.5.2-dy、-Bstatic、-Bdynamic

-dy、-Bstatic、-Bdynamic这些选项用于指明库的连接方式——静态连接方式或动态连接方式;所选择的连接方式决定了库函数何时被连接到程序中。

在静态连接方式下,用户的程序的外部引用同它们的定义在创建可执行文件的时候就被指定内存地址,连接到程序中。在此方式下,可供连接的库有静态连接库(也称归档库)和静态共享库。静态连接库是一组目标文件,其中每个目标文件都包含了一个函数或一组相关函数;连接时,库中含有用户程序中尚未解析的外部引用的目标文件副本将被结合到用户的可执行文件中。相比之下,静态共享库所包含的目标代码可以由多个进程在运行时共享;当用户的程序连接一个静态共享库时,定义用户程序中外部引用的那部分库代码并没有被复制到程序的目标文件中,而是在目标文件中创建了一个识别库代码的被称作.lib的特殊段;直到程序执行时,.lib段中的信息才将所需的静态共享库代码引入到进程的地址空间中;因此,对于所有使用静态共享库的程序来说,静态共享库代码只有一个目标副本在内存中存在。

在动态连接方式下,用户的程序的外部引用同它们的定义是在程序运行时才被连接的。在此方式下,可供连接的库为动态连接库,也称共享目标库。动态连接库是一个独立的目标文件,其中包含了库中每一个函数的代码;动态连接库中的内容只有在程序运行时才被映射到进程的虚拟地址空间中;同静态连接相比,动态连接程序节省磁盘空间和运行时被共享库占用的系统进程内存,而且动态连接代码可以方便地修改和升级,无需对依赖于它的应用程序进行重新连接。

按照约定,动态连接库的文件名前缀为 lib,后缀为.so;静态连接库的文件名前缀为lib,后缀为.a;静态共享库的文件名前缀为lib,后缀为_s.a。所以,标准C库的静态连接版本为libc.a;静态共享版本为libc_s.a;动态连接版本为libc.so。

缺省情况下,gcc/g++使用指定库的静态连接版本;而在-dy选项下,连接程序首先搜索库的动态连接版本,搜索失败后,才使用静态连接版本;静态共享库不受-dy选项的影响,它是在指定库文件时通过库文件名后缀(-s)来标识的。

如果用户想明确限定某些库的连接方式,可以使用-Bstatic和-Bdynamic选项。—6—

-Bstatic选项关闭动态连接方式,-Bdynamic选项打开动态连接方式。一旦指定了-Bstatic选项,连接程序将不再接受动态连接库,直到再次指定-Bdynamic选项;反之亦然。

1.1.5.3-llibrary

-llibrary选项用于指定要连接的库,参数library是库文件名去掉前缀和后缀剩下的部分。如:-lsocket指明连接socket库,其静态连接版本为libsocket.a,动态连接版本为lib-socket.so;具体连接哪一个版本,由-dy、-Bstatic和-Bdynamic选项决定;但若要连接其静态共享版本libsocket_s.a,则应用-lsocket_s选项给出,此选项不受-dy、-Bstatic和-Bdynamic选项的影响。

不论是否使用-l选项,连接程序都将连接标准C库;如果使用-l选项,连接程序将在搜索完-l选项所指定的库文件之后,再在标准C库中寻找尚未解析的外部引用的定义。

注意:由于连接程序在库中仅仅为它所找到的未解析的外部引用搜索定义,所以-l选项在gcc/g++命令行出现的位置很重要,通常放在命令行的末尾。

1.1.5.4-Ldir

-Ldir选项用于指定库的搜索路径。

在未使用此选项的情况下,连接程序直接从库的标准路径(通常为/usr/lib/)中搜索指定的库(包括在-l选项中指定的库和标准C库)。

在使用此选项的情况下,连接程序首先在-L指定的路径中搜索,然后再到标准路径下搜索。

另外,用户还可以使用环境变量LD_LIBRARY_PATH来增加连接程序搜索路径的列表。LD_LIBRARY_PATH必需是用冒号隔开的路径名称列表(限定使用绝对路径),可选的第二个列表同第一个列表之间用分号隔开;如:

LD_LIBRARY_PATH=dir1: dir2; dir3: dir4 exportLD_LIBRARY_PATH

在分号之前的第一个列表中指定的目录将在用-L指定的路径之前按顺序搜索,分号之后的第二个列表中指定的目录将在用-L指定的路径之后按顺序搜索。在使用环境变量LD_LIBRARY_PATH指定库的搜索路径时应注意两点:(1)所有在此环境下执行的连接程序都将受到此变量的影响;(2)当用户将某动态连接库移动到另一个目录中时,只需修改LD_LIBRARY_PATH变量值,不必重新编译程序(用-L选项设定库的搜索路径时,必须在修改-L选项的参数后,重新编译程序,才能正确执行)。

1.1.5.5-dy-G选项

-dy-G选项用于创建动态连接库。用户可以在-G选项后面用-o选项指定要创建的动态连接库的名称,否则,将创建名为a.out的动态连接库。

当所创建的库不遵循lib前缀和.so后缀时,无法用-l选项连接,为此可在创建库后用mv命令重新命名库。

如:gcc-dy-Gfile1.o file2.o file3.o

{ mva.outlibx.a

等价于:gcc-dy-G-o libx.a file1.o file2.o file3.o

1.1.5.6 介绍两个与连接程序密切相关的命令(1)ar命令:此命令用于创建动态连接库,如:ar、-r、libx.a、file1.o、file2.o、file3.o。(2)ldd命令:此命令指示连接程序输出程序所依赖的动态连接库的路径及名称。可用-d选项指示连接程序输出运行程序时遇到的所有未被解析的数据引用的诊断信息;也可用-r选项指示连接程序输出运行程序时遇到的所有未被解析的数据或函数引用诊断信息。1.1.6 目录选项

目录选项包括-Idir、-I-和-Ldir选项等;详细内容在前面的预处理程序选项和连接程序选项中已经讲过,此处不再重复。1.1.7 优化选项

优化选项用于提高gcc/g++编译器产生的汇编语言代码的效率,缩短目标代码的执行时间。若不使用这些选项,编译器将尽可能减少编译开销。

此类选项包括:附表

其中:-O0选项关闭编译器的优化功能;-O1、-O2、-O3 选项分别指示编译器对程序进行不同层次的优化,从-O1到-O2、再到-O3,优化程度依次加深,编译时间越来越长,生成代码的质量逐渐提高,程序运行的速度不断加快。

当在同一gcc/g++命令行使用多个-O选项时,最后一个优化选项起作用。1.1.8 调试选项

调试选项用于指示编译器产生与程序变量和语句相关的信息,供调试工具使用。

1.1.8.1-g

-g选项指示编译器以操作系统的本地格式(如:stabs、COFF、XCOFF、DUARF等)产生调试信息,提供给调试程序(如:gdb)使用。在大多数使用stabs格式的系统上,-g选项能够产生额外的调试信息,但这些信息只能由gdb使用,其他的调试程序可能会因此发生异常;若想禁止额外信息的产生,可使用-gstabs选项。

1.1.8.2-gstabs

-gstabs选项以stabs格式生成调试信息,但不包含gdb的额外调试信息。

1.1.8.3-gstabs+

-gstabs+选项以stabs格式生成调试信息,并含有仅供gdb使用的额外调试信息。—8—

1.1.8.4-ggdb

-ggdb选项生成调试信息,且尽可能包含gdb的额外调试信息。

注意:不同于其他许多C/C++语言编译器,gcc/g++允许调试选项与优化选项一起使用。1.1.9 警告选项

警告作为诊断信息,报告程序中的非致命错误。

警告选项控制由gcc/g++产生警告的数量和种类。

1.1.9.1-pedantic

-pedantic选项禁止某些GNU扩充特性和传统C语言特性。通常不论有无此选项,AN-SI标准C程序都能正确编译,所以一般情况下无需使用该选项。

1.1.9.2-pedantic-errors

-pedantic-errors选项类似于-pedantic,只是不产生警告信息而产生错误信息。

1.1.9.3-fsyntax-only

-fsyntax-only选项只检查代码的语法错误,不产生任何输出。

1.1.9.4-Wimplict

-Wimplict选项当函数或参数被隐式声明时,产生警告信息。

1.1.9.5-Wunused

-Wunused选项当某局部变量未被使用过;或某函数声明被声明为静态函数,却从未被定义过;或者当某表达式的计算结果从未被使用过时,产生警告信息。

1.1.9.6-Wcomment

-Wcomment选项当有“/”出现在注释行中时,产生警告信息。

1.1.9.7-Wformat

-Wformat选项当printf和scanf中的格式出错时,产生警告信息。

以上只分类介绍了gcc/g++编译器的常用选项,另外还有许多选项,请查看gcc/g++的参考手册或相关文档。1.2 gnumake

同gcc/g++一样,gnu make(简称为gmake;在Linux系统中,gmake是make的符号连接,所以本节不区分make与gmake)也是Linux系统上的软件开发人员所必须掌握的工具之一,二者都能将C/C++语言源文件生成可执行程序。比较它们的关系,可以说:gcc/g++是make的基础,没有gcc/g++(不考虑其他编译器), make就无法将C/C++语言

源文件生成可执行程序;而make则好比是gcc/g++命令的调度器,它通过读进一个文本文件(通常称之为Makefile或makefile文件,其内定义有C/C++语言源文件的依赖关系和要执行的命令序列), 执行一组以gcc/g++为主的shell命令序列,在创建/更新程序的同时,将不必要的编译减到最少。

通过使用make命令,可以从C/C++软件的维护工作中解脱出来,不必再因为某些文件的改变,而去手工编译/连接依赖于它们的文件。

make命令可以自动帮助记住以下内容:(1)文件之间的依赖关系;(2)哪些文件是最近修改的;(3)在源文件修改后哪些文件需要重新编译;(4)产生新版本程序所需的精确的操作序列。

make具有如此突出的优势,以至于如果程序不是用make命令生成的,那么这个程序就只能算作是个人程序,而不具有丝毫的通用性。

make命令的基本工作流程如图1 1所示。1.2 gnumake01

图1 1 make命令基本工作流程图

下面先介绍make命令的输入文件,再介绍make命令的使用方法。1.2.1 make命令的输入文件

make命令的输入文件缺省命名为Makefile或makefile。除非在make命令行中特别指定,make将首先查找Makefile文件,找到后就去执行其中的命令序列;找不到再去查找makefile文件(为方便说明,以下称make命令的输入文件为Makefile文件)。

make命令的输入文件主要包含规则和变量,它们负责记录文件之间的依赖关系和命令的执行顺序。

1.2.1.1 规则1.规则构成

Makefile文件中的每条规则由一个带冒号的“依赖行”和一条或多条以tab开头的“命令行”组成。

规则语法为:附表

其中:第一行为依赖行,其下各行为命令行,带方括号的项为可选项。依赖行中,冒号左边是目标,冒号右边是依赖文件;目标和依赖文件均是由字母、数字、句点和斜杠组成的字符串,串中允许包含shell元字符(如:*和?), 这些字符在对行求值时展开;当目标或依赖文件的数目多于一个时,以空格分隔。命令行是不包含“#”(除非出现在引号之间)的任意字符构成的字符串;多个命令可以用分号分隔后写在同一命令行中,也可分成多个命令行;命令行描述如何由依赖文件生成规则目标,所有的命令行都必须以tab字符(命令行中以“\t”代表tab字符)开头。

[例1 1] 下面是由某Makefile文件中抽取出的一条规则。附表

例1 1中:第一行为依赖行,表明规则目标xyz依赖于C语言源文件x.c、y.c、z.c及目标代码文件assemble.o和库文件object.a。第二行为命令行,以tab开头,指定由依赖文件生成规则目标的编译/连接命令。

至此,提到的规则目标均是“真实目标”,它们在命令执行后确实能被创建/更新。与此相对的还有一种目标,称为“假象目标”;此种目标既不出现在规则的命令行中,也不会因为命令行的执行而被创建/更新。“假象目标”通常有两个用处。一是创建多个互不相关的目标。[例1 2] Makefile文件中经常会有类似于下面的语句。附表

例1 2中:all为“假象目标”,object1与object2 是两个互不相关的“真实目标”。执行makeall命令后,因为all是“假象目标”,没有任何规则生成它,所以make会以为all需要创建而去执行此条规则;执行这条规则时,make要先创建/更新规则中的依赖文件object1和object2;于是分别执行以object1和object2 为目标的规则,如此就由一条规则创建/更新了两个互不相关的目标object1和object2。“假象目标”的第二个用处是描述一组不生成固定目标的动作。[例1 3] 某Makefile文件中含有如下内容:附表

例1 3中:clean为“假象目标”,规则执行结果会删除Makefile文件所在路径下的所有以.o和.a为后缀的文件。

正确使用“假象目标”的前提是“假象目标”不存在。倘若由于某种原因,“假象目标”存在,且是最新(在“假象目标”的第二种用法中,由于没有依赖文件,所以只要“假象目标”存在,就一定是最新的), make就会拒绝执行此条规则,因而既无法生成多个互不相关的目标,也不能执行命令行规定的动作。为确保此种情况不会发生,解决办法是在Makefile文件中用.PHONY关键字标示出所有的“假象目标”;这样,make就不会检查“假象目标”是否存在,而总是认为它们需要被创建/更新。

[例1 4].PHONY:clean

指定clean为“假象目标”,且总需要被创建/更新。

2.规则编写

规则编写包括“依赖行”和“命令行”的编写。

首先介绍依赖行的编写。最明显的办法是逐个检查源文件,将它们的目标文件(*.o)作为规则目标,将源文件中包含的头文件列成依赖文件。此种方法的优点是简单易行,但当项目很大时,会因为涉及的文件众多、目录结构复杂,而导致工作量剧增,出错率上升。为克服这个缺点,用户可以借助gcc/g++的-M选项(具体参见本章第一节)来创建依赖关系;此选项为gcc/g++编译器的每个输入文件生成一条规则,规则的目标是输入文件的目标代码文件(*.o),依赖文件是输入文件及其所包含的全部头文件(包括系统头文件和用户定制的头文件), 因为系统头文件(在C/C++语言源文件中以#include<file.h>包含)一般不会被修改,所以用户也可以用-MM选项代替-M选项,使编译器生成的依赖关系中只包含用户自己定制的头文件(在C/C++语言源文件中以#include"file.h"包含)。

编写完依赖关系后,就该编写命令行了。对此,可在依赖行的下一行插入要执行的命令(注意:命令行必须以tab开头),也可什么都不写,按照隐含规则来创建目标。

3.隐含规则

隐含规则也称为后缀转换规则,它们决定如何将某种后缀的文件转换成另一种后缀的文件。每条隐含规则都有名称,其名称是将转换前后的后缀连接得到的。

如:将C语言源文件(*.c)转换成目标文件(*.o)的隐含规则称为.c.o规则;将汇编语言文件(*.s)转换成目标文件(*.o)的隐含规则称为.s.o规则;

将C语言源文件(*.c)生成可执行程序(无后缀)的规则称为.c规则;此规则属于空后缀规则。

当make命令在相应的Makefile文件中没有找到生成某目标的命令行时,就会求助于隐含规则。

[例1 5] 某Makefile文件中含有如下规则:附表

例1 5中,x.o规则只含有依赖行,而没有命令行。make在创建x.o目标时,就会根据隐含规则中的.c.o规则来创建x.o。

除了能提供隐含的命令行外,隐含规则还能提供隐含的依赖信息。[例1 6] 当Makefile文件中含有如下规则时:附表

为创建x.o目标,make先按一定的顺序查找隐含规则,当找到第一条以.o为目标后缀的规则(假定为.c.o规则)后,就去查找Makefile文件所在路径下的文件,若存在此隐含规则的源文件(*.c), 就按此隐含规则(.c.o)创建x.o目标;否则,make再去查找下一条以.o作目标后缀的隐含规则…

make命令内嵌有许多隐含规则;但用户仍可以在Makefile文件中重建或追加它们,只是修改后的隐含规则仅对Makefile文件所属的项目有效。

为添加隐含规则,用户需在Makefile文件中用.SUFFIXES关键字声明后缀,并将新建的隐含规则写入 Makefile文件中;要清除隐含规则,用户需在 Makefile文件中设置.SUFFIXES段为空。

[例1 7] Makefile文件的部分内容如下:附表

例1 7中:第一行删除当前所有的隐含规则;第二行声明两条新的隐含规则(.s.t和.s.l);从第三行开始按照规则的一般格式给出这两条隐含规则(.s.l、.s.t)的定义。如此,这个 Makefile文件所属的项目就用这两条隐含规则覆盖了 make内置的其他所有隐含规则。

注意:在用.SUFFIXES声明隐含规则时,后缀(如果有的话)之间要以空格或 tab分开。

1.2.1.2 变量

Makefile文件中允许定义并使用变量。定义变量时,只要在一行的开始写下这个变量的名字,后面跟一个等号,等号右边写上要设定的变量值即可;而后就可以在Makefile文件中

使用这个变量了,使用时要将变量写在一对圆括号中,并以“1.2.1 make命令的输入文件01

”号作为前导符。[例1 8]

OBJECTS=main.o file1.o file2.o file3.o

定义名为OBJECTS的变量,变量值为一串目标文件名。要引用此变量,应使用1.2.1 make命令的输入文件02(OB-JECTS)。Makefile文件中的变量主要用在以下几个方面:

1.存贮依赖文件列表

通常,依赖文件列表既会出现在依赖行冒号的右边,也可能作为命令行的输入文件。在此情况下,最好将依赖文件列表定义到某变量中,并以该变量替换掉Makefile文件中所有出现过此列表的地方。这样做的目的,一方面可以避免重复写入长的依赖文件列表,从而降低

出错的机率;另一方面也能方便修改此列表,修改时只要改动变量定义一处就可以了。

[例1 9] 某Makefile文件中可能含有如下内容:附表

2.存贮多个同类目标

有时,为了生成最终目标,需要先生成多个同类的中间目标(在此,“同类”指具有相同后缀的文件,如a.o与b.o为同类,a.c与b.c为同类), 每个中间目标都是用各自的源文件(如:*.c)独立编译而成。对此,可以将这些中间文件定义到一个变量中,并引用此变量作为规则目标,从而实现用一条规则创建多个同类目标的目的。

[例1 10]附表

3.存贮命令名

当项目需要创建到多种平台上,而不同平台上创建目标的命令又不尽相同时,可以将创建目标的命令写到一个变量中,相关命令行通过引用此变量创建目标。这样在转到另一平台时,只要将Makefile文件中此变量值改为新平台上的相应命令,就可以在此平台上顺利创建目标了。

[例1 11] Makefile文件中有如下内容:附表

此例中,使用变量CC指定编译器命令。这样,当将此项目用到一个非GNU的系统中时,只要将CC变量的值由gcc改为cc就可以了。

4.存贮命令选项及参数

当要给多条命令传递一组相同的选项时,可以将这些选项和参数存入一个变量中,通过变量引用使用它们。而当想要修改其中的选项或参数时,就只要改变这个变量的值。

[例1 12] 某Makefile文件中含有如下内容:附表

除定义的变量外,Makefile文件中还可以使用内部变量。Makefile文件中的内部变量可以分为两类:(1)第一类内部变量具有缺省值,但允许在Makefile文件中重新赋值。如:①CFLAGS:内定为C编译器选项;

②CXXFLAGS:内定为C++编译器选项;③CPPFLAGS:内定为C预处理器选项。(2)第二类内部变量必须根据规则内容确定其值,不能由用户自行赋值。如:

①1.2.1 make命令的输入文件03

@:代表当前目标的全名;②1.2.1 make命令的输入文件04

<:针对隐含规则产生的命令,代替导致特定动作发生的相关文件的名称;③1.2.1 make命令的输入文件05

^:扩展成依赖文件的列表。

第一类内部变量的定义及引用方法与用户自定义的变量相同;第二类内部变量不能由用

户定义,使用时直接引用变量名,不必加1.2.1 make命令的输入文件06

和圆括号。[例1 13] CFLAGS=-Wall-O-g附表

1.2.1.3 Makefile文件示例

以下列出某Makefile文件的内容,为便于说明,加上行号。附表

在此Makefile文件中:(1)1~3行定义变量:

①SOURCES变量定义源文件a.c和b.c;

②OBJECTS变量定义目标文件a.o和b.o,它们都属于中间目标,最终目标为myprog;③CC变量指定编译器为gcc。(2)4~5行设定规则来创建目标myprog。因为没有创建中间目标的规则,gcc将运用

隐含规则(如.c.o)创建a.o和b.o。(3)6~7行利用编译器gcc的-MM选项生成a.o和b.o的依赖行,并写入depends文件中。(4)第8行的功能类似于C语言中的预处理指令#include。make在执行此行时,会将其后列出的文件( depends)内容包含到Makefile文件中。1.2.2 gnumake的使用

在编写完make命令的输入文件后,就可以运行make命令,创建/更新指定的目标了。

1.2.2.1 make命令的使用

make命令的调用格式为:

make[选项]

[参数]

其中:选项和参数都是可选的。make命令的常用选项及参数有:(1)“目标”参数:用户可以在make命令行指定要创建/更新的目标,此目标必须是Makefile文件中的有效目标(包括真实目标和假象目标);如未指定,make将创建/更新Makefile文件中的第一个目标。(2)“变量赋值”参数:用户可以在make命令行中重新指定变量值。附表

运行时,make命令将按如下顺序为变量赋值:①内部变量定义;

②环境变量定义;

③Makefile文件中的变量定义;

④make命令行中的“变量赋值”参数。

当同一变量在上面多处被赋值时,以最后的赋值为准。(3)-e选项:此选项改变make命令的变量赋值顺序为:①内部变量定义;

②Makefile文件中的变量定义;③环境变量定义;

④make命令行的“变量赋值”参数;(4)-f选项:当make命令的输入文件不是以Makefile或makefile命名时,用户必须在命令行中用此选项指定;否则make将只查找Makefile和makefile文件。(5)-r选项:此选项禁止make运用隐含规则。(6)-n选项:此选项指示make输出用于创建/更新目标的命令序列,但实际上并未真正执行这些命令。(7)-I选项:忽略出错信息。(8)-P选项:此选项使make命令试图以并行方式一次创建多个目标。make并行创建—16—

目标的数目由环境变量PARALLEL决定;如果使用了-P选项,但没有设置PARALLEL环境变量或此变量为空,则make命令并行创建的目标不会超过两个。要禁止make并行创建目标,用户可在Makefile文件中用.MUTEX关键字指定要求串行创建的目标。

1.2.2.2 make命令的工作过程

make命令的工作过程如下:(1)读进输入文件,找到要创建/更新的目标规则。(2)检查规则目标与依赖文件列表的时间戳信息;如果目标尚未创建或者存在比规则目标更新的依赖文件,则说明目标需要创建/更新,继续执行步骤(3)。否则,认为目标最新,终止make命令的运行。(3)检查目标依赖文件是否需要更新;方法是以依赖文件(暂称为“顶级依赖文件”)为目标,查找创建/更新这些文件的规则,检查这些文件与其依赖文件(暂称为“次级依赖文件”)的时间戳信息;如果确定顶级依赖文件需要创建/更新,则继续查找生成次级依赖文件的规则,并按同样的时间戳原则确定次级依赖文件是否需要被更新,依此类推,直至到达某条规则,其所有依赖文件均已为最新;然后,make将按照规则的查找顺序反向执行规则,完成目标的创建/更新。

[例1 14] 考虑下面的Makefile文件。附表

例1 14 是一个相当简单的 Makefile文件,只含有三条规则。为创建 myprog目标,make先检查myprog规则,只要myprog文件不存在或比a.o、b.o中的任何一个旧,myprog就要被创建/更新。在创建/更新myprog之前,make会继续查找以a.o、b.o为目标的规则。当找到a.o规则后,make检查a.o依赖文件的时间戳。如果这些文件( a.c、a.h、b.h)中的任何一个比a.o新或者a.o不存在,命令gcc-ca.c就会被执行,从而创建/更新a.o文件。接下来对文件b.o做类似的检查,其依赖文件为b.c和b.h。在a.o和b.o均为最新的情况下,make返回 myprog规则,执行“gcca.ob.o-omyprog”命令创建/更新 myprog目标。1.3 autoconf

autoconf是一个功能强大的GNU工具软件,主要面向Linux上的软件开发人员。它的作用是为软件的源码包生成自动配置脚本,使软件能不加修改地运行在多种Unix(Linux是一种特殊的Unix)平台上。

由autoconf生成的自动配置脚本是一个 shell脚本,约定命名为 configure。运行 con-

figure,可以检测出用户系统上同软件相关的特性,并由此配置软件,保证软件在用户系统上的顺利运行。

由autoconf生成的configure并不需要autoconf来支持它的运行;而且,软件的发行包中也通常不会包含autoconf。所以,如果用户仅作为软件的使用者,可以不去掌握autoconf;但若是软件的开发者,希望本节的内容会对用户有所帮助。

要为一个软件源码包生成configure脚本,除autoconf外,用户还需要准备configure.in、aclocal.m4和acsite.m4三个文件。这三个文件中,只有configure.in是生成configure脚本所必需的;aclocal.m4和acsite.m4根据软件需要,可能有也可能没有。将这些文件作为auto-conf的输入文件,即可产生configure脚本(图1 2)。1.3 autoconf01

图1 2 configure脚本生成示意图1.3.1 configure.in文件的获得

1.3.1.1 configure.in文件的内容

configure.in文件由一系列宏调用组成,这些宏包括autoconf宏、automake宏(关于au-tomake,具体参见本章第四节)及用户自定义宏等;其中大部分宏用于检测软件所需的系统特性(本节统称这些宏为测试宏)。

不同软件要求测试的特性不同,相应的configure.in文件的内容也就不同,但都必须包含AC_INIT宏和AC_OUTPUT宏:

AC_INIT宏负责处理自动配置脚本configure的命令行参数,并查找软件源码所在的目录。调用格式为:

AC_INIT(file)

其中:file为软件源码包中的某个文件;

AC_INIT就是通过查找file来确证软件源码包路径的正确性。

AC_OUTPUT宏负责创建自动配置脚本configure的输出文件。调用格式为:AC_OUTPUT(file…)

其中:file…是一系列以空格分隔的文件名,可以为空;

相应于file…中的每个文件在源码包中都会有一个file.in文件存在,AC_OUTPUT利用测试宏的测试结果,代换file.in文件中的某些变量(即下文所指的输出变量),产生输出文件file。另外,AC_OUTPUT还会检查另外三个autoconf宏(即:AC_CONFIG_HEADER、AC_LINK_FILES和AC_CONFIG_SUBDIRS) 是否被调用,如果被调用,AC_OUTPUT也会产生由这三个宏的参数所指定的文件。

configure.in文件对其内宏调用的顺序基本不作要求,但有少数几种情况例外:—18—(1)AC_INIT必须在所有测试宏之前调用;(2)AC_OUTPUT必须在其他宏之后调用;(3)当某些宏需要依赖另一些宏时,后者必须先于前者调用;根据这些规定,推荐configure.in文件中的宏调用顺序如下:(1)AC_INIT(file);(2)程序测试宏段;(3)库测试宏段;(4)头文件测试宏段;(5)类型定义测试宏段;(6)结构测试宏段;(7)编译器特性测试宏段;(8)库函数测试宏段;(9)系统服务测试宏段;

(10)AC_OUTPUT(file…).

autoconf为每个测试宏段都提供了多种测试宏;为节约篇幅,在此只列出主要宏名,不过多解释,详细信息可参看autoconf的相关资料。

程序测试宏段:此段中的宏用于检测指定的程序是否存在。具体包括:(1)AC_DECL_YYTEXT;

(2)AC_PROG_AWK;(3)AC_PROG_CC;

(4)AC_PROG_CC_C_O;(5)AC_PROG_CPP;

(6)AC_PROG_CXX;

(7)AC_PROG_CXXCPP;(8)AC_PROG_F77;

(9)AC_PROG_F77_C_O;

(10)AC_PROG_GCC_TRADITIONAL;(11)AC_PROG_INSTALL;

(12)AC_PROG_LEX;(13)AC_PROG_LN_S;(14)AC_PROG_RANLIB;(15)AC_PROG_YACC;(16)AC_CHECK_FILE;

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载