开元食味
德国频道
查看: 2945|回复: 11
打印 上一主题 下一主题

第一讲 Linux编程入门之 C 语言环境

[复制链接]
1#
发表于 28.11.2002 11:15:26 | 只看该作者
                       讲义下载:http://263.aka.org.cn/Lectures/001/Lecture-1/Lecture-1.zip<br>tgz:http://263.aka.org.cn/Lectures/001/Lecture-1/Lecture-1.tgz<br><br><br>第一讲 Linux编程入门之 C 语言环境 <br>整体思路<br>本讲是编程系列讲座的第一讲,主要讲述 Linux 平台上的 C 语言环境,包括编译器、 调试器、Make、Diff、Patch 等。其目的是通过介绍 Linux 上 C 语言编程的基本工具 以及一些新手必须掌握的技巧,迅速引导新手入门,以避免走弯路。<br>首先对 Linux 作一简单介绍,然后通过讲解 Linux 上进行编程的常识以及典型场景的 演示,使大家对 Linux 上的程序开发有一个感性认识。在此基础上,重点讲述 Linux 上 C 语言编程的基本工具,包括编译器和调试器,主要是它们的重要选项和基本用法。 接下来讲述在项目组织和开发过程中非常重要的工具,即 GNU make 和 makefile。 最后讲述 diff/patch 工具。 <br><br>主要内容<br> 什么是 Linux<br><br> Linux 的发展历史以及关键人物<br><br> Linux 与其他操作系统<br><br> Linux 的编程常识<br><br> Linux 上进行程序开发的典型场景<br><br> 程序和脚本<br><br> Linux 上的 C 编译器和调试器<br><br> GNU make 和 makefile<br><br> 实用工具<br><br>各部分要点<br> 1.1 什么是 Linux<br><br>Linux 的发音 <br>Linux 的官方定义 <br>OSIX 及其重要地位 <br>GNU 和 Linux 的关系 <br>GPL 及其主要内容 <br>Linux 的主要发行版 <br> 1.2 Linux 的发展历史以及关键人物<br><br>UNIX, GNU, Linux 的关键人物及贡献 <br>Linux 发展的重要里程碑 <br> 1.3 Linux 与其他操作系统<br><br>Linux 与主要 UNIX 系统之间的关系 <br>Linux 与 Windows 操作系统 <br> 1.4 Linux 的编程常识<br><br>标准 (ANSI C, POSIX, SVID, XPG, ...) <br>函数库和系统调用 <br>在线文档 (man, info, HOW-TO, ...) <br>C 语言编程风格 <br>库和头文件的保存位置 <br>共享库及其相关配置 <br> 1.5 Linux 上进行程序开发的典型场景<br><br>控制台上的开发场景 <br>X Window 上的开发场景 <br> 1.6 程序和脚本<br><br>程序:编写, 编译, 调试和执行 <br>脚本:编写, 执行 <br> 1.7 Linux 上的 C/C++ 编译器和调试器<br><br>运行 gcc/egcs <br>gcc/egcs 的主要选项 <br>gdb <br>gdb 的常用命令 <br>gdb 使用范例 <br>其他程序/库工具 (file, ar, objdump, nm, size, strings, strip, ...) <br>创建和使用静态库 <br>创建和使用共享库 <br>使用高级共享库特性 <br> 1.8 GNU make 和 makefile<br><br>GNU make <br>makefile 基本结构 <br>makefile 变量 <br>GNU make 的主要预定义变量 <br>隐含规则 <br>makefile 范例 <br>运行 make <br> 1.9 开发中常用的工具<br><br>正则表达式 <br>压缩和归档工具 (gzip, bzip2, tar, ...) <br>搜索和排序 (grep, find, sort, ...) <br>文件编辑 (sed, tr) <br>文件比较 (cmp, comm, diff, patch, ...) <br>其他 (ed, vim, emacs, ...) <br>练习<br>如果还没有安装 Linux 系统的话,请安装一种 Linux 发行版,并掌握 Linux 的基本使用。 <br>编写一个 Bash 脚本,用来将当前目录树中(递归)所有 DOS 格式的文本文件转换为 UNIX 格式的文本文件,新文件名称添加后缀 .unix。 <br>试着将自己在 DOS 或 Windows 下编写过的程序移植到 Linux,编译通过并测试正确性。 <br>从网上下载 CCE 或 MiniGUI 的源代码,然后研究其 Makefile 的结构。 <br>用 C 语言或自己喜欢的语言实现第 3 题。 <br>参考书目<br>hil Cornes, The Linux A - Z, Prentice Hall Europe, 1997.<br>(中译本已由电子工业出版社出版, 童寿彬等译) <br>Naba Barkakati, The Linux Secrets, IDG Books Worldwide, Inc. 1999.<br>(中译本已由电子工业出版社出版, 魏永明等译) <br>John Goerzen, The Linux Programming Bible, IDG Books Worldwide, Inc. 1999.<br>(中译本已由电子工业出版社出版, 魏永明等译) <br>进一步读物<br>W. Richard Stevens, Advanced Programming in the UNIX Environment, Chpater 1 and Chapter 2. <br>反馈<br>本讲由魏永明讲解。欢迎任何意见和建议,可发 email: ymwei@mail.minigui.org 与魏永明联系。                       
2#
 楼主| 发表于 28.11.2002 11:15:50 | 只看该作者
                         <br>1.1    什么是 Linux <br>Linux 的发音 <br><br>Linux 的官方定义 <br><br>OSIX 及其重要地位 <br><br>GNU 和 Linux 的关系 <br><br>GPL 及其主要内容 <br><br>Linux 的主要发行版 <br><br>1.1.1    Linux 的发音<br>Linux 发音为 &quot;Lin-noks&quot;.<br><br><br><br>1.1.2    Linux 的官方定义<br>Linux is a Unix clone written from scratch by Linus Torvalds with assistance from a loosely-knit team of hackers across the Net. It aims towards POSIX compliance. <br><br>“Linux 是一种 UNIX 操作系统的克隆,它(的内核)由 Linus Torvalds 以及网络上组织松散的黑客队伍一起从零开始编写而成。 Linux 的目标是保持和 POSIX 的兼容。 <br><br><br><br>It has all the features you would expect in a modern fully-fledged Unix, including true multitasking, virtual memory, shared libraries, demand loading, shared copy-on-write executables, proper memory management and TCP/IP networking. <br><br>“Linux 具备现代一切功能完整的 UNIX 系统所具备的全部特征,其中包括真正的多任务、虚拟内存、共享库、需求装载、共享的写时复制程序执行、优秀的内存管理以及 TCP/IP 网络支持等。 <br><br><br><br>It is distributed under the GNU General Public License. <br><br>“Linux 的发行遵守 GNU 的通用公共许可证。 <br><br><br><br>Linux was first developed for 386/486-based PCs. These days it also runs on ARMs, DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga), MIPS and PowerPC, and others. <br><br>“Linux 起初为基于 386/486 的 PC 机开发,但现在,Linux 也可以运行在 DEC Alpha、SUN Sparc、M68000,以及MIPS 和 PowerPC 等计算机上。” <br><br><br><br>1.1.3    POSIX 及其重要地位<br>OSIX 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX 是为了读音更像 UNIX)。电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX。许多其它的操作系统,例如 DEC OpenVMS 和 Microsoft Windows NT,都支持 POSIX 标准,尤其是 IEEE Std. 1003.1-1990(1995 年修订)或 POSIX.1,POSIX.1 提供了源代码级别的 C 语言应用编程接口(API)给操作系统的服务程序,例如读写文件。POSIX.1 已经被国际标准化组织(International Standards Organization,ISO)所接受,被命名为 ISO/IEC 9945-1:1990 标准。 <br><br>OSIX 现在已经发展成为一个非常庞大的标准族,某些部分正处在开发过程中。表 1-1 给出了 POSIX 标准的几个重要组成部分。POSIX 与 IEEE 1003 和 2003 家族的标准是可互换的。除 1003.1 之外,1003 和 2003 家族也包括在表中。 <br><br>表 1-1 POSIX 标准的重要组成部分 <br><br>1003.0 <br> 管理 POSIX 开放式系统环境(OSE)。IEEE 在 1995 年通过了这项标准。 ISO 的版本是 ISO/IEC 14252:1996。 <br> <br>1003.1 <br> 被广泛接受、用于源代码级别的可移植性标准。1003.1 提供一个操作系统的 C 语言应用编程接口(API)。IEEE 和 ISO 已经在 1990 年通过了这个标准,IEEE 在 1995 年重新修订了该标准。 <br> <br>1003.1b <br> 一个用于实时编程的标准(以前的 P1003.4 或 POSIX.4)。这个标准在 1993 年被 IEEE 通过,被合并进 ISO/IEC 9945-1。 <br> <br>1003.1c <br> 一个用于线程(在一个程序中当前被执行的代码段)的标准。以前是 P1993.4 或 POSIX.4 的一部分,这个标准已经在 1995 年被 IEEE 通过,归入 ISO/IEC 9945-1:1996。 <br> <br>1003.1g <br> 一个关于协议独立接口的标准,该接口可以使一个应用程序通过网络与另一个应用程序通讯。 1996 年,IEEE 通过了这个标准。 <br> <br>1003.2 <br> 一个应用于 shell 和 工具软件的标准,它们分别是操作系统所必须提供的命令处理器和工具程序。 1992 年 IEEE 通过了这个标准。ISO 也已经通过了这个标准(ISO/IEC 9945-2:1993)。 <br> <br>1003.2d <br> 改进的 1003.2 标准。 <br> <br>1003.5 <br> 一个相当于 1003.1 的 Ada 语言的 API。在 1992 年,IEEE 通过了这个标准。并在 1997 年对其进行了修订。ISO 也通过了该标准。 <br> <br>1003.5b <br> 一个相当于 1003.1b(实时扩展)的 Ada 语言的 API。IEEE 和 ISO 都已经通过了这个标准。ISO 的标准是 ISO/IEC 14519:1999。 <br> <br>1003.5c <br> 一个相当于 1003.1q(协议独立接口)的 Ada 语言的 API。在 1998 年, IEEE 通过了这个标准。ISO 也通过了这个标准。 <br> <br>1003.9 <br> 一个相当于 1003.1 的 FORTRAN 语言的 API。在 1992 年,IEEE 通过了这个标准,并于 1997 年对其再次确认。ISO 也已经通过了这个标准。 <br> <br>1003.10 <br> 一个应用于超级计算应用环境框架(Application Environment Profile,AEP)的标准。在 1995 年,IEEE 通过了这个标准。 <br> <br>1003.13 <br> 一个关于应用环境框架的标准,主要针对使用 POSIX 接口的实时应用程序。在 1998 年,IEEE 通过了这个标准。 <br> <br>1003.22 <br> 一个针对 POSIX 的关于安全性框架的指南。 <br> <br>1003.23 <br> 一个针对用户组织的指南,主要是为了指导用户开发和使用支持操作需求的开放式系统环境(OSE)框架 <br> <br>2003 <br> 针对指定和使用是否符合 POSIX 标准的测试方法,有关其定义、一般需求和指导方针的一个标准。在 1997 年,IEEE 通过了这个标准。 <br> <br>2003.1 <br> 这个标准规定了针对 1003.1 的 POSIX 测试方法的提供商要提供的一些条件。在 1992 年,IEEE 通过了这个标准。 <br> <br>2003.2 <br> 一个定义了被用来检查与 IEEE 1003.2(shell 和 工具 API)是否符合的测试方法的标准。在 1996 年,IEEE 通过了这个标准。 <br> <br><br>除了 1003 和 2003 家族以外,还有几个其它的 IEEE 标准,例如 1224 和 1228,它们也提供开发可移植应用程序的 API。要想得到关于 IEEE 标准的最新信息,可以访问 IEEE 标准的主页,网址是 <a href='http://standards.ieee.org/。有关' target='_blank'>http://standards.ieee.org/。有关</a> POSIX 标准的概述信息,请访问 Web 站点 <a href='http://standards.ieee.org/reading/ieee/stad_public/description/posix/。' target='_blank'>http://standards.ieee.org/reading/ieee/sta...iption/posix/。</a> <br><br>1.1.4    GNU 和 Linux 的关系<br>GNU 是 GNU Is Not UNIX 的递归缩写,是自由软件基金会的一个项目,该项目的目标是开发一个自由的 UNIX 版本,这一 UNIX 版本称为 HURD。尽管 HURD 尚未完成,但 GNU 项目已经开发了许多高质量的编程工具,包括 emacs 编辑器、著名的 GNU C 和 C++ 编译器(gcc 和 g++),这些编译器可以在任何计算机系统上运行。所有的 GNU 软件和派生工作均适用 GNU 通用公共许可证,即 GPL。GPL 允许软件作者拥有软件版权,但授予其他任何人以合法复制、发行和修改软件的权利。<br><br><br>Linux 的开发使用了许多 GNU 工具。Linux 系统上用于实现 POSIX.2 标准的工具几乎都是 GNU 项目开发的,Linux 内核、GNU 工具以及其他一些自由软件组成了人们常说的 Linux: <br><br>符合 POSIX 标准的操作系统 Shell 和外围工具。 <br>C 语言编译器和其他开发工具及函数库。 <br>X Window 窗口系统。 <br>各种应用软件,包括字处理软件、图象处理软件等。 <br>其他各种 Internet 软件,包括 FTP 服务器、WWW 服务器等。 <br>关系数据库管理系统等。 <br><br>1.1.5    GPL 及其主要内容<br>1. GPL (General Public License)<br>GPL 的文本保存在 Linux 系统的不同目录下的命名为 COPYING 的文件里。例如,键入 cd /usr/doc/ghostscript* 然后再键入 more COPYING 可查看 GPL 的内容。<br><br><br>GPL 和软件是否免费无关,它主要目标是保证软件对所有的用户来说是自由的。GPL 通过如下途径实现这一目标: <br><br>它要求软件以源代码的形式发布,并规定任何用户能够以源代码的形式将软件复制或发布给别的用户。 <br>它提醒每个用户,对于该软件不提供任何形式的担保。 <br>如果用户的软件使用了受 GPL 保护的任何软件的一部分,那么该软件就继承了 GPL 软件,并因此而成为 GPL 软件,也就是说必须随应用程序一起发布源代码。 <br>GPL 并不排斥对自由软件进行商业性质的包装和发行,也不限制在自由软件的基础上打包发行其他非自由软件。 <br>遵照 GPL 的软件并不是可以任意传播的,这些软件通常都有正式的版权,GPL在发布软件或者复制软件时声明限制条件。但是,从用户的角度考虑,这些根本不能算是限制条件,相反用户只会从中受益,因为用户可以确保获得源代码。<br><br><br>尽管 Linux 内核也属于 GPL 范畴,但 GPL 并不适用于通过系统调用而使用内核服务的应用程序,通常把这种应用程序看作是内核的正常使用。<br><br><br>假如准备以二进制的形式发布应用程序(像大多数商业软件那样),则必须确保自己的程序未使用 GPL 保护的任何软件。如果软件通过库函数调用而使用了别的软件,则不必受到这一限制。大多数函数库,受另一种 GNU 公共许可证,即 LGPL 的保护,将在下面介绍。 <br><br>2. LGPL (Libraray General Public License)<br>GNU LGPL(GNU 程序库公共许可证)的内容全部包括在命名为 COPYING.LIB 的文件中。如果安装了内核核的源程序,在任意一个源程序的目录下都可以找到 COPYING.LIB 文件的一个拷贝。<br><br><br>LGPL 允许在自己的应用程序中使用程序库,即使不公开自己的源代码。但是,LGPL 还规定,用户必须能够获得在应用程序中使用的程序库的源代码,并且允许用户对这些程序库进行修改。<br><br><br>大多数 Linux 程序库,包括 C 程序库(libc.a)都属于 LGPL 范畴。因此,如果在 Linux 环境下,使使用 GCC 编译器建立自己的应用程序,程序所链接的多数程序库是受 LGPL 保护的。如果想以二进制的形式发布自己的应用程序,则必须注意遵循 LGPL 有关规定。<br><br><br>遵循 LGPL 的一种方法是,随应用程序一起发布目标代码,以及可以将这些目标程序和受 LGPL 保护的、更新的 Linux 程序库链接起来的 makefile 文件。<br><br><br>遵循 LGPL 的比较好的一种方法是使用动态链接。使用动态链接时,即使是程序在运行中调用函数库中的函数时,应用程序本身和函数库也是不同的实体。通过动态链接,用户可以直接使用更新后的函数库,而不用对应用程序进行重新链接。<br><br><br>但我们必须当心个别属于 GPL 范畴的库和实用程序:篏NU dbm(即 gdbm)数据库类的程序库是非常著名的 GPL 库;GNU bison 分析器生成程序是另一个实用的 GPL 工具,如果使用 bison 生成代码,所得的代码也适用于 GPL。<br><br><br>在 GPL 的保护范围以外,也有 GNU dbm 和 GNU bison 的相应的替代程序。例如,对于数据库类的程序库库,可以使用 Berkeley 数据库 db 来替代 gdbm;对于分析器生成器,可以使用 yacc 来替代 bison。 <br><br>1.1.6 Linux 的主要发行版<br>表 1-2 给出了 Linux 的主要发行版。除表中列出的发行版之外,还有大量的发行版存在,比如 Slackware、OpenLinux、Mandrake 等等。建议新手使用 Red Hat Linux 或自己喜欢的某种本地化发行版。<br><br>表 1-2 Linux 的主要发行版 <br><br>Debian GNU/Linux<br> 系统初始化:Sys V init<br>采用 dselct 和 dpkg 作为软件包管理程序 <br> <a href='http://www.debian.org' target='_blank'>http://www.debian.org</a> <a href='ftp://ftp.debian.org/debian' target='_blank'>ftp://ftp.debian.org/debian</a> <br> 是由 GNU 发行的 Linux 版本,最符合 GNU 精神。提供了最大的灵活性, 适合 Linux 的高级用户。 <br> <br>Red Hat Linux<br> 系统初始化:Sys V init<br>采用 RPM 软件包管理工具<br>大量图形化的管理工具 <br> <a href='http://www.redhat.com' target='_blank'>http://www.redhat.com</a> <a href='ftp://ftp.redat.com' target='_blank'>ftp://ftp.redat.com</a> <br> CERNET 各大型的 FTP 网站均有最新的 RedHat Linux。<br>采用 RPM 的软件保管理方式,软件的安装、卸载和升级非常方便,并提供了大量的 图形化管理工具,是初学者的最佳选择。 <br> <br><br>简体中文 Linux 发行版:<br><br>BluePoint Linux:最新发布的 Linux 中文版。利用 Linux 2.2 内核的 FrameBuffer,可在控制台获得中文输入输出。具备多内码支持,目前可以支持大陆国标码和港台大五码。与 RedHat Linux 兼容。 <br>TurboLinux:国内最早的简体中文发行版之一。 <br>                       
3#
 楼主| 发表于 28.11.2002 11:16:31 | 只看该作者
                          <br>1.2  Linux 的发展历史以及关键人物<br><br>UNIX, GNU, Linux 的关键人物及贡献 <br><br>Linux 发展的重要里程碑 <br><br>1.2.1  UNIX, GNU, Linux 的关键人物及贡献<br>Ken Thompson, Dennis Ritchie:UNIX;60 年代末<br><br><br>Brian Kernighan, Dennis Ritchie:The C Programming Language;70 年代末<br><br><br>Richard Stallman:FSF,GNU,GPL,emacs,gcc;80 年代中<br><br><br>Andrew S. Tanenbaum:MINIX,Operating Systems: Design and Implementation; 80 年代末,90年代初<br><br><br>Linus Torvalds:Linux;90 年代<br><br>Eric Raymond:《黑客文化简史》,《如何成为一名黑客》,《大教堂和市集》,《开拓智域》,《魔法大锅炉》 <br><br>1.2.2  Linux 发展的重要里程碑<br>1990, Linus Torvalds 首次接触 MINIX<br><br>1991 中, Linus Torvalds 开始在 MINIX 上编写各种驱动程序等操作系统内核组件<br><br>1991 底, Linus Torvalds 公开了 Linux 内核<br><br>1993, Linux 1.0 版发行,Linux 转向 GPL 版权协议<br><br>1994, Linux 的第一个商业发行版 Slackware 问世????<br><br>1996, 美国国家标准技术局的计算机系统实验室确认 Linux 版本 1.2.13(由 Open Linux 公司打包)符合 POSIX 标准<br><br>1999, Linux 的简体中文发行版相继问世<br><br>2000 中, LinuxWorld China 2000 展览会召开,涌现大量基于 Linux 的嵌入式系统。<br><br>                       
4#
 楼主| 发表于 28.11.2002 11:18:43 | 只看该作者
                          <br>1.3  Linux 与其他操作系统<br><br><br>Linux 与主要 UNIX 系统之间的关系 <br><br>Linux 与 Windows 操作系统 <br><br>1.3.1  Linux 与主要 UNIX 系统之间的关系<br>UNIX 是七十年代由 AT&amp;&amp;;T 的 Bell 实验室开发的。Bell 实验室继续进行 UNIX 的开发工作,发行了几个版本的 UNIX:System V 第一版(SVR1)、SVR2、SVR3、SVR4 和后来的 System III。<br><br><br>在维护和发展 UNIX 过程中,Bell 实验室将 UNIX 的源代码向教育界公开。许多学校接受了 UNIX 的拷贝,并向操作系统增加了许多新特性,California 大学的 Berkeley 分校就是其中一个。最终,该学校发行了自己的 UNIX 版本,称为 Berkeley Software Distribution(BSD)UNIX。BSD UNIX 使用最广泛的版本是 4.3 和 4.4(称为 4.4BSD)。<br><br><br>到 4.4BSD UNIX 分布时,这个版本中已经很少有最初 Bell 实验室的 UNIX 代码了。不久,几个小组相继编写了新的代码,替换掉 Bell 实验室代码的剩余那部分,使 BSD UNIX 适合在 Intel 386 处理器上运行。这导致了用于 Intel PC 的免费的 BSD UNIX 的 FreeBSD 和 NetBSD 版本的出现。<br><br><br>Linux 不仅符合 POSIX 标准,而且还包括其它 UNIX 标准的多种特性,例如,UNIX 的 System V 接口文档(System V Interface Document,SVID)和伯克利软件发布(Berkeley Software Distribution,BSD)版本。Linux 采用了折衷的策略,包含了 UNIX 几个典型特性当中最实用的一些功能:<br><br>Linux 采用了 SVR4 的进程间通信(IPC)机制:共享内存、消息队列、信号灯 <br>Linux 支持 BSD Socket 网络编程接口 <br>许多 Linux 发行版采用 SysV init 机制,支持运行级别 <br>1.3.2  Linux 与 Windows 操作系统<br>开放与封闭 <br>大视野与小圈子 <br>创新与跟随 <br>                       
5#
 楼主| 发表于 28.11.2002 11:22:33 | 只看该作者
                          <br>   <br>1.4  Linux 的编程常识<br><br><br>标准 (ANSI C, POSIX, SVID, XPG, ...) <br><br>函数库和系统调用 <br><br>在线文档 (man, info, HOW-TO, ...) <br><br>C 语言编程风格 <br><br>库和头文件的保存位置 <br><br>共享库及其相关配置 <br><br>1.4.1  标准 (ANSI C, POSIX, SVID, XPG, ...)<br>ANSI C:这一标准是 ANSI(美国国家标准局)于 1989 年制定的 C 语言标准。 后来被 ISO(国际标准化组织)接受为标准,因此也称为 ISO C。<br>ANSI C 的目标是为各种操作系统上的 C 程序提供可移植性保证,而不仅仅限于 UNIX。 该标准不仅定义了 C 编程语言的语发和语义,而且还定义了一个标准库。这个库可以根据 头文件划分为 15 个部分,其中包括:字符类型 (&lt;ctype.h&gt;)、错误码 (&lt;errno.h&gt;)、 浮点常数 (&lt;float.h&gt;)、数学常数 (&lt;math.h&gt;)、标准定义 (&lt;stddef.h&gt;)、 标准 I/O (&lt;stdio.h&gt;)、工具函数 (&lt;stdlib.h&gt;)、字符串操作 (&lt;string.h&gt;)、 时间和日期 (&lt;time.h&gt;)、可变参数表 (&lt;stdarg.h&gt;)、信号 (&lt;signal.h&gt;)、 非局部跳转 (&lt;setjmp.h&gt;)、本地信息 (&lt;local.h&gt;)、程序断言 (&lt;assert.h&gt;) 等等。 <br>OSIX:该标准最初由 IEEE 开发的标准族,部分已经被 ISO 接受为国际标准。该标准的具体内容 见 1.1.3。POSIX.1 和 POSIX.2 分别定义了 POSIX 兼容操作系统的 C 语言系统接口 以及 shell 和工具标准。这两个标准是通常提到的标准。 <br>SVID:System V 的接口描述。System V 接口描述(SVID)是描述 AT&amp;&amp;;T Unix System V 操作 系统的文档,是对 POSIX 标准的扩展超集。 <br>XPG:X/Open 可移植性指南。X/Open 可移植性指南(由 X/Open Company, Ltd.出版), 是比 POSIX 更为一般的标准。X/Open 拥有 Unix 的版权,而 XPG 则指定成为 Unix 操作系统必须满足的要求。 <br>1.4.2  函数库和系统调用<br>1. glibc<br>众所周知,C 语言并没有为常见的操作,例如输入/输出、内存管理,字符串操作等提供内置的支持。相反,这些功能一般由标准的“函数库”来提供。GNU 的 C 函数库,即 glibc,是 Linux 上最重要的函数库,它定义了 ISO C 标准指定的所有的库函数,以及由 POSIX 或其他 UNIX 操作系统统变种指定的附加特色,还包括有与 GNU 系统相关的扩展。目前,流行的 Linux 系统使用 glibc 2.0 以上的版本。glibc 基于如下标准:<br><br>ISO C: C 编程语言的国际标准,即 ANSI C。 <br>OSIX:GNU C 函数库实现了 ISO/IEC 9945-1:1996 (POSIX 系统应用程序编程接口, 即 POSIX.1)指定的所有函数。该标准是对 ISO C 的扩展,包括文件系统接口原 语、设备相关的终端控制函数以及进程控制函数。同时,GUN C 函数库还支持部分由 ISO/IEC 9945-2:1993(POSIX Shell 和 工具标准,即 POSIX.2)指定的函数, 其中包括用于处理正则表达式和模式匹配的函数。 <br>Berkeley Unix:BSD 和 SunOS。GNU C 函数库定义了某些 UNIX 版本中尚未标准化的函数, 尤其是 4.2 BSD, 4.3 BSD, 4.4 BSD Unix 系统(即“Berkeley Unix”)以及“SunOS” (流行的 4.2 BSD 变种,其中包含有某些 Unix System V 的功能)。BSD 函数包括 符号链接、select 函数、BSD 信号处理函数以及套接字等等。 <br>SVID:System V 的接口描述。GNU C 函数库定义了大多数由 SVID 指定而未被 ISO C 和 POSIX 标准指定的函数。来自 System V 的支持函数包括进程间通信和共享内存、 hsearch 和 drand48 函数族、fmtmsg 以及一些数学函数。 <br>XPG:X/Open 可移植性指南。GNU C 函数库遵循 X/Open 可移植性指南(Issue 4.2) 以及所有的 XSI(X/Open 系统接口)兼容系统的扩展,同时也遵循所有的 X/Open Unix 扩展。 <br>2. 其他重要函数库<br>除 glibc 之外,流行的 Linux 发行版中还包含有一些其他的函数库,这些函数库具有重要地位,例如:<br><br>GNU Libtool:GNU Libtool 实际是一个脚本生成工具,它可以为软件包开发者提供一般性 的共享库支持。<br>以前,如果源代码包的开发者要利用共享库的优点,则必须为每个软件包可支持的平台编写 定制的支持代码。并且还需要设计配置接口,以便软件包的安装程序能够正确选择要建立的 库类型。利用 GNU Libtool,则可以简化开发者的这一工作。它在一个单独的脚本中同时封装 了与平台相关的依赖性以及用户界面。GNU Libtool 可使每个宿主类型的完整功能可通过 一般性的接口获得,同时为程序员隐藏了宿主的特殊性。GNU Libtool 一致性接口是可靠的, 用户不必阅读那些晦涩的文档,以便在每个平台上建立共享库。他们只需运行软件包的配置 脚本,而由 libtool 完成繁复的工作。 <br>CrackLib:CrackLib 为用户提供了一个 C 语言函数接口,利用这一函数,可避免用户选择 容易破解的密码。该函数库可在类似 passwd 的程序中使用。 <br>LibGTop:LibGTop 是一个能够获取进程信息以及系统运行信息的函数库,这些信息包括: 系统的一般信息、SYS V IPC 限制、进程列表、进程信息、进程映射、文件系统使用信息等。 <br>图形文件操作函数库:包括 libungif、libtiff、libpng、Imlib, libjpeg 等,可分别用来操作 GIF、TIFF、PNG、JPEG 以及其他一些格式图形文件。 <br>3. 系统调用<br>系统调用是操作系统提供给外部程序的接口。在 C 语言中,操作系统的系统调用通常通过函数调用的形式完成,这是因为这些函数封装了系统调用的细节,将系统调用的入口、参数以及返回值用 C 语言的函数调用过程实现。在 Linux 系统中,系统调用函数定义在 glibc 中。 <br><br>谈到系统调用时,需要注意如下几点:<br><br>系统调用函数通常在成功时返回 0 值,不成功时返回非零值。如果要检查失败原因,则 要判断 errno 这个全局变量的值,errno 中包含有错误代码。 <br>许多系统调用的返回数据通常通过引用参数传递。这时,需要在函数参数中传递一个 缓冲区地址,而返回的数据就保存在该缓冲区中。 <br>不能认为系统调用函数就要比其他函数的执行效率高。要注意,系统调用是一个非常耗时 的过程。 <br>有关系统调用我们将在以后详细讲述。 <br><br>1.4.3  在线文档 (man, info, HOW-TO, ...)<br>1. man<br>man,即 manunal,是 UNIX 系统手册的电子版本。根据习惯,UNIX 系统手册通常分为不同的部分(或小节,即 section),每个小节阐述不同的系统内容。目前的小节划分如下: <br><br>命令:普通用户命令 <br>系统调用:内核接口 <br>函数库调用:普通函数库中的函数 <br>特殊文件:/dev 目录中的特殊文件 <br>文件格式和约定:/etc/passwd 等文件的格式 <br>游戏。 <br>杂项和约定:标准文件系统布局、手册页结构等杂项内容 <br>系统管理命令。 <br>内核例程:非标准的手册小节。便于 Linux 内核的开发而包含 <br>其他手册小节:<br><br>l: PostgreSQL 数据库命令 <br>n: TCL/TK 命令 <br>手册页一般保存在 /usr/man 目录下,其中每个子目录(如 man1, man2, ..., manl, mann)包含不同的手册小节。使用 man 命令查看手册页。<br><br>man 命令行:<br>man [-acdfFhkKtwW] [-m system] [-p string] [-C config_file] [-M path] [-P pager] [-S section_list] [section] name <br><br>常用命令行:<br>$ man open<br>$ man 7 man<br>$ man ./myman.3<br><br><br>2. info<br>Linux 中的大多数软件开发工具都是来自自由软件基金会的 GNU 项目,这些工具软件件的在线文档都以 info 文件的形式存在。info 程序是 GNU 的超文本帮助系统。 <br><br>info 文档一般保存在 /usr/info 目录下,使用 info 命令查看 info 文档。<br><br>要运行 info,可以在 shell 提示符后输入 info,也可以在 GNU 的 emacs 中键入 Esc-x 后跟 info。 <br><br>info 帮助系统的初始屏幕显示了一个主题目录,你可以将光标移动到带有 * 的主题菜单上面,然后按回车键<br>进入该主题,也可以键入 m,后跟主题菜单的名称而进入该主题。例如,你可以键入 m,然后再键入 gcc 而进<br>进入 gcc 主题中。<br>如果你要在主题之间跳转,则必须记住如下的几个命令键:<br>* n:跳转到该节点的下一个节点;<br>* p:跳转到该节点的上一个节点;<br>* m: 指定菜单名而选择另外一个节点;<br>* f:进入交叉引用主题;<br>* l:进入该窗口中的最后一个节点;<br>* TAB:跳转到该窗口的下一个超文本链接;<br>* RET:进入光标处的超文本链接;<br>* u:转到上一级主题;<br>* d:回到 info 的初始节点目录;<br>* h:调出 info 教程;<br>* q:退出 info。<br>#DEMO#<br><br>3. HOW-TO<br>可供用户参考的联机文档的另一种形式是 HOWTO 文件,这些文件位于系统的 /usr/doc/HOWTO 目录下。 HOWTO 文件的文件名都有一个 -HOWTO 后缀,并且都是文本文件。<br><br>每一个 HOWTO 文件包含 Linux 某一方面的信息,例如它支持的硬件或如何建立一个引导盘。 <br><br>要想查看这些文件,进入 /usr/doc/HOWTO 目录,使用 more 命令,具体形式如下:<br>$ cd /usr/doc/HOWTO; more topic-name-HOWTO <br><br>另外,HOWTO 文档还有其他格式的文件,例如 HTML 和 PS 等,保存在 /usr/doc/HOWTO/other-formats 下。 <br><br>4. 其他<br>Linux 的内核文档一般包含在内核源代码中,目录如下:/usr/src/linux-2.x.x/Documentation <br><br>/usr/doc 目录下包含有大量与特定软件或函数库相关的说明性文档。 <br><br>1.4.4  C 语言编程风格<br>编写这一小节的目的是提醒大家在编程过程中注意编程风格。如果你只是在编写一些小的练习程序,程序只有一两百行长的话,编程风格可能并不重要。然而,如果你和许多人一起进行开发工作,或者,你希望在过一段时间之后,还能够正确理解自己的程序的话,就必须养成良好的编程习惯。在诸多编程习惯当中,编程风格是最重要的一项内容。 <br><br>良好的编程风格可以在许多方面帮助开发人员。如果你阅读过 Linux 内核源代码的话,可能会对程序的优美编排所倾倒。良好的编程风格可以增加代码的可读性,并帮助你理清头绪。如果程序非常杂乱,大概看一眼就该让你晕头转向了。编程风格最能体现一个程序员的综合素质。 <br><br>许多读者可能对 Windows 所推崇的匈牙利命名法很熟悉。这种方法定义了非常复杂的函数、变量、类型等的命名方法,典型的命名方法是采用大小写混写的方式,对于变量名称,则采用添加前缀的办法来表示其类型,例如:<br>char szBuffer[20];<br>int nCount;<br>利用 sz 和 n 分别代表字符串和整数。为了表示一个变量名称,采用如下的变量名称是可能的:<br>int iThisIsAVeryLongVariable; <br><br>在 Linux 中,我们经常看到的是定义非常简单的函数接口和变量名称。在 Linux 内核的源代码中,可以看到 Linux 内核源代码的编码风格说明(/ Documentation/CodingStyle)。UNIX 系统的一个特点是设计精巧,并遵守积木式原则。C 语言最初来自 UNIX 操作系统,与 UNIX 的设计原则一样, C 语言被广泛认可和使用的一个重要原因是它的灵活性以及简洁性。因此,在利用 C 语言编写程序时,始终应当符合其简洁的设计原则,而不应当使用非常复杂的变量命名方法。Linus 为 Linux 内核定义的 C 语言编码风格要点如下: <br><br>缩进时,使用长度为 8 个字符宽的 Tab 键。如果程序的缩进超过 3 级,则应考虑重新设计程序。 <br>大括号的位置。除函数的定义体外,应当将左大括号放在行尾,而将右大括号放在行首。函数的定义体应将左右大括号放在行首。如下所示:<br>int function(int x, int y)<br>{<br>        if (x == y) {<br>                ...<br>        } else if (x &gt; y) {<br>                ...<br>        } else {<br>                ...<br>        }<br><br>        return 0;<br>}<br><br>应采用简洁的命名方法。对变量名,不赞成使用大小写混写的形式,但鼓励使用描述性的名称;尽可能不使用全局变量;不采用匈牙利命名法表示变量的类型;采用短小精悍的名称表示局部变量;保持函数短小,从而避免使用过多的局部变量。 <br>保持函数短小精悍。 <br>不应过分强调注释的作用,应尽量采用好的编码风格而不是添加过多的注释。 <br>1.4.5  库和头文件的保存位置<br>1. 函数库<br>/lib:系统必备共享库 <br>/usr/lib:标准共享库和静态库 <br>/usr/i486-linux-libc5/lib:libc5 兼容性函数库 <br>/usr/X11R6/lib:X11R6 的函数库 <br>/usr/local/lib:本地函数库 <br>2. 头文件<br>/usr/include:系统头文件 <br>/usr/local/include:本地头文件 <br>1.4.6  共享库及其相关配置<br>/etc/ld.so.conf:包含共享库的搜索位置 <br>ldconfig:共享库管理工具,一般在更新了共享库之后要运行该命令 <br>ldd:可查看可执行文件所使用的共享库 <br><br><br>                          
6#
 楼主| 发表于 28.11.2002 11:37:47 | 只看该作者
                          <br>1.5  Linux 上进行程序开发的典型场景<br><br><br>控制台上的开发场景 <br><br>X Window 上的开发场景 <br><br>1.5.1  控制台上的开发场景<br>#DEMO#<br><br>在控制台上利用 vim 编辑器编写“Hello, world&#33;”程序,并在命令行编译并运行。<br><br>1.5.2  X Window 上的开发场景<br>#DEMO#<br><br>在 X Window 上利用 Emacs 编写“Hello, world&#33;”程序,并在 Emacs 中直接编译并运行。<br>                       
7#
 楼主| 发表于 28.11.2002 11:38:40 | 只看该作者
                          <br>1.6  程序和脚本<br><br><br>程序:编写, 编译, 调试和执行 <br><br>脚本:编写, 执行 <br><br>1.6.1  程序:编写, 编译, 调试和执行<br>#TODO#<br><br>1.6.2  脚本:编写, 执行<br>#TODO#<br><br>#DEMO#<br><br>一个 Perl 脚本,用来生成函数的手册页<br><br>                       
8#
 楼主| 发表于 28.11.2002 11:39:13 | 只看该作者
                          <br>1.7  Linux 上的 C/C++ 编译器和调试器<br><br><br>运行 gcc/egcs <br><br>gcc/egcs 的主要选项 <br><br>gdb <br><br>gdb 的常用命令 <br><br>gdb 使用范例 <br><br>其他程序/库工具 (ar, objdump, nm, size, strings, strip, ...) <br><br>创建和使用静态库 <br>创建和使用共享库 <br>使用高级共享库特性 <br>1.7.1  运行 gcc/egcs<br>Linux 中最重要的软件开发工具是 GCC。GCC 是 GNU 的 C 和 C++ 编译器。实际上,GCC 能够编译三种语言:C、C++ 和 Object C(C 语言的一种面向对象扩展)。利用 gcc 命令可同时编译并连接 C 和 C++ 源程序。 <br><br>#DEMO#: hello.c <br><br>如果你有两个或少数几个 C 源文件,也可以方便地利用 GCC 编译、连接并生成可执行文件。例如,假设你有两个源文件 main.c 和 factorial.c 两个源文件,现在要编译生成一个计算阶乘的程序。 <br><br>-----------------------<br>清单 factorial.c<br>-----------------------<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br><br>int factorial (int n)<br>{<br>    if (n &lt;= 1)<br>        return 1;<br><br>    else<br>        return factorial (n - 1) * n;<br>}<br>-----------------------<br><br>-----------------------<br>清单  main.c<br>-----------------------<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br><br>int factorial (int n);<br><br>int main (int argc, char **argv)<br>{<br>    int n;<br><br>    if (argc &lt; 2) {<br>        printf (&quot;Usage: %s n\n&quot;, argv [0]);<br>        return -1;<br>    }<br>    else {<br>        n = atoi (argv[1]);<br>        printf (&quot;Factorial of %d is %d.\n&quot;, n, factorial (n));<br>    }<br><br>    return 0;<br>}<br>-----------------------<br><br>利用如下的命令可编译生成可执行文件,并执行程序:<br>$ gcc -o factorial main.c factorial.c<br>$ ./factorial 5<br>Factorial of 5 is 120.<br>GCC 可同时用来编译 C 程序和 C++ 程序。一般来说,C 编译器通过源文件的后缀名来判断是 C 程序还是 C++ 程序。在 Linux 中,C 源文件的后缀名为 .c,而 C++ 源文件的后缀名为 .C 或 .cpp。 <br><br>但是,gcc 命令只能编译 C++ 源文件,而不能自动和 C++ 程序使用的库连接。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会自动调用 gcc 实现编译。假设我们有一个如下的 C++ 源文件(hello.C): <br><br>#include &lt;iostream.h&gt;<br><br>void main (void)<br>{<br>    cout &lt;&lt; &quot;Hello, world&#33;&quot; &lt;&lt; endl;<br>}<br>则可以如下调用 g++ 命令编译、连接并生成可执行文件: <br><br>$ g++ -o hello hello.C<br>$ ./hello<br>Hello, world&#33;<br>1.7.2  gcc/egcs 的主要选项<br>                表 1-3  gcc 命令的常用选项<br>选项                解释<br>-ansi               只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色,<br>                    例如 asm 或 typeof 关键词。<br>-c                  只编译并生成目标文件。<br>-DMACRO             以字符串“1”定义 MACRO 宏。<br>-DMACRO=DEFN        以字符串“DEFN”定义 MACRO 宏。<br>-E                  只运行 C 预编译器。<br>-g                  生成调试信息。GNU 调试器可利用该信息。<br>-IDIRECTORY         指定额外的头文件搜索路径DIRECTORY。<br>-LDIRECTORY         指定额外的函数库搜索路径DIRECTORY。<br>-lLIBRARY           连接时搜索指定的函数库LIBRARY。<br>-m486               针对 486 进行代码优化。<br>-o FILE             生成指定的输出文件。用在生成可执行文件时。<br>-O0                 不进行优化处理。<br>-O 或 -O1           优化生成代码。<br>-O2                 进一步优化。<br>-O3                 比 -O2 更进一步优化,包括 inline 函数。<br>-shared             生成共享目标文件。通常用在建立共享库时。<br>-static             禁止使用共享连接。<br>-UMACRO             取消对 MACRO 宏的定义。<br>-w                  不生成任何警告信息。<br>-Wall               生成所有警告信息。<br>#DEMO#<br><br>MiniGUI 的编译选项<br><br>1.7.3  gdb<br>GNU 的调试器称为 gdb,该程序是一个交互式工具,工作在字符模式。在 X Window 系统中,<br>有一个 gdb 的前端图形工具,称为 xxgdb。gdb 是功能强大的调试程序,可完成如下的调试<br>任务:<br>* 设置断点;<br>* 监视程序变量的值;<br>* 程序的单步执行;<br>* 修改变量的值。<br>在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义<br> CFLAGS 变量:<br>CFLAGS = -g<br>运行 gdb 调试程序时通常使用如下的命令:<br>gdb progname<br><br>在 gdb 提示符处键入help,将列出命令的分类,主要的分类有:<br>* aliases:命令别名<br>* breakpoints:断点定义;<br>* data:数据查看;<br>* files:指定并查看文件;<br>* internals:维护命令;<br>* running:程序执行;<br>* stack:调用栈查看;<br>* statu:状态查看;<br>* tracepoints:跟踪程序执行。<br>键入 help 后跟命令的分类名,可获得该类命令的详细清单。<br>#DENO#<br><br>1.7.4  gdb 的常用命令<br>                表 1-4  常用的 gdb 命令<br>命令                        解释<br>break NUM               在指定的行上设置断点。<br>bt                      显示所有的调用栈帧。该命令可用来显示函数的调用顺序。<br>clear                   删除设置在特定源文件、特定行上的断点。其用法为:clear FILENAME:NUM。<br>continue                继续执行正在调试的程序。该命令用在程序由于处理信号或断点而<br>                        导致停止运行时。<br>display EXPR            每次程序停止后显示表达式的值。表达式由程序定义的变量组成。<br>file FILE               装载指定的可执行文件进行调试。<br>help NAME               显示指定命令的帮助信息。<br>info break              显示当前断点清单,包括到达断点处的次数等。<br>info files              显示被调试文件的详细信息。<br>info func               显示所有的函数名称。<br>info local              显示当函数中的局部变量信息。<br>info prog               显示被调试程序的执行状态。<br>info var                显示所有的全局和静态变量名称。<br>kill                    终止正被调试的程序。<br>list                    显示源代码段。<br>make                    在不退出 gdb 的情况下运行 make 工具。<br>next                    在不单步执行进入其他函数的情况下,向前执行一行源代码。<br>print EXPR              显示表达式 EXPR 的值。<br><br><br>1.7.5  gdb 使用范例<br>-----------------<br>清单  一个有错误的 C 源程序 bugging.c<br>-----------------<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br><br>static char buff [256];<br>static char* string;<br>int main ()<br>{<br><br>    printf (&quotlease input a string: &quot;);<br>    gets (string);<br><br>    printf (&quot;\nYour string is: %s\n&quot;, string);<br>}<br>-----------------<br>上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了<br>一个未经过初始化的字符串地址 string,因此,编译并运行之后,将出现 Segment Fault 错误:<br>$ gcc -o test -g test.c<br>$ ./test<br>lease input a string: asfd<br>Segmentation fault (core dumped)<br>为了查找该程序中出现的问题,我们利用 gdb,并按如下的步骤进行:<br>1.运行 gdb bugging 命令,装入 bugging 可执行文件;<br>2.执行装入的 bugging 命令;<br>3.使用 where 命令查看程序出错的地方;<br>4.利用 list 命令查看调用 gets 函数附近的代码;<br>5.唯一能够导致 gets 函数出错的因素就是变量 string。用 print 命令查看 string 的值;<br>6.在 gdb 中,我们可以直接修改变量的值,只要将 string 取一个合法的指针值就可以了,为<br>此,我们在第 11 行处设置断点;<br>7.程序重新运行到第 11 行处停止,这时,我们可以用 set variable 命令修改 string 的取值;<br>8.然后继续运行,将看到正确的程序运行结果。<br><br><br>#DEMO#<br><br>1.7.6  其他程序/库工具<br>strip:<br>nm:<br>size:<br>string:<br><br>1.7.7  创建和使用静态库<br><br>创建一个静态库是相当简单的。通常使用 ar 程序把一些目标文件(.o)组合在一起,<br>成为一个单独的库,然后运行 ranlib,以给库加入一些索引信息。<br><br><br>1.7.8  创建和使用共享库<br>特殊的编译和连接选项<br>-D_REENTRANT         使得预处理器符号 _REENTRANT 被定义,这个符号激活一些宏特性。<br>-fPIC                选项产生位置独立的代码。由于库是在运行的时候被调入,因此这个<br>                     选项是必需的,因为在编译的时候,装入内存的地址还不知道。如果<br>                     不使用这个选项,库文件可能不会正确运行。<br>-shared              选项告诉编译器产生共享库代码。<br>-Wl,-soname          -Wl 告诉编译器将后面的参数传递到连接器。而 -soname 指定了<br>                     共享库的 soname。<br><br><br>    # 可以把库文件拷贝到 /etc/ld.so.conf 中列举出的任何目录中,并以<br> root 身份运行 ldconfig;或者<br>    # 运行 export LD_LIBRARY_PATH=&#39;pwd&#39;,它把当前路径加到库搜索路径中去。<br><br><br>1.7.9  使用高级共享库特性<br>1. ldd 工具<br>ldd 用来显示执行文件需要哪些共享库, 共享库装载管理器在哪里找到了需要的共享库.<br><br>2. soname<br><br>共享库的一个非常重要的,也是非常难的概念是 soname——简写共享目标名(short for shared object name)。这是一个为共享库(.so)文件而内嵌在控制数据中的名字。如前面提到的,每一个程序都有一个需要使用的库的清单。这个清单的内容是一系列库的 soname,如同 ldd 显示的那样,共享库装载器必须找到这个清单。<br><br><br><br>soname 的关键功能是它提供了兼容性的标准。当要升级系统中的一个库时,并且新库的 soname 和老的库的 soname 一样,用旧库连接生成的程序,使用新的库依然能正常运行。这个特性使得在 Linux 下,升级使用共享库的程序和定位错误变得十分容易。 <br><br><br><br><br>在 Linux 中,应用程序通过使用 soname,来指定所希望库的版本。库作者也可以通过保留或者改变 soname 来声明,哪些版本是相互兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。<br><br><br><br>查看/usr/local/lib 目录,分析 MiniGUI 的共享库文件之间的关系<br><br>3. 共享库装载器<br><br>当程序被调用的时候,Linux 共享库装载器(也被称为动态连接器)也自动被调用。它的作用是保证程序所需要的所有适当版本的库都被调入内存。共享库装载器名字是 ld.so 或者是 ld-linux.so,这取决于 Linux libc 的版本,它必须使用一点外部交互,才能完成自己的工作。然而它接受在环境变量和配置文件中的配置信息。<br><br><br><br>文件 /etc/ld.so.conf 定义了标准系统库的路径。共享库装载器把它作为搜索路径。为了改变这个设置,必须以 root 身份运行 ldconfig 工具。这将更新 /etc/ls.so.cache 文件,这个文件其实是装载器内部使用的文件之一。<br><br><br><br>可以使用许多环境变量控制共享库装载器的操作(表1-4+)。<br><br>                        表 1-4+ 共享库装载器环境变量<br>变量                       含义<br>LD_AOUT_LIBRARY_PATH       除了不使用 a.out 二进制格式外,与 LD_LIBRARY_PATH 相同。<br>LD_AOUT_PRELOAD            除了不使用 a.out 二进制格式外,与 LD_PRELOAD 相同。<br>LD_KEEPDIR                 只适用于 a.out 库;忽略由它们指定的目录。<br>LD_LIBRARY_PATH            将其他目录加入库搜索路径。它的内容应该是由冒号<br>                           分隔的目录列表,与可执行文件的 PATH 变量具有相同的格式。<br>                           如果调用设置用户 ID 或者进程 ID 的程序,该变量被忽略。<br>LD_NOWARN                  只适用于 a.out 库;当改变版本号是,发出警告信息。<br>LD_PRELOAD                 首先装入用户定义的库,使得它们有机会覆盖或者重新定义标准库。<br>                           使用空格分开多个入口。对于设置用户 ID 或者进程 ID 的程序,<br>                           只有被标记过的库才被首先装入。在 /etc/ld.so.perload 中指定<br>                           了全局版本号,该文件不遵守这个限制。<br><br><br>4. 使用 dlopen<br><br>    另外一个强大的库函数是 dlopen()。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。比如 Apache Web 服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。一个配置文件控制了加载模块的过程。这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了。<br><br><br><br>    可以在自己的程序中使用 dlopen()。dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现。它需要两个参数:一个文件名和一个标志。文件名可以是我们学习过的库中的 soname。标志指明是否立刻计算库的依赖性。如果设置为 RTLD_NOW 的话,则立刻计算;如果设置的是 RTLD_LAZY,则在需要的时候才计算。另外,可以指定 RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。<br><br><br><br>    当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。<br><br>                       
9#
 楼主| 发表于 28.11.2002 11:42:08 | 只看该作者
                          <br>1.8  GNU make 和 makefile<br><br><br>GNU make <br><br>makefile 基本结构 <br><br>makefile 变量 <br><br>GNU make 的主要预定义变量 <br><br>隐含规则 <br><br>makefile 范例 <br><br>运行 make <br><br>1.8.1  GNU make<br>在大型的开发项目中,通常有几十到上百个的源文件,如果每次均手工键入 gcc 命令进行编译的话,则会<br>非常不方便。因此,人们通常利用 make 工具来自动完成编译工作。这些工作包括:如果仅修改了某几个<br>源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。<br>利用这种自动编译可大大简化开发工作,避免不必要的重新编译。<br>实际上,make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作。makefile 需要按照某种<br>语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。<br>当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。<br>makefile 文件是许多编译器,包括 Windows NT 下的编译器维护编译信息的常用方法,只是在集成开发环<br>境中,用户通过友好的界面修改 makefile 文件而已。<br>默认情况下,GNU make 工具在当前工作目录中按如下顺序搜索 makefile:<br>* GNUmakefile<br>* makefile<br>* Makefile<br>在 UNIX 系统中,习惯使用 Makefile 作为 makfile 文件。如果要使用其他文件作为 makefile,则可利用类<br>似下面的 make 命令选项指定 makefile 文件:<br>$ make -f Makefile.debug<br>1.8.2  makefile 基本结构<br>makefile 中一般包含如下内容:<br>* 需要由 make 工具创建的项目,通常是目标文件和可执行文件。通常使用“目标(target)”一词来表示<br>要创建的项目。<br>* 要创建的项目依赖于哪些文件。<br>* 创建每个项目时需要运行的命令。<br>例如,假设你现在有一个 C++ 源文件 test.C,该源文件包含有自定义的头文件 test.h,则目标文件 test.o<br> 明确依赖于两个源文件:test.C 和 test.h。另外,你可能只希望利用 g++ 命令来生成 test.o 目标文件。<br>这时,就可以利用如下的 makefile 来定义 test.o 的创建规则:<br><br># This makefile just is a example.<br># The following lines indicate how test.o depends<br># test.C and test.h, and how to create test.o<br><br>test.o: test.C test.h<br>    g++ -c -g test.C<br><br>从上面的例子注意到,第一个字符为 # 的行为注释行。第一个非注释行指定 test.o 为目标,并且依赖于 <br>test.C 和 test.h 文件。随后的行指定了如何从目标所依赖的文件建立目标。<br>当 test.C 或 test.h 文件在编译之后又被修改,则 make 工具可自动重新编译 test.o,如果在前后两次<br>编译之间,test.C 和 test.h 均没有被修改,而且 test.o 还存在的话,就没有必要重新编译。这种依赖<br>关系在多源文件的程序编译中尤其重要。通过这种依赖关系的定义,make 工具可避免许多不必要的编译工<br>作。当然,利用 Shell 脚本也可以达到自动编译的效果,但是,Shell 脚本将全部编译任何源文件,包括<br>哪些不必要重新编译的源文件,而 make 工具则可根据目标上一次编译的时间和目标所依赖的源文件的更新<br>时间而自动判断应当编译哪个源文件。<br>一个 makefile 文件中可定义多个目标,利用 make target 命令可指定要编译的目标,如果不指定目标,<br>则使用第一个目标。通常,makefile 中定义有 clean 目标,可用来清除编译过程中的中间文件,例如:<br>clean:<br>    rm -f *.o<br>运行 make clean 时,将执行 rm -f *.o 命令,最终删除所有编译过程中产生的所有中间文件。<br>1.8.3  makefile 变量<br>GNU 的 make 工具除提供有建立目标的基本功能之外,还有许多便于表达依赖性关系以及建立目标的命令的特<br>色。其中之一就是变量或宏的定义能力。如果你要以相同的编译选项同时编译十几个 C 源文件,而为每个目<br>标的编译指定冗长的编译选项的话,将是非常乏味的。但利用简单的变量定义,可避免这种乏味的工作:<br><br># Define macros for name of compiler<br>CC = gcc<br><br># Define a macr o for the CC flags<br>CCFLAGS = -D_DEBUG -g -m486<br><br># A rule for building a object file<br>test.o: test.c test.h<br>    $(CC) -c $(CCFLAGS) test.c<br><br>在上面的例子中,CC 和 CCFLAGS 就是 make 的变量。GNU make 通常称之为变量,而其他 UNIX 的 make <br>工具称之为宏,实际是同一个东西。在 makefile 中引用变量的值时,只需变量名之前添加 $ 符号,如<br>上面的 $(CC) 和 $(CCFLAGS)。<br>1.8.4  GNU make 的主要预定义变量<br>GNU make 有许多预定义的变量,这些变量具有特殊的含义,可在规则中使用。表 1-5 给出了一些主要的<br>预定义变量,除这些变量外,GNU make 还将所有的环境变量作为自己的预定义变量。<br><br>                        表 1-5  GNU make 的主要预定义变量<br>预定义变量                      含义<br>$*              不包含扩展名的目标文件名称。<br>$+              所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。<br>$&lt;              第一个依赖文件的名称。<br>$?              所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。<br>$@              目标的完整名称。<br>$^              所有的依赖文件,以空格分开,不包含重复的依赖文件。<br>$%              如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称<br>                为 mytarget.so(image.o),则 $@ 为 mytarget.so,而 $% 为 image.o。<br>AR              归档维护程序的名称,默认值为 ar。<br>ARFLAGS         归档维护程序的选项。<br>AS              汇编程序的名称,默认值为 as。<br>ASFLAGS         汇编程序的选项。<br>CC              C 编译器的名称,默认值为 cc。<br>CFLAGS          C 编译器的选项。<br>CPP             C 预编译器的名称,默认值为 $(CC) -E。<br>CPPFLAGS        C 预编译的选项。<br>CXX             C++ 编译器的名称,默认值为 g++。<br>CXXFLAGS        C++ 编译器的选项。<br>FC              FORTRAN 编译器的名称,默认值为 f77。<br>FFLAGS          FORTRAN 编译器的选项。<br>1.8.5  隐含规则<br>GNU make 包含有一些内置的或隐含的规则,这些规则定义了如何从不同的依赖文件建立特定类型的目标。<br>GNU make 支持两种类型的隐含规则:<br>* 后缀规则(Suffix Rule)。后缀规则是定义隐含规则的老风格方法。后缀规则定义了将一个具有某个<br>后缀的文件(例如,.c 文件)转换为具有另外一种后缀的文件(例如,.o 文件)的方法。每个后缀规<br>则以两个成对出现的后缀名定义,例如,将 .c 文件转换为 .o 文件的后缀规则可定义为:<br><br>.c.o:<br>$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $&lt;<br><br>* 模式规则(pattern rules)。这种规则更加通用,因为可以利用模式规则定义更加复杂的依赖性规则。<br>模式规则看起来非常类似于正则规则,但在目标名称的前面多了一个 % 号,同时可用来定义目标和依赖<br>文件之间的关系,例如下面的模式规则定义了如何将任意一个 X.c 文件转换为 X.o 文件:<br><br>%.c:%.o<br>$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $&lt;<br><br>1.8.6  makefile 范例<br>#SAMPLE#<br><br>CCE 的 Makefile<br><br>1.8.7  运行 make<br>我们知道,直接在 make 命令的后面键入目标名可建立指定的目标,如果直接运行 make,则建立第一个<br>目标。我们还知道可以用 make -f mymakefile 这样的命令指定 make 使用特定的 makefile,而不是<br>默认的 GNUmakefile、makefile 或 Makefile。但 GNU make 命令还有一些其他选项,表 1-6 给出了<br>这些选项。<br><br>                        表 1-6  GNU make 命令的常用命令行选项<br><br>命令行选项              含义<br>-C DIR              在读取 makefile 之前改变到指定的目录 DIR。<br>-f FILE             以指定的 FILE 文件作为 makefile。<br>-h                  显示所有的 make 选项。<br>-i                  忽略所有的命令执行错误。<br>-I DIR              当包含其他 makefile 文件时,可利用该选项指定搜索目录。<br>-n                  只打印要执行的命令,但不执行这些命令。<br>-p                  显示 make 变量数据库和隐含规则。<br>-s                  在执行命令时不显示命令。<br>-w                  在处理 makefile 之前和之后,显示工作目录。<br>-W FILE             假定文件 FILE 已经被修改。<br><br>                          
10#
 楼主| 发表于 28.11.2002 11:42:43 | 只看该作者
                         <br>1.9  实用工具<br><br><br>正则表达式 <br><br>压缩和归档工具 (gzip, bzip2, tar, ...) <br><br>搜索和排序 (grep, find, sort, ...) <br><br>文件编辑 (sed, tr) <br><br>文件比较 (cmp, comm, diff, ...) <br><br>其他 (ed, emacs, ...) <br><br>1.9.1  正则表达式<br>正则表达式在 shell、工具程序、Perl 语言中有非常重要的地位。正则表达式通过<br>一些特殊符号表示特定的字符串模式。常见的特殊字符包括:<br><br>字符                功能<br>^                   置于待搜索的字符串之前,匹配行首的字<br>$                   置于待搜索的字符串之后,匹配行末的字<br>\&lt;                  匹配一个字的字头<br>\&gt;                  匹配一个字的字尾<br>.                   匹配任意单个正文字符<br>[str]               匹配字符串 str 中的任意单个字符<br>[^str]              匹配不在字符串 str 中的任意单个字符<br>[a-c]               匹配从 a 到 c 之间的任一字符<br>*                   匹配前一个字符的 0 次或多次出现<br>\                   忽略特殊字符的特殊含义,将其看作普通字符<br><br>扩充的特殊字符:<br>字符                功能<br>+                   重复匹配前一项 1 次以上<br>?                   重复匹配前一项 0 次或 1 次<br>{j}                 重复匹配前一项 j 次<br>{j, }               重复匹配前一项 j 次以上<br>{, k}               重复匹配前一项最多 k 次<br>{j, k}              重复匹配前一项 j 到 k 次<br>s | t               匹配 s 或 t 中的一项<br>(exp)               将表达式 exp 作为单项处理<br><br>1.9.2  压缩和归档工具<br>gzip, bzip2, tar 等<br><br>#DEMO#<br><br>1.9.3  搜索和排序<br>grep find<br><br>#DEMO#<br><br>1.9.4  文件编辑<br>sed, tr<br><br>#DEMO#<br><br>1.9.5  文件比较<br>cmp, comm, diff, patch<br><br>#DEMO#<br><br>1.9.6  其他<br>ed, vi, emacs<br><br>#DEMO#<br><br><br><br><br><br><br><br><br><br><br><br>                        
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点信息

站点统计| 举报| Archiver| 手机版| 小黑屋

Powered by Discuz! X3.2 © 2001-2014 Comsenz Inc.

GMT+1, 26.5.2024 19:49

关于我们|Apps

() 开元网

快速回复 返回顶部 返回列表