从头构建Linux系统之二 —— 搭建宿主机系统

本章会描述如何搭建宿主机系统,大致分为以下三个步骤:

  • 首先,宿主机系统需要安装一些特定版本的工具才能正确编译LFS系统。
  • 然后,还需要创建若干个LFS系统专用的磁盘分区。
  • 最后,还需要在这些磁盘分区上创建相应的文件系统,然后再将这些文件系统挂载至宿主机系统。

本章的所有操作都以root用户身份运行!

一、满足宿主机的系统需求

1. 安装宿主机系统的依赖包

从CentOS 6.6的官方镜像源,通过yum安装依赖包和头文件包:

  1. ## 安装依赖包
  2. yum install -y bash binutils bison bzip2 coreutils diffutils findutils glibc grep gzip kernel m4 make patch perl sed tar texinfo wget
  3. ## 安装头文件包
  4. yum install -y binutils-devel bison-devel bzip2-devel glibc-devel perl-devel kernel-devel kernel-headers

创建指向bison的yacc符号链接:

  1. ln -sv /usr/bin/bison /usr/bin/yacc

由于CentOS官方镜像源提供的gcc、gawk和xz软件包的版本太低,不能满足编译Linux系统的最低版本要求,因此必须下载相应的源码包,然后编译安装gcc、gawk和xz软件包。

2. 编译安装GCC

通过yum安装官方镜像源的GCC,然后才能进行自举编译:

  1. yum -y install gcc gcc-c++

下载gcc-5.2.0的源码包:

  1. cd /root/Downloads/
  2. wget http://mirrors.ustc.edu.cn/gnu/gcc/gcc-5.2.0/gcc-5.2.0.tar.gz

解压缩gcc-5.2.0的源码包:

  1. tar -zxvf gcc-5.2.0.tar.gz

下载编译所需的依赖包:

  1. cd /root/Downloads/gcc-5.2.0
  2. ./contrib/download_prerequisites
  3. cd ..

新建目录存放编译结果:

  1. mkdir gcc-build-5.2.0

进入新目录,并执行configure命令,生成makefile文件:

  1. cd gcc-build-5.2.0
  2. ../gcc-5.2.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib

编译gcc-5.2.0:

  1. make -j2

安装gcc-5.2.0:

  1. make install

更新库文件和符号链接:

  1. cp /root/Downloads/gcc-build-5.2.0/prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21 /usr/lib64
  2. ln -sf /usr/lib64/libstdc++.so.6.0.21 /usr/lib64/libstdc++.so.6

运行以下命令,检查gcc的版本:

  1. gcc --version

若返回信息如下图所示,则表示编译安装成功:

检查gcc版本

运行以下命令,检查g++的版本:

  1. g++ --version

若返回信息如下图所示,则表示编译安装成功:

检查g++版本

3. 编译安装Gawk

下载gawk-4.1.4的源码包:

  1. cd /root/Downloads
  2. wget http://mirrors.ustc.edu.cn/gnu/gawk/gawk-4.1.4.tar.gz

解压缩源码包:

  1. tar xvzf gawk-4.1.4.tar.gz

配置编译选项:

  1. cd gawk-4.1.4
  2. ./configure

编译和安装:

  1. make && make install

更新软链接:

  1. rm -rf /usr/bin/awk
  2. ln -sv /usr/local/bin/gawk /usr/bin/awk

4. 编译安装Xz

下载xz-5.2.3的源码包:

  1. cd /root/Downloads
  2. wget http://tukaani.org/xz/xz-5.2.3.tar.gz

解压缩源码包:

  1. tar xvzf xz-5.2.3.tar.gz

配置编译选项:

  1. cd xz-5.2.3
  2. ./configure

编译和安装:

  1. make && make install

5. 检查宿主机软件包的版本

宿主机系统依赖的软件包的名称和最低版本,如下表所示:

名称 最低版本 注释
Bash 3.2 /bin/sh应当是指向bash的符号链接
Binutils 2.17 不推荐使用高于2.27的版本,因为没有经过测试验证
Bison 2.3 /usr/bin/yacc应当是指向bison的符号链接
Bzip2 1.0.4
Coreutils 6.9
Diffutils 2.8.1
Findutils 4.2.31
Gawk 4.0.1 /usr/bin/awk应当是指向gawk的符号链接
GCC 4.7 不推荐使用高于6.2.0的版本,因为没有经过测试验证
Glibc 2.11 不推荐使用高于2.24的版本,因为没有经过测试验证
Grep 2.5.1a
Gzip 1.3.12
Linux Kernel 2.6.32
M4 1.4.10
Make 3.81
Patch 2.5.4
Perl 5.8.8
Sed 4.1.5
Tar 1.22
Texinfo 4.7
Xz 5.0.0

本章先前的操作已经在宿主机系统之中安装了合适版本的依赖包。可以创建一个版本检查脚本:

  1. cd /root/Downloads
  2. vi version-check.sh

version-check.sh脚本的内容如下所示:

  1. #!/bin/bash
  2. # 用于检查关键开发工具的版本号的简单脚本
  3. export LC_ALL=C
  4. # 检查Bash的版本
  5. bash --version | head -n1 | cut -d" " -f2-4
  6. MYSH=$(readlink -f /bin/sh)
  7. echo "/bin/sh -> $MYSH"
  8. echo $MYSH | grep -q bash || echo "ERROR: /bin/sh does not point to bash"
  9. unset MYSH
  10. # 检查Binutils和Bison的版本
  11. echo -n "Binutils: "; ld --version | head -n1 | cut -d" " -f3-; bison --version | head -n1
  12. if [ -h /usr/bin/yacc ]; then
  13. echo "/usr/bin/yacc -> `readlink -f /usr/bin/yacc`";
  14. elif [ -x /usr/bin/yacc ]; then
  15. echo yacc is `/usr/bin/yacc --version | head -n1`
  16. else
  17. echo "yacc not found"
  18. fi
  19. # 检查Bzip2和Coreutils的版本
  20. bzip2 --version 2>&1 < /dev/null | head -n1 | cut -d" " -f1,6-; echo -n "Coreutils: "; chown --version | head -n1 | cut -d")" -f2
  21. # 检查Diffutils的版本
  22. diff --version | head -n1
  23. # 检查Findutils的版本
  24. find --version | head -n1
  25. # 检查Gawk的版本
  26. gawk --version | head -n1
  27. if [ -h /usr/bin/awk ]; then
  28. echo "/usr/bin/awk -> `readlink -f /usr/bin/awk`";
  29. elif [ -x /usr/bin/awk ]; then
  30. echo awk is `/usr/bin/awk --version | head -n1`
  31. else
  32. echo "awk not found"
  33. fi
  34. # 检查GCC的版本
  35. gcc --version | head -n1
  36. g++ --version | head -n1
  37. # 检查Glibc的版本
  38. ldd --version | head -n1 | cut -d" " -f2- # glibc version
  39. # 检查Grep的版本
  40. grep --version | head -n1
  41. # 检查Gzip的版本
  42. gzip --version | head -n1
  43. # 检查Linux Kernel的版本
  44. cat /proc/version
  45. # 检查M4的版本
  46. m4 --version | head -n1
  47. # 检查Make的版本
  48. make --version | head -n1
  49. # 检查Patch的版本
  50. patch --version | head -n1
  51. # 检查Perl的版本
  52. echo Perl `perl -V:version`
  53. # 检查Sed的版本
  54. sed --version | head -n1
  55. # 检查Tar的版本
  56. tar --version | head -n1
  57. # 检查Texinfo的版本
  58. makeinfo --version | head -n1
  59. # 检查Xz的版本
  60. xz --version | head -n1
  61. # 检查GCC是否能正确编译
  62. echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c
  63. if [ -x dummy ]
  64. then echo "g++ compilation OK";
  65. else echo "g++ compilation failed"; fi
  66. rm -f dummy.c dummy

运行version-check.sh脚本,检查宿主机系统的依赖关系:

  1. chmod 755 version-check.sh
  2. ./version-check.sh

若脚本输出的结果如下图所示,则表示宿主机系统的依赖关系满足需求:

检查依赖关系版本

6. 检查宿主机库文件的一致性

某些Linux发行版会报告gcc使用的一些库文件可能处于一种不一致的状态,这种状态会妨碍某些LFS软件包的编译。可以在/usr/lib/usr/lib64目录中检查libgmp.lalibmpfr.lalibmpc.la文件是否存在。这三个文件要么同时都存在,要么同时都不存在,只有这两种状态才能表明gcc的库文件没有不一致的问题。如果宿主机系统出现这种不一致的问题,那么既可以重命名或删除这三个.la文件,也可以安装合适的缺失软件包。可以创建一个库文件检查脚本:

  1. cd /root/Downloads
  2. vi library-check.sh

library-check.sh脚本的内容如下所示:

  1. #!/bin/bash
  2. for lib in lib{gmp,mpfr,mpc}.la; do
  3. echo $lib: $(if find /usr/lib* -name $lib|
  4. grep -q $lib;then :;else echo not;fi) found
  5. done
  6. unset lib

运行library-check.sh脚本,检查宿主机系统的库文件一致性:

  1. chmod 755 library-check.sh
  2. ./library-check.sh

若脚本输出的结果如下图所示,则表示宿主机系统没有库文件不一致的问题:

检查库文件一致性

二、创建磁盘分区

LFS系统将会安装在专用的磁盘和分区之中,这块磁盘的容量为120GB,系统设备号为sdb。需要为这块专用磁盘划分以下七个分区:

分区 类型 文件系统 容量
/ 主分区 ext4 20480 MB
swap 主分区 swap 4096 MB
/boot 主分区 ext4 100 MB
/usr/local 逻辑分区 ext4 30720 MB
/tmp 逻辑分区 ext4 4096 MB
/usr/src 逻辑分区 ext4 30720 MB
/home 逻辑分区 ext4 其余所有

运行以下命令,列出所有磁盘的状态:

  1. fdisk -l

上述命令的输出如下图所示:

查看磁盘分区列表

其中,/dev/sda是宿主机的系统磁盘,/dev/sdb是编译安装LFS系统的专用磁盘。

可以创建一个磁盘自动分区脚本:

  1. cd /root/Downloads
  2. vi disk-partition.sh

disk-partition.sh脚本的内容如下所示:

  1. #!/bin/bash
  2. echo "
  3. n
  4. p
  5. 1
  6. 1
  7. +20480M
  8. n
  9. p
  10. 2
  11. 2613
  12. +4096M
  13. n
  14. p
  15. 3
  16. 3136
  17. +100M
  18. n
  19. e
  20. 3150
  21. 15665
  22. n
  23. 3150
  24. +30720M
  25. n
  26. 7067
  27. +4096M
  28. n
  29. 7590
  30. +30720M
  31. n
  32. 11507
  33. 15665
  34. t
  35. 2
  36. 82
  37. w
  38. " | fdisk /dev/sdb

这个脚本每行的作用如下所述:

  • 第4~8行:创建/dev/sdb1分区,这是一个主分区,容量为20480MB,用于挂载/文件系统;
  • 第9~13行:创建/dev/sdb2分区,这是一个主分区,容量为4096MB,用作内存交换区;
  • 第14~18行:创建/dev/sdb3分区,这是一个主分区,容量为100MB,用于挂载/boot文件系统;
  • 第19~22行:创建/dev/sdb4分区,这是一个扩展分区,包含所有的逻辑分区;
  • 第23~25行:创建/dev/sdb5分区,这是一个逻辑分区,容量为30720MB,用于挂载/usr/local文件系统;
  • 第26~28行:创建/dev/sdb6分区,这是一个逻辑分区,容量为4096MB,用于挂载/tmp文件系统;
  • 第29~31行:创建/dev/sdb7分区,这是一个逻辑分区,容量为30720MB,用于挂载/usr/src文件系统;
  • 第32~34行:创建/dev/sdb8分区,这是一个逻辑分区,容量为磁盘剩余的所有空间,用于挂载/home文件系统;
  • 第35~37行:/dev/sdb2分区的System ID修改为82,也就是“Linux swap / Solaris”分区类型;
  • 第38行:将分区表写入磁盘。

运行磁盘自动分区脚本:

  1. chmod 755 disk-partition.sh
  2. ./disk-partition.sh

磁盘分区创建完成之后,运行以下命令:

  1. fdisk -l /dev/sdb

上述命令的返回结果就是LFS系统专用磁盘的分区状态,如下图所示:

查看sdb分区状态

三、创建和挂载文件系统

现在,LFS系统的专用磁盘已经被划分为7个空白分区,接下来将会为每个磁盘分区创建相应的文件系统。LFS系统可以使用Linux内核能够识别的任何文件系统,本文将会使用EXT4文件系统类型(除了sdb2分区之外)。

1. 设置$LFS环境变量

本系列教程会多次使用$LFS环境变量。在LFS系统的整个编译过程中,应当确保这个环境变量始终是可用的,很多目录的路径都会以这个变量作为前缀。本章会将这个环境变量设置为专用于编译LFS系统的目录名,也就是/mnt/lfs目录。运行以下命令,设置$LFS环境变量:

  1. export LFS=/mnt/lfs

检查环境变量是否设置正确:

  1. echo $LFS

若返回信息如下图所示,则表示环境变量设置正确:

检查LFS环境变量

2. 创建和挂载“/”文件系统

这是LFS系统的根文件系统,对应于宿主机系统的$LFS目录。

创建挂载点目录:

  1. mkdir -pv $LFS

/dev/sdb1创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb1

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb1 $LFS

3. 创建和启用内存交换区

/dev/sdb2创建内存交换区:

  1. mkswap /dev/sdb2

启用内存交换区:

  1. swapon -v /dev/sdb2

若返回信息如下图所示,则表示内存交换区成功启用:

启用内存交换区

4. 创建和挂载“/boot”文件系统

这是LFS系统的/boot文件系统,对应于宿主机系统的$LFS/boot目录。

创建挂载点目录:

  1. mkdir -pv $LFS/boot

/dev/sdb3创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb3

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb3 $LFS/boot

5. 创建和挂载“/usr/local”文件系统

这是LFS系统的/usr/local文件系统,对应于宿主机系统的$LFS/usr/local目录。

创建挂载点目录:

  1. mkdir -pv $LFS/usr/local

/dev/sdb5创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb5

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb5 $LFS/usr/local

6. 创建和挂载“/tmp”文件系统

这是LFS系统的/tmp文件系统,对应于宿主机系统的$LFS/tmp目录。

创建挂载点目录:

  1. mkdir -pv $LFS/tmp

/dev/sdb6创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb6

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb6 $LFS/tmp

7. 创建和挂载“/usr/src”文件系统

这是LFS系统的/usr/src文件系统,对应于宿主机系统的$LFS/usr/src目录。

创建挂载点目录:

  1. mkdir -pv $LFS/usr/src

/dev/sdb7创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb7

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb7 $LFS/usr/src

8. 创建和挂载“/home”文件系统

这是LFS系统的/home文件系统,对应于宿主机系统的$LFS/home目录。

创建挂载点目录:

  1. mkdir -pv $LFS/home

/dev/sdb8创建ext4文件系统:

  1. mkfs -v -t ext4 /dev/sdb8

挂载文件系统:

  1. mount -v -t ext4 /dev/sdb8 $LFS/home

9. 检查文件系统

执行以下命令,检查文件系统是否成功地创建和挂载:

  1. df -lh

若返回信息如下图所示,则表示已经成功地为LFS系统的专用磁盘创建和挂载了文件系统:

检查LFS文件系统

现在,宿主机系统已经能够满足编译LFS系统的基本需求了。下一章将会介绍构成LFS系统的必要的软件包和补丁,以及它们的下载方法。