2.1.3 应用程序

操作系统一般还提供必要的应用程序——系统应用,如编译器、公用函数库、编辑器、Shell等,以支持计算机系统的管理和维护,以及办公软件、娱乐软件、科学计算软件、工业软件和中间件等用户应用程序的开发和运行。

GNU项目基于POSIX开发了大量的应用程序,包括以上提及的必要的系统应用,正好可与莱纳斯·托瓦尔兹开发的Linux内核组成完整的操作系统,即GNU/Linux。这些软件非常优秀,如同一个个业务小能手,聚合在一起组成一个强大的软件团队,深受程序员的喜爱,也因此蓬勃发展。

1.编译器

编译器是开发新应用程序的必备工具。它通过非常复杂的编译过程,将抽象度较高的编程语言代码(源程序)转化成抽象度较低的机器语言代码(目标程序),为操作系统提供功能扩展能力。C语言因改写UNIX操作系统而发明,因此C语言编译器最初是为UNIX而生的,至今已广泛应用于各种操作系统。常见的C/C++编译器主要有GCC(GNU Compiler Collection,GNU编译器套件)、Microsoft Visual C++等。

(1)GCC

GCC中的C/C++编译器一般是UNIX类操作系统默认安装的C/C++编译器。此外,GCC还包括Objective-C、Java、Ada和Go语言的编译器前端及这些语言的运行库。GCC最初是为GNU操作系统专门编写的一款编译器,是彻底的自由软件,现在被大多数UNIX类操作系统(如Linux、BSD、macOS等)采纳为标准的编译器,同样适用于Windows操作系统(借助MinGW)。

GCC是最受欢迎的GNU自由软件之一,它基于CLI使用,提供了大量的参数与选项,功能强大,支持性能优化。GCC通常与Makefile或CMake等工具相配合,可构建强大、灵活、可移植的软件构建方案,是开放源码领域使用非常广泛的编译器。

有关如何用GCC在Linux开发环境下进行C/C++开发,在第5章会详细讨论。

(2)Microsoft Visual C++

Microsoft Visual C++是微软公司发布的C/C++编译器,提供Windows API(Application Program Interface,应用程序接口)、3D图形DirectX API、.NET Framework等丰富的库函数支持。它以拥有语法高亮、IntelliSense(自动完成功能)及高级除错功能而著称,曾广泛应用于Windows系统各种系统服务和应用软件开发。

此外,新兴编译器也在不断涌现。

2007年,苹果公司开发了Clang编译器,在BSD开源协议下发布。Clang是Clang LLVM的一个编译器前端,它目前支持C/C++、Objective-C及Objective-C++等编程语言。Clang具有编译快速、占用内存少、诊断信息可读性强、易扩展、易于集成开发环境集成等优点。此外,还具有ARC(Automatic Reference Counting,自动引用计数)静态分析功能,能够自动分析程序的逻辑,在编译时就找出程序可能存在的bug。

2019 年 8 月底,华为方舟编译器正式开源(OpenArkCompiler),其目标是构建一个基于MapleIR的跨语言编程环境,实现跨语言的全局分析及优化。目前,方舟编译器加入了对C语言程序编译的支持,当然继续开源也是实现Java和C混合编译的基础。未来,方舟编译器不仅会支持对来自Java语言的IR(Intermediate Representation,中间表示)代码进行JIT(Just-In-Time,即时)编译,也会支持对来自C、C++语言的IR代码进行JIT编译。

2021年4月,华为发布了GCC for openEuler。该编译器基于开源的GCC-10.3开发并进行了优化和改进,实现软硬件深度协同优化,在OpenMP、SVE(Scalable Vector Extension,可伸缩向量扩展)向量化、数学库等领域挖掘极致性能,是一种在Linux下适配鲲鹏920处理器的高性能编译器。GCC for openEuler默认使用场景为TaiShan服务器、鲲鹏920处理器、ARM架构,支持的操作系统为CentOS 7.6、openEuler 20.03或openEuler 22.03等。

2.公用函数库

公用函数库通常指的是C/C++运行库,由编译器将它与用户开发的应用程序链接在一起,实现功能封装和代码复用,为操作系统的功能扩展提供统一机制,极大降低软件开发和移植的复杂性。这些标准的运行库的实现方式主要是基于操作系统提供的系统调用接口、API(如POSIX),并将相关基础功能封装为简洁、一致的跨平台标准API,提高应用程序的开发效率和可移植性,这种实现方式是整个计算机软件体系的基础。常见的C/C++运行库有ANSI(American National Standards Institute,美国国家标准学会)的libc/libc++、GNU的glibc/libstdc++和微软公司的msvcrt等。

libc是符合ANSI C标准的一个公用函数库,包含C语言基本函数的运行库。这个库可根据头文件划分为 15 个部分,包括类型、错误码、浮点常数、数学常数、标准定义、标准 I/O(Input/Output,输入输出)、工具函数、字符串操作、时间和日期、可变参数表、信号、非局部跳转、本地信息、程序断言等。

glibc是GNU发布的C运行库,是GNU/Linux操作系统中非常基础的API,服务于几乎其他所有应用程序,glibc架构如图2.3所示。glibc除了提供libc的全部功能外,还封装了信号量、进程间通信等基于POSIX的系统调用,几乎囊括所有的UNIX中通行的标准,可见其包罗万象。

glibc是GNU/Linux演进的一个重要里程碑,更是C语言编程爱好者的学习宝库。glibc按照GNU LGPL(GNU Lesser General Public License,GNU宽通用公共许可证)发布,源码全部开源,可免费下载和学习。例如,C语言库函数strcpy函数的实现是软件开发相关岗位的一道常见面试题,然而glibc给出了迥然不同的代码逻辑,其核心代码大致如下。

图2.3 glibc架构

char *strcpy(char *dest, const char *src)
 { 
     char *s = src; 
     const ptrdiff_t off = dest -s -1; 
     do { 
         s[off]=*s; 
     } while (*s++ != '\0'); 
     return dest; 
 }

思考:上述代码的完整实现要稍微复杂一些,另外针对不同CPU平台的实现可能有所不同。就上面这段核心代码来看,glibc实现的主要思路是什么?glibc中还有strlen等很多其他函数的实现,读者可自行阅读glibc相关源码。

3.编辑器

编辑器是用于修改文本文件的工具,在不同的操作系统中的地位可能截然不同。在Windows操作系统中,编辑器似乎无足轻重,但在UNIX类操作系统中,编辑器却是使用极为频繁的重要工具。

在Windows等GUI操作系统的日常使用中,很少用到编辑器,特别是在当今以触摸屏作为主要输入接口、以娱乐为主的智能手机和智能平板操作系统中,已不再需要编辑器。相反,系统维护者通过使用不同的二进制工具修改系统配置,软件开发者也必须使用不同的编辑器,它们分布在各种不同的集成开发环境中,如MATLAB、Visual Studio等。这些集成开发环境大都使用不同的编辑器,开发者不得不适应不同的编辑习惯。

UNIX 类操作系统迥然不同,编辑器是配置维护和软件开发的基本工具,由黑客程序员出于自己的需要而开发。它们设计优雅,或效率高、或功能强,从发布以来,不断扩展并沿用至今,已成为UNIX优秀文化的重要代表之一。它们富有创意的设计将文本编辑这一任务做到极致。用户只需要掌握极少数编辑器的使用方法,并选择按自己喜爱的方式操作,即可非常高效地编辑所有文本文件。这一切得益于UNIX操作系统广泛采用文本的优秀设计。

UNIX操作系统的设计哲学之一就是尽可能使用文本文件,而不是二进制文件。文本文件解析简单,任何时候都可用任何文本编辑器打开,而不会出现由于文件损坏或版本过低等兼容性问题无法读取的情况。在UNIX类操作系统中,所有的系统配置都使用文本文件,甚至HTTP(Hypertext Transfer Protocol,超文本传送协议)、SMTP(Simple Mail Transfer Protocol,简单邮件传送协议)、POPv3(Post Office Protocol Version 3,邮局协议第3版)、FTP(File Transfer Protocol,文件传送协议)等最初的许多互联网应用协议也都采用文本格式。在UNIX类操作系统中,使用文本文件,还可高效地完成制表绘图、编写技术报告/学术论文等许多图文结合的编辑任务。例如,编辑如下文本,即可用LaTeX工具生成包含公式甚至电路图的PDF文档,如图2.4所示。

\documentclass{article}
\begin{document} 
\[ x(t)=\sum^{+\infty}_{k=-\infty}\alpha_k\cdot e^{jk(\frac{2\pi}{T})t} \] 
\newpage
\begin{figure}[h!] 
  \begin{circuitikz}
   \draw (0,0)
   to[V,v=$U_q$] (0,2)
   to[short] (2,2)
   to[R=$R_1$] (2,0)
   to[short] (0,0); 
  \end{circuitikz}
\end{figure}
\end{document}

图2.4 LaTex用文本文件生成的公式和电路图

在UNIX文化的激励下,涌现出了一批优秀的编辑器软件,如ed、ex、sed、vi、vim、nano、Emacs等。它们提供了许多强大、灵活的功能,为现代编辑器提供设计参考。事实上,诸多现代编辑器,如Notepad++、UltraEdit、Sublime Text、Atom、jEdit,以及Visual Studio Code等,都在不断地从“前辈”身上借鉴思路并进行创新。相比之下,这些几十年前的优秀编辑器,依然是经典,其中最为流行的是Vi和Emacs,分别是两种不同编辑流派的杰出代表。

Vi是由加利福尼亚大学伯克利分校的研究生比尔·乔伊[3]于1976年发布的第一款全屏幕控制台,也是一款通用的文本编辑器,被誉为“编辑器之神”。在此之前,人们只能使用行编辑器,如肯·汤普森开发的ed及乔治·库鲁里斯(George Coulouris)开发的em[4]等。Vi的核心设计思想是让程序员的手指始终保持在键盘的核心区域,就能完成所有的编辑动作。它功能强大、效率极高,可编辑系统配置文件、各种编程语言文件,几乎可在任何 UNIX 类操作系统上运行。这个编辑器因其独特的使用方式,让无数程序员爱不释手,也让无数程序员从入门到放弃。


[3] 比尔·乔伊被誉为“神一样的程序员”。除了Vi之外,他还是BSD、TCP/IP、NFS、Java的主要设计者,SPARC微处理器的主要设计者。1982年,他作为联合创始人创立了Sun公司并担任首席科学家,直至2003年。

[4] 更多关于从ed到em/Vi的发展,可阅读关于比尔·乔伊的采访文章。

Vim(Vi IMproved)是基于Vi编辑器的改进版,是由布拉姆·穆莱纳尔(Bram Moolenaar)[5]开发的一款增强版的文本编辑器,具有更丰富的内置高级功能。它支持语法高亮、自动缩进、自动补全、模式匹配与替换、区块操作和无限次撤销等。Vim 也支持用户自定义脚本和插件,可进行个性化定制和扩展。Vi系列编辑器最大的优点就是,在一个新的系统上无须配置即可立即使用,无须担心使用习惯不一致。Vim在管理员和程序员中广受欢迎,与Emacs一起成为深受UNIX类操作系统用户喜爱的文本编辑器。Vim多buffer编辑界面如图2.5所示。


[5] 布拉姆·穆莱纳尔于2023年8月3日去世,他将人生近半的时间奉献给了Vim,为开源社区做出了巨大的贡献。

图2.5 Vim多buffer编辑界面

Emacs在20世纪70年代诞生于麻省理工学院人工智能实验室(MIT AI Lab),是著名的文本编辑器和集成开发环境,被誉为“神的编辑器”。Emacs针对多种文档定义了不同的“主模式”(major mode),包括普通文本文件、所有编程语言的源文件、HTML(Hypertext Markup Language,超文本标记语言)文档、LaTeX文档,以及其他类型的文本文件。Emacs是一个易扩展、高度可定制的开源编辑器,具有许多优秀特性,如自定义模式、自定义快捷键、自定义宏操作、多种选择模式、多窗口、多书签、多剪贴板、选中区域起始点切换、矩形区块操作,以及支持显示图片、PDF文档等。

Emacs 是具备高可移植性的重要软件之一,能够在当前大多数操作系统上运行,包括GNU/Linux、Windows、Android,以及iOS等,并且具有极其丰富的功能扩展,几乎可用于处理所有的文本编辑任务。然而,Emacs编辑器复杂的按键操作、极为陡峭的学习曲线,令新手望而生畏,但一旦熟练掌握使用方法,即可用它高效处理多种文本编辑任务,再也无法离开。Emacs多buffer编辑界面如图2.6所示。

  注:左上为C++代码,左下为Shell界面,右上为Markdown文档,右下为心理医生程序和小游戏。

图2.6 Emacs多buffer编辑界面

此外,还有nano、JOE、Pico等众多优秀的开源编辑器,都属于非常简单的编辑器,常用于系统安装过程或嵌入式系统等资源受限场景,感兴趣的读者不妨试试看。