深度探索Linux操作系统 —— 构建根文件系统2

简介: 深度探索Linux操作系统 —— 构建根文件系统

深度探索Linux操作系统 —— 构建根文件系统1:https://developer.aliyun.com/article/1598090

6、安装X的然就会明白。

   看到输入设备驱动,读者可能会有个疑问:内核中不是包括了各种设备的驱动吗?怎么X中还要安装设备驱动?没错,输入设备的驱动是在内核中,X 中的所谓输入设备的驱动 evdev 谈不上是一个驱动了,只不过大家习惯这么称呼而已。evdev 模块并不面向任何具体输入设备,它只不过是接收和解析内核发送到用户空间的输入事件。仔细观察图 6-12 所示的 Linux 输入子系统的架构,读者自然就会明白。


9383303702daabbb839bf36d51db74d2.png


   操作系统将面对各种各样的输入设备,如鼠标、键盘、触摸屏、游戏手柄等。由于这些输入设备大部分不遵循统一的标准,所以导致应用程序,比如 X 将不得不处理来自各种输入设备的五花八门的输入事件。


   因此,内核中抽象了一个输入子系统。在输入子系统中,设备驱动面对各种各样具体的硬件设备,而输入事件经过事件处理模块处理后,将以统一的格式发送给用户空间的应用,用户空间的应用无需再为各种各样的输入事件格式疲于奔命。


   现在很多输入设备都使用 USB 接口,对于 USB 接口的输入设备,图 6-12 演化为图 6-13 所示。


17255c0fa41597fb419b93205b99160a.png


   USB 设备通过主控制器连接到主机,所以内核需要驱动 USB 主控制器。USB 流行的一个主要原因就是具有统一的标准,所以对于 USB 接口的输入设备,它们使用统一的设备驱动,即图 6-13 中的 USB HID 驱动。


   通过上面的讨论可见,从操作系统的角度,安装 X 的输入设备驱动事实上有两件事需要做:一是需要配置内核的输入设备相关的驱动和模块;二是安装 X 的 evdev 模块。


7、运行X服务器

   X 服务器将建立一个套接字与应用程序进行通信,通常这个套接字被命名为 “/tmp/.X11-unix/X0” ,0 表示是第一个 X 服务器,如果再启动第二个 X 服务器,则为 “/tmp/.X11-unix/X1” 。除了建立套接字外,X 服务器还将在 /tmp 目录下建立一个锁文件,例如对于第一个 X 服务器,这个锁文件为 “/tmp/.X0-lock” 。另外,在前面编译时,我们指定 X 服务器将日志文件存放在 /var/log 目录下,因此,我们需要在根文件系统中建立这两个目录:


06ca582d8057bb035003e10e7a5d985c.png

   为了使书中的截图不至于尺寸过大,笔者将vita系统的 X 服务器的分辨率设置为 “640×480” 。最初,X 服务器完全由用户通过书写配置文件的方式手动配置,在 udev 出现后,X 服务器采用了自动配置技术。但是 X 也给用户留有机会进行手动微调,并且用户手动配置的优先级还要更高。当然读者不必设置分辨率,由 X 服务器自动探测即可。通过 xorg.conf 设定分辨率的方法如下:

09ffa77e655627c65f4adc8f68aea6f3.png


   最初,X 服务器启动后将创建并显示鼠标指针。后来,X 的开发人员认为只有在应用程序明确表明需要与用户进行交互时,才应该显示鼠标指针。所以,这个默认行为发生了改变,在 X 服务器启动后,不再默认创建并显示鼠标指针,而是在第一个应用明确调用类似 XDefineCursor 这样的函数请求X服务器显示鼠标后,才显示鼠标指针。


   但是 X 还是为用户留了余地,增加了一个命令行参数 “-retro” 。如果用户运行 X 服务器启动时即创建和显示鼠标,那么给 X 服务器传递这个参数即可。


   在默认情况下,当最后一个 X 应用断开与 X 服务器的连接后,X 服务器默认自动重置。同样,X 也为这个行为提供了修正的机会,用户可以使用命令行参数 “-noreset” 关闭这个特性。vita 系统不需要这个特性,因此我们传递了 “-noreset” 参数给 X 服务器。


   最后,使用如下命令运行 X 服务器:

Xorg -retro -noreset &

    在 X 服务器启动成功后,将创建一个根窗口,作为未来所有用户窗口的根。默认情况下,这个根窗口只以一个简单的灰色背景显示。并且我们看到,X 也按照我们的要求,创建并显示了鼠标指针。

8、一个简单的X程序

  我们使用 Xlib 编写一个简单的 X 程序来确认 X 服务器是否已经正常工作。这个程序非常简单,就是创建一个窗口,并在其上显示字符串 “Hello X Window!”,代码如下:

// /vita/build/hello_x/hello_x.c:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
  Display *dpy;
  int screen_num;
  Window win;
  int x, y:
  unsigned int w, h;
  Atom atom_win_type, atom_win_type_normal;
  XEvent e;
  GC gc;
  char *s = "Hello x Window !";
  
  if (!(dpy = XOpenDisplay (NULL))) {
    fprintf(stderr, "Can't connect to X sever!\n");
    return -1;
  }
  screen_num = DefaultScreen(dpy) ;
  × = у = 20;
  w = DisplayWidth(dpy, screen_num) / 2;
  h = DisplayHeight (dpy, screen_num) / 2;
  win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
      x, y, w, h, 2, BlackPixel(dpy, screen_num),
      WhitePixel (dpy, screen num));
      
  XStoreName(dpy, win, "Hello X11");
  atom_win_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
  atom_win_type_normal = XInternAtom(dpy,
      "_NET_WM_WINDOW_TYPE_NORMAL", False);
  XChangeProperty(dpy, win, atom_win_type, XA_ATOM,
      32, PropModeReplace,
      (unsigned char *)&atom_win_type_normal, 1);
      
  XSelectInput (dpy, win, ExposureMask)
  gc = XCreateGC(dpy, win, 0, 0);
  XMapWindow(dpy, win);

  while (1) {
    XNextEvent (dpy, &e);
    switch (e.type) {
      case Expose:
        XDrawString(dpy, win, gc, 30, 30, s, strlen(s));
        break;
    }
  }
}

编译这个程序的 Makefile 如下:

# /vita/build/hello_x/Makefile:
LDFLAGS=`pkg-config --libs x11`
hello_x: hello_x.o
clean:
  rm -rf hello x *.o

    在登录到vita的终端中,使用如下命令启动X服务器,并运行应用程序 hello_x:

Xorg -retro &
export DISPLAY=:0.0
./hello_x &

注意环境变量DISPLAY的设置,其格式如下:


hostname: displaynumber.screennumber


   如果主机名(hostname)为空,则表示 X 服务器运行在本机。读者可以把 display 理解为一个 X 服务器,screen 这里无须解释。displaynumber 和 screennumber 均从 0 开始计数,如值为 “:0.0” 表示运行在本机的第一个 X 服务器接的第一块屏幕。vita系统只启动了一个 X 服务器,并且只接一块屏。所以自然将环境变量 DISPLAY 设置为 “:0.0” 。


9、配置内核支持 DRM

   如果读者是在真实机器上调试的,那么为了使 GPU 的 2D 驱动和 3D 驱动都可以正常工作,内核中还需要进行相关的配置,因为用户空间的 GPU 驱动是通过内核中的 DRM 访问 GPU 的。GPU 用户空间的驱动(2D 和 3D 驱动)和内核空间的驱动(DRM 模块)之间的关系如图 6-22 所示。


0fb879a3a68e4391e1dd6ed5c435d998.png


九、安装图形库

   前面,我们使用 Xlib 编写了一个小程序。但是我们也看到,Xlib 是多么的原始,使用 X 提供的库编写一个如此简单的程序是多么的复杂,更别提具有复杂图形用户界面的程序了。所以先辈开发者们前赴后继,尝试在 Xlib 的基础上为 X 开发更高级的图形库,这些图形库通常被称为 Widget Libraries 或 Toolkits ,其中最著名的就是 GTK 和 QT 。这些图形库引入了控件的概念,极大简化了程序开发,也提高了开发效率。


   我们选择 GTK 作为 vita 系统的图形库。这一节,我们就来编译安装 GTK。相比于安装 X ,图形库的安装过程相对要简单,但是我们也提供了一个编译脚本 build-gtk.sh 。必要时,读者可以参考这个脚本。


1、安装 GLib 和 libffi

   GLib 是 GTK+ 和 GNOME 工程的基础底层核心程序库,是一个实用的轻量级的库,它提供常用的数据结构、相关的处理函数和一些运行时支承机制,如事件循环、线程、对象系统等。因此安装 GTK+ 前首先需要安装 GLib 。GLib 目前也由开发 GTK+ 的团队维护。


   因为 GLib 提供的对象系统(GObject)可以绑定到多种语言,常见的如 C、Python、Ruby 等,因此,GLib 的对象系统借助库 libffi 处理不同语言间的函数调用。libffi 是专门设计的一个库,主要用于不同语言间的相互调用。因此,安装 GLib 前还需要安装 libffi 。


   libffi 和 GLib 的编译安装命令如下:


6ef07c8492be91f20a46d7edc59df3d7.png


2、安装ATK

   ATK(Accessibility ToolKit)是 GTK 中实现辅助功能使用的库,包括辅助视觉、听觉、打字等。这个库也是别无选择,必须要安装的,安装命令如下:

7374c768151292cf37ee62404dde9997.png



3、安装libpng

   图形库当然离不开图片格式处理的库,常用的图片格式有多种,比如 PNG、JPEG 等。但是为了简单起见,vita 系统只支持 PNG 图片格式。处理 PNG 图形格式的库是 libpng ,安装命令如下:


fe52787bca12d3c921d83bd505d09caa.png


4、安装GdkPixbuf

   GTK 使用 GdkPixbuf 进行图片的渲染,是 GTK 图形库的基本依赖之一,是必须安装的,安装命令如下:


2c6a7789a8e25434f31ae94dfe392a79.png


5、安装Fontconfig

   Linux 最初在我国的程序员中流行时,有很多程序员热衷于 Linux 的美化,其中优化文字的显示是其中主要内容之一,至今在各个 Linux 论坛仍然可见 Linux 美化的身影。文本渲染比较烦琐,除了技术原因外,文本处理机制不断的发展变化,从最初的 X 的核心字体,到 X 的字体服务器,再到现在广泛采用的客户端渲染,也给这个本身就不是特别容易理解的领域增加了很多复杂性。


   凡是涉及字体相关的地方,我们经常看到如 Fontconfig、Freetype、Pango, 甚至更多,这些库在文本渲染中都担任什么角色?它们之间的关系又是什么?在我们埋头搭建系统时,还是要不时抬头看看路的。下面,我们就结合图 6-28 来简单地介绍一下文本的渲染。


7cae6b62227955597e820ce518a76e4b.png


(1)字符编码(character code)

   虽然我们在写程序时,直接使用可读的字符,但事实上,在程序内部,是用字符的编码来代表字符的。字符的编码有多种标准,比如 ISO-8859 系列编码,Unicode 编码以及我国的 GB18030 等。

   假设系统使用 UTF8 编码,当程序准备显示字符串 “你好Linux!” 时,程序中将以编码 “4F60 597D 4C 69…” 来记录这个字符串。


(2)字形(glyph)

   字形是字的形体的简称,GB/T 16964《信息技术字型信息交换》中关于字形的的定义为:一个可以辨认的抽象的图形符号,它不依赖于任何特定的设计。


   这样解释读者可能依然会感到比较生疏,因为平时我们很少使用这个概念,但是提到字体,大家就一定比较熟悉了,因为操作系统中一定要安装字体文件的,否则是不能正确显示字符的。而所谓的这个字体文件,其实就是字形的集合。


   以 TrueType 字体文件为例,其中包含两个关键的数据结构:


   ◆ 一个是字形表,也称为 glyf 。字形表中每一项代表一个字形,使用字形索引访问其中的字形。TrueType 的字形表中,每个字形的描述并非如图 6-28 中的字形表(glyf)中显示的那样直观,字形表中描述的字形信息都是矢量的,字符的每一个笔画都是由多条曲线包围而形成的。一次曲线需要两个点来确定,二次需要三个点,三次就需要四个点。字体内部保存了这些点的坐标。


   ◆ 一个是字符编码到字形映射表(Character to Glyph Mapping),简称 cmap 。读者可能会有个疑问,cmap 中的第二列为什么不是字形,而是字形索引呢?原因是字体文件可能使用在不同的编码环境中,所以字体文件可能包含多个 cmap 表,比如 UTF8 对应一个 cmap 表,GB18030 对应另外一个 cmap 表。另外,一个字体文件中也可能不只包含一种字体。


(3)排版(layout)

   每每谈到文本渲染时,大家更多的关注在字体上,却往往忽略了文本的布局排版。实际上,文字的排版是重要而且复杂的。排版引擎需要将单个字符按照一定的间距美观的排列起来。


   除了处理字形信息外,由于世界上有多种文字体系,因此,文本可能是多种语言混合的。而且,还有像阿拉伯文、希伯来文这种文字体系是从右向左书写,更别提布局规则极其复杂的印度系文字。


   可见,排版引擎是一位真正的幕后英雄。而且,文本渲染的过程都是由排版引擎牵头开始的,不同的图形库可能使用不同的排版引擎,GTK 使用的排版引擎是 Pango 。


(4)确定字体

   在将字符编码转化为字符前,首先需要确定字体文件,否则巧妇也难为无米之炊。一个系统中可能安装了多个字体文件,因此,在众多的字体文件中要选择一个最合适的,这就是 Fontconfig 的主要任务之一。


(5)光栅化

   一旦字体确定后,Fontconfig 使用库 Freetype 提供的接口,确定字符编码对应的字形索引,依据的就是如 TrueType 字体文件中的 cmap 表。最后,Freetype 根据字形索引,从字体文件的字形表中获取描述字形的矢量信息,构建具体的字形,这个过程也叫光栅化。经过光栅化的字符编码,就是一普通图形了,接下来无论是显示到具体窗口中,还是进行其他处理,都与处理普通的图形完全相同。


   理解了各个库的作用后,下面我们开始安装这些库。


   Freetype 在前面安装 X 时已经安装,接下来只需安装 Fontconfig 和 Pango 。由于 Cairo 依赖于 Fontconfig ,而 Pango 又基于 Cairo 进行字体渲染,所以,这里的安装顺序看上去有点奇怪。我们先安装 Fontconfig,中间插播 Cairo,然后才安装 Pango。


安装 Fontconfig 的命令如下:

0c19016684e488baa5618aed326643bb.png



6、安装Cairo

   Cairo 是一个矢量图形库,GTK 使用其作为绘制后端。换句话说,GTK 的绘制动作由 Cairo 完成。看到这里,读者可能会非常困惑:X 上的应用不是由 X 服务器负责绘制吗?没错,暂且不提我们第 8 章讨论的 DRI。事实上,即使普通的 2D 应用也是可以自己绘制的,只不过,应用是将内容绘制在一个离屏的区域,但是最后还是要请求 X 服务器将绘制的内容显示到屏幕上。应用或者将绘制的内容复制到 X 服务器,或者使用 X 提供的 RENDER 扩展。当然,应用也可以将全部绘制请求 X 服务器完成,这就要看具体图形库采用的策略了。


   安装 Cairo 的命令如下:


8f529902caa2bfd6fdc4f16989472cc1.png


7、安装Pango

安装Pango的命令如下:


ea533d25a6fcc52cc3bb0011298e80e3.png


8、安装libXi

图形库当然是要接收用户输入的,X 输入扩展协议的实现是库 libXi,安装命令如下:


45d272c055bc3c9fcf9b3b79a5ccdfdc.png


9、安装GTK

   GTK 的基本依赖已经安装完成,只差完成最后一步了,安装GTK的命令如下:


633292bc2ed7a55cf6b9d499c0040295.png

   至此,图形库 GTK 的安装过程已经全部完成,读者可以将 /vita/sysroot 目录下的文件系统更新到vita的根文件系统了。


10、安装GTK图形库的善后工作

   更新了vita系统的根文件系统后,在运行使用 GTK 编写的程序前,我们还要在vita系统上为图形库做一点收尾工作。注意下面两个操作需要在使用安装了 GTK 图形库的根文件系统重启vita系统后进行。


(1)为 Pango 创建语系和模块对应关系的文件

   不同语系,对布局有不同的要求,全世界有各种各样的语系,如汉语、阿拉伯语、印度语等。Pango 采用模块化的方式提供对这些语系的支持。为了提高效率,在运行时,Pango 不会到文件系统中解析具体的模块,查看其支持的语系,而是直接读取/etc/pango目录下的文件pango.modules,其中记录了每个模块及其支持的语系。因此,我们需要为Pango创建文件pango.modules 。


(2)为库 GdkPixbuf 创建模块信息文件

   在安装库 GdkPixbuf 时,我们看到,GdkPixbuf 使用模块的形式支持各图形格式。因此,在这个库初始化时,需要加载这些模块。但是这些模块存储在文件系统的什么位置,每个模块又支持什么图形格式等,诸如此类信息从哪里获取呢?为了提高加载速度,GdkPixbuf 没有去再次扫描每个模块,而是直接从系统的一个文件中读取,因此,我们需要为 GdkPixbuf 创建这个文件。


11、一个简单的GTK程序

   最后,我们使用一个简单的程序来测试我们的 GTK 是否工作正常,程序代码如下:

0d0ae5a135b11fe5012957cb72e1286e.png



编译该程序的Makefile文件如下:

9f7c38938bf26032b267df049d46be93.png


   可见,同样是显示一个简单的窗口,使用 GTK 编写就简单多了,那些烦琐的细节已经实现在如 GTK 等这些图形库中。编译这个程序,并将其复制到 vita 系统并运行,步骤与程序 hello_x 完全相同。


十、安装字体

   对于基于 Xlib 编写的程序,一般简单的字符使用X中的内置字体就可以应付了。X的内置字体在 libXfont 中:

f37450dc4e3395fbac3453e35465a759.png



   其中 file_6x13 中记录的就是简单的点阵字体,又称位图字体,显然这个内置的点阵字体是把每一个字符都分成 6×23 个点,然后用每个点的虚实来表示字符的轮廓。


   这也是为什么前面在没有安装字体的情况下,使用 Xlib 编写的例子可以显示字符的原因。但是既然有内置的字体,那为什么使用 GTK 的程序不能显示字符呢?原因是 GTK 程序的字体是在客户端绘制的,客户端绘制完成后,将字形位图传给 X 服务器。而 GTK 中并没有像 libXfont 那样内置了字体,所以如果系统中没有安装字体,当然应用就找不到字体了。因此,我们需要安装字体。


   字体的安装非常简单,直接把字体文件复制到相关的目录下即可。但是安装在哪个目录下呢?前面我们已经看到,Linux 使用 Fontconfig 寻找字体,因此这个问题要问 Fontconfig 。没错,Fontconfig 在其配置文件中明确指明了其寻找字体文件的目录:


9ee6ecae39bd01c3a6f89da7ef5e3ec1.png


   这里,我们使用文泉驿字体,并将其安装到vita系统的 /usr/share/fonts 目录下,命令如下:


193d197405a77a74f12188461a7c052c.png


   安装完字体后,再次执行 gtk_hello,就会发现字符不再是一个一个的 “方框” 了。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
2天前
|
存储 安全 Linux
探索Linux操作系统的心脏:内核
在这篇文章中,我们将深入探讨Linux操作系统的核心—内核。通过简单易懂的语言和比喻,我们会发现内核是如何像心脏一样为系统提供动力,处理数据,并保持一切顺畅运行。从文件系统的管理到进程调度,再到设备驱动,我们将一探究竟,看看内核是怎样支撑起整个操作系统的大厦。无论你是计算机新手还是资深用户,这篇文章都将带你领略Linux内核的魅力,让你对这台复杂机器的内部运作有一个清晰的认识。
12 3
|
2天前
|
存储 数据挖掘 Linux
服务器数据恢复—Linux操作系统网站服务器数据恢复案例
服务器数据恢复环境: 一台linux操作系统服务器上跑了几十个网站,服务器上只有一块SATA硬盘。 服务器故障: 服务器突然宕机,尝试再次启动失败。将硬盘拆下检测,发现存在坏扇区
|
4天前
|
安全 Android开发 数据安全/隐私保护
构建未来:移动应用开发与操作系统的融合之道
在数字化浪潮中,移动应用和操作系统如同现代文明的双子星座。本文将探索它们之间的紧密联系,揭示如何通过技术创新和设计哲学的融合,共同塑造我们的数字生活。从用户体验到系统性能,我们将一窥这些看似简单却复杂的互动是如何影响我们日常生活的。
|
6天前
|
存储 Linux 索引
Linux 下最主流的文件系统格式——ext
【9月更文挑战第8天】硬盘被划分为若干相同大小的块(Block),默认大小为4K,便于灵活管理文件数据。文件数据分散存放于这些块中,提高了数据添加、删除和插入的便利性。
|
12天前
|
Java 开发工具 Android开发
移动应用开发之旅:探索移动操作系统与应用构建的奥秘
【8月更文挑战第33天】在数字时代的浪潮中,移动应用已成为我们日常生活的一部分。本文将带您深入理解移动操作系统的工作原理,并揭示如何在这个多姿多彩的平台上开发出引人入胜的应用。我们将从基础概念出发,逐步深入到高级编程技巧,最终通过一个实际的代码示例,展示如何将理论应用于实践。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的见解和灵感。让我们一起踏上这场激动人心的移动应用开发之旅吧!
|
13天前
|
机器学习/深度学习 vr&ar Android开发
构建未来:移动应用开发与操作系统的革新之路
【9月更文挑战第1天】 在数字时代的浪潮中,移动应用和操作系统是推动技术前进的重要力量。本文将深入探讨移动应用开发的新趋势、移动操作系统的创新演进,以及它们如何共同塑造我们的未来生活。通过分析当前技术发展的现状和挑战,我们将一窥即将到来的技术变革,并理解这些变化对个人和社会的深远影响。
28 1
|
2天前
|
存储 缓存 Linux
Linux文件系统的功能规划
【9月更文挑战第12天】本文通过类比图书馆,形象地解释了文件系统的组织形式和管理方法。首先,文件系统需按块存储文件,并设有索引区方便查找。其次,热点文件应有缓存层提高效率,文件需分类存储以便管理。最后,Linux内核需记录文件使用情况,通过文件描述符区分不同文件,确保文件操作准确无误。
|
14天前
|
开发者 API 开发框架
Xamarin 在教育应用开发中的应用:从课程笔记到互动测验,全面解析使用Xamarin.Forms构建多功能教育平台的技术细节与实战示例
【8月更文挑战第31天】Xamarin 作为一款强大的跨平台移动开发框架,在教育应用开发中展现了巨大潜力。它允许开发者使用单一的 C# 代码库构建 iOS、Android 和 Windows 应用,确保不同设备上的一致体验。Xamarin 提供广泛的 API 支持,便于访问摄像头、GPS 等原生功能。本文通过一个简单的教育应用示例——课程笔记和测验功能,展示了 Xamarin 在实际开发中的应用过程。从定义用户界面到实现保存笔记和检查答案的逻辑,Xamarin 展现了其在教育应用开发中的高效性和灵活性。
24 0
|
14天前
|
人工智能 Java 物联网
构建未来:移动应用开发与操作系统的融合之旅
【8月更文挑战第31天】在数字时代的浪潮中,移动应用和操作系统成为我们日常生活和工作的基石。本文将深入探讨移动应用开发的核心概念、移动操作系统的架构,并通过一个实际的开发案例,展示如何将创新理念融入应用设计之中。我们将从基础出发,逐步深入到高级话题,旨在为读者提供一个全面而深刻的技术洞见。
|
14天前
|
网络协议 Linux Shell
探索Linux操作系统:从基础到高级编程
【8月更文挑战第31天】本文旨在为读者提供一条清晰的路径,从Linux操作系统的基础知识出发,逐步深入到高级编程技巧。我们将一起揭开Linux神秘的面纱,了解其内部工作原理,并通过实际代码示例加深理解。无论你是初学者还是有一定经验的开发者,这篇文章都将为你带来新的视角和技能提升。