《Linux/UNIX系统编程手册(上、下册)》——1.3 标准化

简介: 20世纪80年代末,可用的UNIX实现层出不穷,由此也带来了种种弊端。有些UNIX实现基于BSD,而另一些则基于System V,还有一些则是对两大“流派”“兼容并蓄”。更有甚者,每个厂商都在自己的UNIX实现中添加了额外特性。

本节书摘来自异步社区《Linux/UNIX系统编程手册(上、下册)》一书中的第1章,第1.3节,作者:【德】Michael Kerrisk著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.3 标准化

20世纪80年代末,可用的UNIX实现层出不穷,由此也带来了种种弊端。有些UNIX实现基于BSD,而另一些则基于System V,还有一些则是对两大“流派”“兼容并蓄”。更有甚者,每个厂商都在自己的UNIX实现中添加了额外特性。其结果是将软件及技术人员在不同UNIX实现间转移就变得异常困难。这一形式有力地推动了C语言和UNIX系统的标准化进程,使得应用程序能够在不同操作系统间很方便地进行移植。接下来,将介绍由此而产生的各种标准。

1.3.1 C编程语言
20世纪80年代初,C语言问世已达10年之久,在大量UNIX系统以及其他操作系统上都有实现。各种C语言的实现之间存在着细微差别,这部分是由于在当时C语言事实上的标准——Kernighan和Ritchie于1978年所著的The C Programming Language一书中(有时,人们将书中所记载的老式C语言语法称为传统C或K&R C),并未就C语言在某些方面的运作方式进行细化。此外,借鉴于1985年面世的C++语言,在不破坏现有程序的前提下,C语言得以进一步丰富和完善,其中最知名的莫过于函数原型、结构赋值、类型限定符(const and volatile)、枚举类型以及void关键字。

上述因素形成了C语言标准化进程的强力推手,ANSI(美国国家标准委员会)C语言标准(X3.159-1989)最终于1989年获批,随之于1990年被ISO(国际标准化组织)所采纳(ISO/IEC 9899:1990)。这份标准在定义C语言语法和语义的同时,还对标准C语言库操作进行了描述,这包括stdio函数、字符串处理函数、数学函数、各种头文件等等。通常将C语言的这一版本称为C89或者(不太常见的)ISO C90,Kernighan和 Ritchie所著的The C Programming Language第2版(1988)对其有完整描述。

1999年,ISO又正式批准了对C语言标准的修订版。通常将这一标准称为C99,其中包括了对C语言及其标准库的一系列修改,诸如,增加了long long和布尔数据类型、C++风格的注释(//)、受限指针以及可变长数组等。写作本书之际,对C语言标准的进一步修订(非正式命名为C1X)仍在进行之中,预计将于2011年正式获批。

C语言标准独立于任何操作系统,换言之,C语言并不依附于UNIX系统。这也意味着仅仅利用标准C语言库编写而成的C语言程序可以移植到支持C语言实现的任何计算机或操作系统上。

回顾历史,过去的ANSI C通常指C89,时至今日,这一用法还时有所见。GCC就是一例,其限定符-ansi意指“支持所有ISO C90程序”。然而,本书会避免这种用法,因为如今该术语的含义有些含糊不清。自从ANSI委员会批准了C99修订版之后,确切说来,现在的ANSI C应该是C99。
1.3.2 首个POSIX标准
术语“POSIX(可移植操作系统Portable Operating System Interface的缩写)”是指在IEEE(电器及电子工程师协会),确切地说是其下属的可移植应用标准委员会赞助下所开发的一系列标准。PASC标准的目标是提升应用程序在源码级别的可移植性。

POSIX之名来自于Richard Stallman的建议。最后一个字母之所以是“X”是因为大多数UNIX变体之名总以“X”结尾。该标准特别注明,POSIX应发音为“pahz-icks”,类似于“positive”。
本书会关注名为POSIX.1的第一个POSIX标准,以及后续的POSIX.2标准。

POSIX.1和POSIX.2
POSIX.1于1989年成为IEEE标准,并在稍作修订后于1990年被正式采纳为ISO标准(ISO/ IEC 9945-1:1990)。无法在线获得这一POSIX标准,但能从IEEE购得。

POSIX.1一开始是基于一个更早期的(1984年)非官方标准,由名为/usr/group的UNIX厂商协会制定。
符合POSIX.1标准的操作系统应向程序提供调用各项服务的API,POSIX.1文档对此作了规范。凡是提供了上述API的操作系统都可被认定为符合POSIX.1标准。

POSIX.1基于UNIX系统调用和C语言库函数,但无需与任何特殊实现相关。这意味着任何操作系统都可以实现该接口,而不一定要是UNIX操作系统。实际上,在不对底层操作系统大加改动的同时,一些厂商通过添加 API 已经使自己的专有操作系统符合了 POSIX.1标准。

对原有POSIX.1标准的若干扩展也同样重要。正式获批于1993年的IEEE POSIX 1003.1b(POSIX.1b,原名POSIX.4或POSIX 1003.4)包含了一系列对基本POSIX标准的实时性扩展。正式获批于1995年的IEEE POSIX 1003.1c(POSIX.1c)对POSIX线程作了定义。1996年,一个经过修订POSIX.1版本诞生,在核心内容保持不变的同时,并入了实时性和线程扩展。IEEE POSIX 1003.1g(POSIX.1g)定义了包括套接字在内的网络API。分别获批于1999年和2000年的IEEE POSIX 1003.1d(POSIX.1d)和POSIX.1j在POSIX基本标准的基础上,定义了附加的实时性扩展。

POSIX.1b实时性扩展包括文件同步、异步I/O、进程调度、高精度时钟和定时器、采用信号量、共享内存,以及消息队列的进程间通信。这3种进程间通信方法的称谓前通常冠以POSIX,以示其有别于与之类似而又较为古老的System V信号、共享内存以及消息队列。
POSIX.2(1992,ISO/IEC 9945-2:1993)这一与POSIX.1相关的标准,对shell和包括C编译器命令行接口在内的各种UNIX工具进行了标准化。

F151-1和FIPS 151-2
FIPS 是Federal Information Processing Standard(联邦信息处理标准)的缩写,这套标准由美国政府为规范其对计算机系统的采购而制定。FIPS 151-1于1989年发布。这份标准基于1988年的IEEE POSIX.1标准和ANSI C语言标准草案。FIPS 151-1和POSIX.1(1988)之间的主要差别在于:某些对后者来说是可选的特性,对于前者来说是必须的。由于美国政府是计算机系统的“大买家”,大多数计算机厂商都会确保其UNIX系统符合FIPS 151-1版本的POSIX.1规范。

FIPS 151-2与POSIX.1的1990 ISO版保持一致,但在其他方面则保持不变。2000年2月,已然过时的FIPS 151-2标准被废止。

1.3.3 X/Open公司和The Open Group
X/Open公司是由多家国际计算机厂商所组成的联盟,致力于采纳和改进现有标准,以制定出一套全面而又一致的开放系统标准。该公司编纂的《X/Open 可移植性指南》是一套基于POSIX标准的可移植性指导丛书。这份指南的首个重要版本是1989年发布的第三号(XPG3),XPG4随之于1992年发布。1994年,X/Open又对XPG4做了修订,从而诞生了XPG4版本2,其中吸收了1.3.7节所述AT&T System V接口定义第三号中的重要内容。也将这一修订版称为Spec 1170,而1170是指标准中所定义的接口(函数、头文件及命令)数量。

1993年初,Novell从AT&T收购了UNIX系统的相关业务,又在稍后放弃了这项业务,并将UNIX商标权转让给了X/Open。(这一转让计划公布于1993年,但法律限制将这一转让推迟到1994年初。)随后,X/Open又将XPG4版本2“重新包装”为SUS(Single UNIX Specification)(有时,也叫SUSv1)或称之为UNIX95。其内容包括:XPG4版本2,X/Open Curses规范第4号版本2,以及X/Opena联网服务(XNS)规范第4号。SUS版本2发布于1997年,人们也将经过该规范认证的UNIX实现称为UNIX 98。(有时,该规范也被称之为XPG5。)

1996年,X/Open与开放软件基金会(OSF)合并,成立The Open Group。如今,几乎每家与UNIX系统有关的公司或组织都是The Open Group的会员,该组织持续着对API标准的开发。

OSF是20世纪80年代末UNIX纷争期间成立的两家厂商联盟之一。OSF的主要成员包括Digital、IBM、HP、Apollo、Bull、Nixdorf和Siemens。OSF成立的主要目的是为了应对由AT&T(UNIX的发明者)和SUN公司(UNIX工作站市场的领跑者)结盟所带来的威胁。随之,AT&T、SUN和其他公司结成了与OSF对抗的UNIX International联盟。
1.3.4 SUSv3和POSIX.1-2001
始于1999年,出于修订并加强POSIX标准和SUS规范的目的,IEEE、Open集团以及ISO/ IEC联合技术委员会共同成立了奥斯丁公共标准修订工作组。(该工作组的首次会议于1998年9月在德州奥斯丁召开,这也是奥斯丁工作组名称的由来。)2001年12月,该工作组正式批准了POSIX 1003.1-2001,有时简称为POSIX.1-2001(随后,又获批为ISO标准:ISO/IEC 9945:2002)。

POSIX 1003.1-2001取代了SUSv2、POSIX.1、POSIX.2以及大批的早期POSIX标准。有时,人们也将该标准称为Single Unix Specification版本3,本书在后续内容中将称其为SUSv3。

SUSv3基本规范约有3700页,分为以下4部分。

基本定义(XBD),包含了定义、术语、概念以及对头文件内容的规范。总计提供了84个头文件的规范。
系统接口(XSH),首先介绍了各种有用的背景信息。主要内容包含对各种函数(在特定的UNIX实现中,这些函数要么是作为系统调用,要么是作为库函数来实现的)的定义。总计包括了1123个系统接口。
Shell和实用工具(XCU),明确定义了shell和各种UNIX命令的行为。总共定义了160个实用工具的行为。
基本原理(XRAT),包括了与前三部分有关的描述性文字和原理说明。
此外,SUSv3还包含了X/Open CURSES第4号版本2(XCURSES)规范,该规范针对curses屏幕处理API定义了372个函数和3个头文件。

在SUSv3中共计定义了1742个接口。与之形成鲜明对照的是,POSIX.1-1990(连同FIPS 151-2)定义了199个接口,POSIX.2-1992定义了130个实用工具。

自SUSv3获批以来,人们针对规范文本中所发现的问题进行了多次小规模的修复和改进。因此而诞生的1号技术勘误表并入了2003年发布的SUSv3修订版,而2号技术勘误表的改进成果则并入了SUSv3 2004修订版。

符合POSIX、XSI规范和XSI扩展
回顾历史,SUS(和XPG)标准顺应了相应POSIX标准,并被组织为POSIX的功能超集。除了对许多额外接口作出规范外,SUS标准还将诸多被POSIX视为可选的接口和行为规范作为必备项。

对于身兼IEEE标准和OPEN集团技术标准的POSIX 1003.1-2001来说(如前所述,POSIX 1003.1-2001是由早期的POSIX和SUS标准合并而成),上述区别的存在方式更显微妙。该文档定义了对规范的两级符合度。

POSIX规范符合度,就符合该规范的UNIX实现所必须提供的接口定义了基线。规范允许符合度达标的UNIX实现提供其他可选接口。
XSI(X/Open系统接口[X/Open System Interface])规范符合度,对UNIX实现来说,要想完全符合XSI规范,除了必须满足POSIX规范的所有规定之外,还要提供若干POSIX规范中的可选接口和行为。只有这一规范符合度达标,才能从OPEN GROUP获得UNIX03称号。
人们将XSI规范符合度达标所需的额外接口和行为统称为XSI扩展。这些扩展支持以下特性:线程、mmap()和munmap()、dlopen API、资源限制、伪终端、System V IPC、syslog API、poll()以及登录记账。

后续各章所言及的“符合SUSv3规范”是指“符合XSI规范”。

由于POSIX和SUSv3目前由同一份文档描述,故而在文档的正文中,对于满足SUSv3符合度所需的额外接口和强制选项都以阴影和边注形式加以标明。
未定义和未明确定义的接口
有时,我们会称某些接口在SUSv3中“未定义”或“未明确定义”。

未定义的接口是指尽管偶尔会在背景和原理描述中提及,却根本未经正式标准定义过的接口。

未明确定义的接口是指标准虽然包括了该接口,但却未对其重要细节进行规范。(通常是由于现有接口的实现差异导致标准委员会成员无法达成一致性意见。)

“未定义”或“未明确定义”的接口一经使用,在不同UNIX实现间移植应用就很难得到保证。尽管如此,少数此类接口在不同实现下的表现又相当一致。针对这些接口,本书通常会在提及时一一指出。

LEGACY(传统)特性
书中有时会指出SUSv3将某个特定特性标记为LEGACY。这一术语意味着保留此特性意在与老应用程序保持兼容,而在新应用程序中应避免使用。这也是标准对此特性的限制所在。大多数情况下,都能找到与LEGACY特性等效的其他API。

1.3.5 SUSv4和POSIX.1-2008
2008年,奥斯丁工作组完成了对已合并的POSIX和SUS规范的修订工作。较之于之先前版本,该标准包含了基本规范以及XSI扩展。人们将这一修订版本称为SUSv4。

与SUSv3的变化相比,SUSv4的变化范围不算太大。最显著的变化如下所示。

SUSv4为一系列函数添加了新规范。本书将会介绍以下新标准中定义的如下函数:dirfd()、fdopendir()、fexecve()、futimens()、mkdtemp()、psignal()、strsignal()以及utimensat()。另一组与文件相关的函数,例如:openat(),参见18.11节,和现有函数,例如:open(),功能相同,其区别在于前者对相对路径的解释是相对于打开文件描述符的所属目录而言,而非相对于进程的当前工作目录。
某些在SUSv3中被定义为可选的函数在SUSv4中成为基本标准的必备部分。例如,某些原本在SUSv3中属于XSI扩展的函数,在SUSv4中转而隶属于基本标准。在SUSv4中转变为必备的函数中包括了dlopen API(42.1节)、实时信号API(22.8节)、POSIX信号量API(53章)以及POSIX定时器API(23.6节)。
SUSv4废止了SUSv3中的某些函数,这包括asctime()、ctime()、ftw()、gettimeofday()、getitimer()、setitimer()以及siginterrupt()。
SUSv4删除了在SUSv3中被标记为作废的一些函数,这包括 gethostbyname()、 gethostbyaddr()以及vfork()。
SUSv4对SUSv3现有规范的各方面细节进行了修改。例如,对于应满足异步信号安全(async-signal-safe)的函数列表,二者内容就有所不同(见表21-1)。
本书后文会就所论及的相关主题指出其在SUSv4中的变化。

1.3.6 UNIX标准时间表
图1-1总结了上述各节所述及各种标准之间的关系,并按时间顺序对标准进行了排列。图中的实线表示标准间的直接过渡,虚线则表示标准间有一定的瓜葛,这无非有两种情况:其一,一个标准被并入了另一标准;其二,一个标准依附于另一个标准。
screenshot

在网络标准方面,情况稍微有些复杂。该领域的标准化工作始于20世纪80年代末期,成立了POSIX 1003.12委员会,对套接字API、XTI(X/Open传输接口)API(另一套基于System V传输层接口的网络编程API)以及各种相关的API进行规范。该标准的酝酿历时数年,并于2000年获得了批准。其间,POSIX 1003.12被更名为POSIX 1003.1g。

在开发POSIX 1003.1g的同时,X/Open也在开发自己的X/Open网络规范(XNS)。该规范的第一版XNS第4号隶属于SUS首版。其后继版本为XNS第5号,隶属于SUSv2。XNS第5号与当时的POSIX.1g草案(6.6)基本相同。紧随其后的XNS第5.2号与XNS第5号以及获批为标准的POSIX.1g有所不同,将XTI API标记为作废,并纳入了于20世纪90年代中期开发出的IPv6。XNS第5.2号构成了SUSv3中网络编程相关内容的基础,如今已被取代。出于类似原因,POSIX.1g在获批后不久也退出了历史舞台。

1.3.7 实现标准
除了由独立或多边组织所制定的标准以外,有时,人们也会提到由4.4BSD(BSD的最终版)和SVR4(AT&T的System V Release 4)所定义的两种实现标准。后者随AT&T所发布的SVID(System V定义)而正式出台。1989年,AT&T发布了SVID第3号,定义了自称为System V Release 4的UNIX实现所必须提供的接口。

在BSD和SVR4之间,某些系统调用和库函数的行为各不相同,因此,许多UNIX实现都提供了兼容函数库和条件编译工具,可仿效并非特定UNIX实现“本色”的任意一种UNIX特性(请参见3.6.1节)。这减轻了从另一UNIX实现移植应用程序的负担。
1.3.8 Linux、标准、Linux标准规范(Linux Standard Base)
遵守各种UNIX标准,尤其是符合POSIX和SUS规范,是Linux(即内核、glibc以及工具)开发的总体目标。可是,在写作本书之际,尚无Linux发行版被The Open group授予“UNIX”商标。造成这一问题的主要原因不外乎是时间和费用。为了获得这一冠名,每个厂商的发行版都要经受规范符合度检查,每当有新的发行版诞生,还需重复执行上述检查。不过,正是由于Linux实际上几近于符合各种UNIX标准,才令其在UNIX市场上如此成功。

对于大多数商业UNIX实现来说,都是由同一家公司来开发和发布操作系统的。Linux则有所不同,其实现与发行是分开的,多家组织——无论是商业性质还是非商业性质——都握有Linux的发行权。

Linus Torvalds并不参与或支持任一特定Linux发行版的发行。然而,就参与Linux开发的其他人而言,情况更为复杂。许多从事Linux内核及其他自由软件项目开发的人员要么受雇于各家Linux发行商,要么就职于对Linux抱有浓厚兴趣的某些公司(诸如IBM和HP)。这些公司允许其程序员为特定Linux项目的开发投入一定的工作时间,这虽然对Linux的发展方向有所影响,但还没有哪家公司能够真正左右Linux的开发。更何况,很多参与Linux和GUN项目的其他开发者都是义工。

写作本书之际,Torvalds受雇成为Linux基金会会员,该基金会是一家由多个商业和非商业组织组成的非赢利性联盟,旨在推动Linux的成长。
由于Linux的发行商众多,并且内核的开发者又无法控制Linux发布版的内容,因此还没有诞生“标准”的商业Linux。一般情况下,每家Linux发行商所提供的内核都是基于某特定时间点发布的主要内核(比如Torvalds)版本的快照,最多不过针对其打上几个补丁。发行商普遍认为,这些补丁所提供的特性可以在一定程度上迎合商业需求,从而能够提高市场竞争力。在某些情况下,主要内核版本稍后会打上这些补丁。实际上,某些新内核特性最初正是由某个Linux发行商开发而成,最终被纳入主要内核版本之前,这些新特性早已随着发行商的Linux发布版销售了。例如,被正式纳入主线2.4内核版本之前,版本3的Reiserfs日志文件服务器已经随着某些Linux发布版销售很长时间了。

上面的论述所要说明的就是由不同Linux发行公司提供的系统(往往)存在(细微的)差别。这使人在一定程度上不禁想起在 UNIX 发展之初,其实现方面所存在的各种差异。为了保证不同 Linux 发布版之间的兼容性,LSB 付出了不懈的努力。为了达成上述愿望,LSB开发并推广了一套Linux系统标准,其主要目的是用来确保让二进制应用程序(即编译过的程序)能够在任何符合LSB规范的系统上运行。

由LSB所推广的二进制可移植性与POSIX所推广的源码可移植性可谓“一时瑜亮”。源码可移植性是指以C语言编写的程序可在任何符合POSIX规范的系统上编译并运行。而二进制可移植性则要苛刻得多,通常,只要硬件平台不一,便无法实现。二进制可移植性允许我们在某特定平台上将程序一次编译“成型”,然后,便可在任何符合LSB标准的Linux实现上运行该编译好的程序,当然,符合LSB标准的Linux实现必须运行在相同的硬件平台之上。对于在 Linux 上开发应用程序的独立软件开发商来说,二进制可移植性是其生存的基本前提。

相关文章
|
28天前
|
算法 Linux C++
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
【Linux系统编程】解析获取和设置文件信息与权限的Linux系统调用
29 0
|
28天前
|
算法 Linux C++
【Linux系统编程】深入解析Linux中read函数的错误场景
【Linux系统编程】深入解析Linux中read函数的错误场景
202 0
|
28天前
|
Linux API C语言
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
34 0
【Linux系统编程】深入理解Linux 组ID和附属组ID的查询与设置
|
1月前
|
存储 Shell Linux
【Shell 命令集合 网络通讯 】Linux 显示Unix-to-Unix Copy (UUCP) 系统的状态信息 uustat命令 使用指南
【Shell 命令集合 网络通讯 】Linux 显示Unix-to-Unix Copy (UUCP) 系统的状态信息 uustat命令 使用指南
26 0
|
28天前
|
存储 算法 Linux
【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录
【Linux系统编程】深入理解Linux目录扫描函数:scandir目录函数(按条件扫描目录
37 0
|
28天前
|
存储 算法 Linux
【Linux系统编程】Linux 文件系统探究:深入理解 struct dirent、DIR 和 struct stat结构
【Linux系统编程】Linux 文件系统探究:深入理解 struct dirent、DIR 和 struct stat结构
40 0
|
15天前
|
Linux 开发者
Linux文件编程(open read write close函数)
通过这些函数,开发者可以在Linux环境下进行文件的读取、写入和管理。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
84 4
|
20天前
|
Java Unix Linux
Linux系统常用命令速查手册
Linux系统常用命令速查手册
|
21天前
|
传感器 Linux API
嵌入式Linux串口编程简介
嵌入式Linux串口编程简介
18 1
|
22天前
|
Linux 测试技术 C语言
【Linux】应用编程之C语言文件操作
【Linux】应用编程之C语言文件操作