LFS 构建与学习
| 2024-4-28
0  |  Read Time 0 min
type
Post
status
Published
date
Jun 20, 2023
slug
lfs-build-and-learn
summary
感谢 Linux From Scratch 一书以及翻译、中文社区做出的贡献,在本次构建中学习到了很多。
tags
运维
学习
Linux
category
学习思考
icon
password

参考资料致谢

该文仅作学习目的,绝大部分的内容都从 Linux.cn Translation Team (lctt.github.io)3.1. 概述 (xry111.site) 中摘抄复现,再次感谢 LINUX.CN TRANSLATION TEAM 对社区做的贡献。

学习时间

Jun 20, 2023 - Jun 23, 2023

目前进度

Jun 20, 2023: 构建 LFS 至 GCC 部分
Jun 21, 2023: 发现所使用的 LFS Book 有点老,过时了,所以更换至新版的重新做一遍进度至第六章交叉编译临时工具
Jun 22, 2023: 到其他临时工具Gettext第一个(7.7)
Jun 23, 2023: 跳过了一些软件包的编译安装,成功开机!

主机环境准备

本次还没深入到后面,根据U2说明,这里可以先不分区,并且先使用lxc来进行实验。为了实验可中断与恢复,这里使用 tmux 来进行管理,按下Ctrl+b,d即可暂时退出,使用 tmux attach 即可恢复。
lxc 这里使用了 Tari 的 arch-playground 来进行实验,感谢 U2 和 Tari 的支持。

LFS环境准备

这里的LFS使用的是Tari家的 Arch-Playground,暂时不创建新分区,将目录放到 /mnt/lfs,并新建环境变量 LFS=/mnt/lfs

创建目录环境准备

下载之前先创建目录 mkdir -v $LFS/sources ,并且开启目录的写权限和粘滞模式 chmod -v a+wt $LFS/sources 。这里使用粘滞模式是为了确保在构建过程中所需的临时文件和目录不会被意外删除或更改,多个用户都对某个目录有写权限,但只有文件的所有者能够删除文件。

下载wget列表

执行 wget https://lfs.xry111.site/zh_CN/development/wget-list-sysv 下载LFS所需的文件列表,然后执行 wget --input-file=wget-list-sysv --continue --directory-prefix=$LFS/sources 来下载这些文件。

校验md5

下载md5sums文件 ,执行

创建目录布局

为 LFS 分区创建 /etc, /var, /usr/bin, /usr/lib, /usr/sbin

创建编译后安装的软件目录

运行 mkdir -v $LFS/tools ,执行 ln -sv $LFS/tools / 将这个目录创建为根目录的符号链接
这使得宿主机根目录下的工具链总是指向 /tools 。可以确保在 LFS 构建过程中,系统能够正确地找到并使用所需的构建工具,从而顺利进行构建操作。

添加LFS用户

为了防止清理大师,这里添加一个lfs用户组/用户。在LFS书本上使用的方法是
-k /dev/null 是为了使用户目录不包含任何默认配置文件,确保用户目录干净、空白

设置LFS用户下的环境

运行
为lfs用户创建 bash_profile ,排除其他不安全的因素。
运行
我在使用的 Arch 环境有 /etc/bash.bashrc ,有可能会干扰LFS软件包的构建,可以先移到一边。
执行 source ~/.bash_profile 准备环境

设置并行构建减少时间

TARI 所使用的环境是一颗 Intel(R) Core(TM) i7-10700F ,它拥有十六颗核心,所以可以设定16个同时运行的进程来减少构建时间。
可设置 export MAKEFLAGS='-j16'make -j16

构建临时系统

在这一章节中,编译出来的文件都将放在 $LFS/tools ,因为不想让它影响 $LFS/sources
这里要求先安装Binutils,能获得必要的二进制工具,例如汇编器(as)和链接器(ld),来支持后面的编译过程。然后安装GCC编译器,GCC的构建过程将使用Binutils提供的工具来生成可执行程序。经过第一次gcc的configure,我们能看到gcc配置文件所使用的是/tools下的工具链。
然后安装净化的Linux API头文件和Glibc
这里是相关的一些注意事项,包括正确设置LFS环境变量,查看sh、awk、yacc(yacc这里有可能是一个脚本,grep一下bison看看有没有就行)是否为指定符号链接,刚刚下的源文件是不是在 /mnt/lfs/sources 并且cd过去,而且在lfs用户中

安装编译Binutils

解压Binutils tar -xvf binutils-2.40.tar.xz ,切换进解压目录后创建一个build文件夹并切换进去,执行configure生成makefile
然后继续执行 make 来编译软件包
安装软件包 make install
删除解压出来的目录 rm -rf binutils-2.40

安装编译gcc

首先先解压gcc目录,顺便需要先安装编译GMP、MPFR、MPC[?]
更新后删除
根据原文描述,这段代码的作用时为了确保GCC编译器使用 /tools 目录中的工具链而不是宿主机上的工具链,以便在构建LFS系统时正确地编译和链接软件包。
执行后会进行以下几个操作
然后执行下面这个(虽然本机本来就是在x86_64上跑的,case了好像也没啥用,估计是从原来的代码上摘下来的?)
新建一个目录build编译gcc,然后切换进去,配置选项
然后进行 make 和 make install,首次编译不需要进行测试,因为第一遍编译的程序很快就会被取代。(第一次更新也就是所谓的,Host是本机,但是生成的玩意是给LFS用的)
这里我第一次make有一个卡了很久,不知道原因,删掉重新编译就好了
然后合并 limitx.h glimits.h limity.h 创建一个完整的limits.h内部头文件(这个文件定义了一些基本的系统限制,如整数类型的最大值和最小值,字符类型的位数,指针类型的大小等等),具体原因见[?]
删除 gcc 文件夹

安装 Linux API 头文件

Linux API 是操作系统提供的一组编程接口,它包含了许多与操作系统相关的函数、变量和宏等,可以帮助程序员编写能够与操作系统交互的程序。例如,Linux API 中包含了许多文件操作函数,如 open()、read()、write() 等等,可以帮助程序员在程序中进行文件的读写操作。在 Linux 系统上进行 C 语言编程时,需要使用 Linux API 头文件,以便在程序中调用操作系统提供的接口。
解压 linux-6.3.8.tar.xz,切换目录。
执行 make mrproper,删除所有生成的目标文件和中间文件、内核镜像文件、配置文件、标签文件和依赖关系文件,确保没有遗留的陈旧文件
执行 make headers,在交叉编译工具链中生成一些头文件,之后会复制到LFS系统中
删除linux-6.3.8文件夹

安装 Glibc

Glibc 是 GNU C 库的缩写,是一组与 C 语言编程相关的库函数和头文件。它提供了许多常用的函数和数据结构,如字符串操作函数、数学函数、进程管理函数等等,可以帮助程序员编写更加高效、可靠的程序。在 Linux 系统上进行 C 语言编程时,需要安装 Glibc 库和头文件,以便在程序中使用这些库函数。
哇,是熟悉的老爹(ld),之前在尝试LD_PRELOAD的时候就见过这玩意,它包含了一些共享库的东西,比如我们常用的printf都得从这拿,现在我们要将它编译出来。
执行以下内容,使ld链接到 $LFS/lib64 ,同时链接到文件 $LFS/lib64/ld-lsb-x86-64.so.3
应用一个补丁到Glibc源代码中,以使得Glibc程序在FHS(Filesystem Hierarchy Standard,Linux文件系统层次结构标准)兼容的位置存放运行时数据。
在一些旧版的Glibc程序中,会使用与FHS不兼容的/var/db目录存放它们的运行时数据,这违反了FHS的规范。为了解决这个问题,需要应用一个名为"glibc-2.37-fhs-1.patch"的补丁,该补丁会修改Glibc源代码中的一些文件,以使得Glibc程序可以在FHS标准中定义的位置存放运行时数据。
这个patch是给源代码patch的。
然后新建一个build文件夹,再cd进去
设置,使 ldconfig 和 sln 安装到 /usr/sbin
准备安装 glibc
然后编译出错,因为没有 Python (阿哲,编译glibc竟然会用到python??)
然后make,make完以后 make DESTDIR=$LFS install
(这里知识点来了,为什么 DESTDIR 会和 prefix 不一样?可以见问题9)
执行sed '/RTLDLIST=/s@/usr@@g' -i $LFS/usr/bin/ldd ,替换掉 RTLDLIST 的 /usr

确认新工具链工作正常

按照 LFS Book 的流程,编写一个简单的C语言程序,编译并查看其编译使用的解释器
这里 $LFS_TGT-gcc 经过环境变量替换后实际上是 x86_64-lfs-linux-gnu-gcc ,可以直接执行,因为之前修改过PATH指向tools上,然后会吐出一个 a.out ,用readelf 读取一下看看正不正常就行了
完事删除一下生成的文件

安装Libstdc++

Libstdc++ 是 GNU C++ 标准库,它包含了一系列的 C++ 标准库函数和类。在 LFS 中,Libstdc++ 主要作用是提供 C++ 标准库的支持,使得 LFS 系统能够编译和运行 C++ 程序。 在编译 C++ 程序时,编译器会使用 C++ 标准库中的一些函数和类。如果没有正确的 C++ 标准库支持,就会导致编译错误或运行时错误。因此,在构建 LFS 系统时,需要安装 Libstdc++ 库,以便提供 C++ 标准库的支持。同时,还需要在交叉编译器中设置正确的 Libstdc++ 路径,以便在编译 C++ 程序时正确地链接标准库。
解压 gcc 压缩包(对,这里是gcc,不是单独的 libstdc++),然后创建构建目录build并切换,执行 configure 准备编译
然后就是经典的 make 和 make DESTDIR=$LFS install
这里需要移除对交叉编译有害的libtool文档文件,也不算有害吧,就是用不到,原因见问题15

交叉编译临时工具

这里安装一些工具,比如M4,bash之类的,这里就按照LFS Book的教程一个个安装就行了。
coreutils - 安装类似 ls if echo mv cp这种常见指令
findutils - find 指令
file - 用于确定文件类型,比如确定是一个普通的文本文件,还是一个shell文件,还是一个elf文件
同时还要二次安装 binutils和gcc,这里注意参数的变化,包括prefix的变化以及with-sysroot的变化,一开始都是 $LFS 目录下的,后面直接不设置了。容易产生误解的是gcc的 with-build-sysroot 的变化,注意这个参数虽然还是 $LFS 下的,但是它代表的是编译时使用的目录,编译后我也不会硬编码进gcc,也就是编译后到底读哪就跟这个参数没有关系了。

进入chroot并构建其他工具

将文件夹权限从lfs给回root

具体原因见 问题20

准备虚拟内核文件系统

目前我们构建的LFS系统的目录是这样的
可以发现,我们使用的什么 /dev /proc 之类的文件夹都还没有呢,所以我们要先创建并挂载
还要瞅瞅 /dev/shm ,挂载一个tmpfs。我这里shm不是一个符号链接,只是一个普通的文件夹

进入 chroot 环境

进来以后发现 UID 为0,但是提示 (lfs chroot) I have no name!:/ ,且运行 whoami 会有 whoami: cannot find name for user ID 0: No such file or directory ,这是因为 /etc/passwd 还没创建

创建必要的目录

创建必要的文件和符号链接

这里 /proc/self/mounts 查看了一下,发现没有根目录选项,应该按照官方教程是有的,但是由于我是直接在lxc上,也没有分区,但是U2说不影响.jpg

构建一些其他工具

从这里开始,编译一些工具就不再需要在外面用lfs来编译了,而只需要chroot进去用lfs的环境来编译即可。由于软件包太多了,下面直接看教程,写得写死人。
cd到/sources,然后解压,按照configure后make的流程来走。

清理并备份系统

删除临时的工具和文档

迁移环境

转移目录

由于后面越用越发现 LXC 已经无法满足需求了,所以决定迁移到正常的虚拟机上石笋
搭建一个 ubuntu-playground,然后
将刚才的lfs系统打包
chroot 进去以后
转移文件后在目标系统
tar -xvpzf system_backup.tar.gz -C /mnt/lfs

重新分区

新的硬盘在 /dev/sdb ,使用fdisk重新分区,之前是给 /boot/efi 200M,剩下的容量给根目录,这里也这么办。然后使用 mkfs.fat -F32 /dev/sdb1 格式化EFI分区,使用 mkfs.ext4 /dev/sdb2 格式化根目录分区
重新创建 /mnt/lfs,然后挂载

使LFS系统可引导

确定 /etc/fstab

由于在上面分好区了,直接写入 /etc/fstab 就行了

安装内核

切换到 linux-6.3.8 文件夹,必须先安装 Flex, bc, libelf(→zlib),openssl 。执行 make mrproper 清除不必要文件,然后通过界面 make menuconfig 来设置界面(很人性化了可以说是)
grub(→e2fsprogs→pkg-config→texinfo→xorriso
root密码(expect→tcl→shadow)
其实东西也不用全部构建,只要关键部分构建了就行了,就是找关键部分有点折磨
下面是根据grub教程修改的部分,主要修改了uuid和partuuid

LFS,启动!

开放世界(指自己下载源码编译),烧鸡(指编译CPU爆棚),椅子可以坐(指编译这玩意一坐就是一天)
notion image
notion image

自问自答

以下问题为进行实验的时候提出的,有些答案通过 ChatGPT 总结后贴上。
  1. 问:一个纯64位的系统是不能运行32位应用程序的吗?为什么现代化的系统都可以在64位系统运行32位程序?
    1. 答:因为有兼容层。比如装扩展的时候,有一些是x xx-32bit或者xxx-i386
  1. 问:设置LFS用户下的环境章节下,LFS_TGT=$(uname -m)-lfs-linux-gnu 的作用是什么?
    1. 答:为主机设置编译三元组,什么是编译三元组下面会解释。
  1. 问:为什么Binutils和GCC需要经过两次编译?
    1. 答:为了创建一个独立的、自包含的工具链环境。在开始构建LFS系统时,已经有了一个主机系统作为基础,它安装了自己的Bintuils和GCC。但是,构建LFS时,需要一个全新的系统,包括Binutils和GCC,二次编译是为了确保LFS系统中使用的Binutils和GCC是专门为了LFS构建的,与主机系统的工具链相互独立,可以确保LFS系统的构建过程和最终生成的软件包与主机系统的环境无关,避免因主机系统的配置和版本差异而导致的不一致性或问题。
      这里假设说,目标lfs是 aarch64 架构的,假设我自己的机器上本身只有一个 host=x86_64, target=x86_64 ,那我就没办法生成一个 aarch64 架构的编译器,所谓的编译器就是:我跑在host上,我要生成target的目标程序,所以我的第一步工作就是要生成一个能跑在 x86_64 上,但是生成的目标程序是给 aarch64 用的
      这么理解以后,如果我要生成一个跑在 aarch64 上的程序,且未来我自己也有能力再编译源码继续跑在 aarch64 上,我就需要生成一个跑在 aarch64 上,目标程序也在 aarch64 上的GCC程序。
      所以一开始要用 host=x86_64,target=x86_64 的编译器生成出来一个host=x86_64,target=aarch64 ,然后再通过这个编译器生成出来一个host=aarch64,target=aarch64。
      LFS构建阶段分为三个阶段[?],第一阶段是在PC(已构建好的发行版)上使用cc-pc(PC上的编译器)构建cc1(中间编译器),此时构建程序使用的(Build)、将来会运行被构建程序的(Host)是已构建的发行版,而为lfs产生代码。也就是我一开始只能生成能跑在PC上的编译器,但是我可以将目标产物换成能跑在LTS上的了。
      那只能由PC生成不够啊,我LFS也想自己生成,所以第二阶段则是将中间编译器换成刚刚构建好的cc1(中间编译器),目标产物是要使编译器能够在LFS上生成,也能在LFS自己编译后跑得动。
      第三阶段,那就是全部在LFS上跑,只要都能跑过,那就成功了。
  1. 问:GLIBC和GCC分别是什么?
    1. 答:glibc 是 C 库,提供了基本的系统功能和接口,用于支持程序的运行。它是 Linux 系统中的默认 C 库。提供了一些常见的,比如printf, scanf等函数。
      GCC 是编译器套件,支持多种编程语言,用于将源代码编译为可执行程序或库。它提供了编译器和相关工具,帮助开发者编写高效的代码。
  1. 问:configure 文件是用来干嘛的
    1. 答:通常用来生成makefile,通常会使用autoconf工具链来自动生成可移植的构建系统
  1. 问:为什么GCC需要GMP、MPFR和MPC软件包?GCC本来没有吗?
    1. 答:GMP是一个用于高精度整数运算的库,提供了高效可移植的多精度算数操作。MPFR则是用于高精度浮点数,MPC用于高精度复数,这三个库能够使GCC处理高精度整数、浮点数和附属运算。
      GCC原本也不包含这三个库,而将这三个库独立作为GCC外部依赖项,可以让其独立维护和发展,同时提高可配置性和可移植性。
  1. 问:什么是编译三元组/目标三元组?
    1. 答:编译三元组(Compile Triple)是一个由三个部分组成的标识符,用于唯一标识一个特定的目标体系(target system)。它通常用于交叉编译的环境中,表示编译器和生成的可执行程序所针对的目标平台。
      三元组由 Architecture-Vendor-(-Kernel-Operating System) 组成
      常见的编译三元组比如有:x86_64-pc-linux-gnu, x86_64-apple-darwin
      还有一些编译三元组中间还会跟一个 -Kernel-,比如 aarch64-unknown—linux-android 表示运行在 ARM64 智能手机上的 Android, aarch64-unknown-linux-gnu 则可被表示用于 ARM64 服务器上的Ubuntu,它们的区别仅在于后面的系统,如果三元组只有三个部分则无法正确表示。
      还有一些比如有 riscv32-unknown-windows-msvc (实际上并不存在,因为压根没有 risc-v 的 Windows),用于标识 RISC-V 32 位架构在 Windows 操作系统上使用 MSVC(Microsoft Visual C++)编译器的目标平台。
  1. 问:第一次安装交叉编译的GCC时,为什么要重新定义默认的 STARTFILE 前缀?
    1. 答:重新定义默认的startfile前缀是为了解决交叉编译器(cross-compiler)的问题。交叉编译器是一种在一种操作系统或体系结构上生成另一种操作系统或体系结构的可执行文件的编译器。由于编译器本身是在宿主系统上编译的,因此它们默认会使用宿主系统的标准启动文件路径。但是,当我们使用交叉编译器时,需要使用目标系统的启动文件,而这些启动文件在宿主系统上是不可用的。 通过重新定义默认的startfile前缀,我们可以告诉编译器在寻找启动文件时搜索目标系统的启动文件路径而不是宿主系统的启动文件路径。这样,我们就可以在宿主系统上使用交叉编译器来生成目标系统的可执行文件。
  1. 问:gcc 里面编译的 --prefix 和 DESTDIR 有什么区别?分开写有什么作用?
    1. 答:prefix是硬编码安装的路径(也就是编译后的程序认为自己所在的位置),而DESTDIR是暂时安装的路径(也就是编译后的程序实际被存放的位置)。
      对于挂载 /mnt/lfs 的系统,实际上就是想让它生成到 /mnt/lfs/usr,然后让lfs跑起来的时候认为自己是放到了 /usr
      所以,--prefix 应该被设为 /usr (让以后使用的lfs知道编译后的程序被放到了 /usr),而 DESTDIR 应该被设成 /mnt/lfs (让现在的程序存放到这个地址,实际路径=DESTDIR+prefix)
  1. 问:第一次安装交叉编译的GCC时,为什么要将 /lib64 替换为传统的 /lib 目录?
    1. 答:在一些 x86_64 架构的 Linux 系统上,库文件默认安装在 /lib64 目录下,而不是传统的 /lib 目录下。而 GCC 编译器默认情况下会去 /lib 目录下查找库文件,这可能会导致编译器无法找到所需的库文件而无法正常工作。 因此,这段代码的作用是修改 GCC 编译器的配置文件,以便在 x86_64 架构的系统上使用 /lib 路径来查找库文件而不是 /lib64 路径,从而确保编译器能够正确地链接库文件。这样做可以解决编译器找不到库文件的问题,使编译器在 x86_64 架构的系统上正常工作。
  1. 问:ln -sv usr/$i $LFS/$i 的时候,我本地工作目录是 /root ,会不会将 /root/bin 映射过去?
    1. 答:不会。符号链接进行链接的时候,使用的是相对路径的链接方式,这里的相对路径并不会使用目前的工作目录,而是相对于后面路径。在填充变量的时候,比如此时 $i=bin,实际的路径是 ln -sv usr/bin $LFS/bin(注意这里bin后面没有/),那么前面的是源链接,后面的是目的链接,就是 $LFS/bin 指向了 $LFS/usr/bin ,即
      notion image
  1. 问:.patch 文件是给源代码 patch 的还是给系统 patch的
    1. 答:是给源代码patch的,我们查看其部分代码就知道
      从这个源码我们可以轻松看出,这里的patch修改了 a/sysdeps/unix/sysv/linux/paths.h ,对 VARDB 的路径进行了修改,改为了 /var/lib/nss_db/
  1. 问:为什么编译 glibc 会依赖 python?
    1. 答:编译 Glibc 时需要使用 Python 脚本来自动生成一些文件。这些文件包括一些内部头文件和一些符号表,它们是 Glibc 编译和链接的必要组成部分。这些脚本可以在 ./scripts 里面看到,有一大堆的 *.py
  1. 问:(?)为什么需要修改ldd脚本中硬编码的可执行文件加载器路径
    1. 答:我们打开 /mnt/lfs/usr/bin/ldd,可以发现 RTLDLIST 行内容是
      RTLDLIST="/usr/lib/ld-linux.so.2 /usr/lib64/ld-linux-x86-64.so.2 /usr/libx32/ld-linux-x32.so.2"
      而我们在之前已经将 /lib /lib64 链接过去/usr/lib了,推测是为了统一管理?而且我们也不存在 /usr/lib64 这个文件夹,替换一下刚好能使 /lib64/ld-linux-x86-64.so.2 生效,否则就没一个能生效了
  1. 问:为什么要移除对交叉编译有害的 libtool 文档文件
    1. 答:libtools 是 GNU Libtool 工具的一部分,它用于管理库文件的编译和链接过程。在构建 LFS 系统时,由于需要进行交叉编译,因此需要使用交叉编译工具链,而 libtools 本身并不支持交叉编译,所以需要进行一些特殊的处理。
      其中,rm -v $LFS/usr/lib/lib{stdc++,stdc++fs,supc++}.la 命令的作用是删除 Libstdc++ 库中的一些不必要的文件,即 .la 文件。这些文件是由 Libtool 工具生成的,用于在编译时链接库文件。但是,在交叉编译环境下,这些文件并不是必需的,因为它们只包含本地系统的配置信息,而不包含交叉编译目标系统的信息。因此,这些文件可以删除,以减小库文件的大小,同时也可以避免在链接时出现错误。
  1. 问:为什么gcc在第二次编译的时候还要使用 with-build-sysroot 参数并指向 $LFS?
    1. 答:仅仅是因为编译的时候所使用的目录是 $LFS 的目录,和编译后硬编码的程序没有关系,所以不用担心二次编译的时候指向 $LFS 这个问题
  1. 问:gcc参数的 -lxxx 代表什么?
    1. 答:代表指定的库文件。一般来说,使用-lxxx代表使用的是libxxx.so库文件,也就是如果编译的时候发现 -ltinfo 找不到,那就是系统里没有 libtinfo.so 这个文件,查询发现是 ncurses 的东西,那么就可以先装 ncurses
  1. 问:musl和glibc的区别是什么?
    1. 答:Musl和Glibc是两个不同的C标准库,它们的主要区别在于以下几个方面:
      • 大小和性能:Musl库相对于Glibc库来说,体积更小、启动速度更快、内存占用更小,因此在嵌入式设备和轻量级系统中使用更为普遍。
      • 兼容性:Musl库相对于Glibc库来说,对POSIX标准和C标准的实现更为严格,因此在某些情况下可能会与一些应用程序不兼容,需要进行代码修改或兼容性设置。
      • 功能支持:Glibc库相对于Musl库来说,支持的功能更为丰富,例如支持多线程、多语言、动态链接等,因此在一些高级应用程序中使用更为普遍。
      • 许可证:Musl库使用的是MIT许可证,而Glibc库使用的是GNU通用公共许可证(GPL),因此在一些商业应用中,使用Musl库可能更为方便。
      需要注意的是,Musl和Glibc虽然是两个不同的C标准库,但都是符合POSIX和C标准的,因此在大部分情况下,它们的使用方式和API是相似的,只是在一些细节上可能会有所不同。
  1. 问:Busybox和Coreutils的区别是什么?
    1. 答:BusyBox和Coreutils都是常用的Linux工具集,它们都包含了许多基本的UNIX命令,例如ls、cp、mv、rm等。它们的主要区别在于以下几个方面:
      • 大小和功能:BusyBox相对于Coreutils来说,体积更小、功能更少,因此在嵌入式设备和轻量级系统中使用更为普遍。BusyBox使用了一个可配置的单一二进制文件,以替代许多独立的UNIX工具程序。而Coreutils则是一个完整的工具集,包含了大部分基本的UNIX命令。
      • 兼容性:BusyBox相对于Coreutils来说,对POSIX标准的实现更为严格,因此在一些情况下可能会与一些应用程序不兼容,需要进行代码修改或兼容性设置。而Coreutils则更为符合GNU和Linux标准。
      • 许可证:BusyBox使用的是GPL许可证,而Coreutils使用的是GPL或LGPL许可证,因此在一些商业应用中,使用Coreutils可能更为方便。
      需要注意的是,BusyBox和Coreutils虽然在体积和功能上有所不同,但它们的使用方式和命令参数基本上是相同的。在Linux系统中,可以根据具体的需求选择使用它们中的任何一个,或者同时使用它们。
  1. 问:为什么一开始要用 lfs 用户来搞前面的操作,后面又要用root?
    1. 答:单纯是为了防止你乱搞的时候伤到原来的系统而已。lfs用户可以极大地限制权限,你编译的时候都可以不用root。但是后面要chroot进去了,如果你系统里面不存在同UID的,可能后面新增用户的时候就会一下子获得了这些文件的权限,这十分危险。
  1. 问:挂载虚拟内核文件系统的时候,使用的proc sysfs似乎都不是直接指代根目录的文件夹,是系统预置的关键字吗?
    1. 答:是的。包括 sys proc dev tmpfs 这几个都是特殊挂载点,是预留关键词,所以可以通过类似
      的方式来挂载,
      /proc是一个虚拟的文件系统,它提供了进程、系统和硬件设备信息的访问接口。在Linux中,/proc目录下的文件和目录都是虚拟的,它们并不对应任何物理设备,而是由内核动态生成的。例如,/proc/cpuinfo文件提供了CPU的信息,/proc/meminfo文件提供了内存的信息,/proc/net目录提供了网络的信息,等等。
      /sys也是一个虚拟的文件系统,它提供了系统设备和驱动的信息。与/proc不同的是,/sys是一个标准的文件系统,它的内容和结构是由内核和驱动程序开发者共同定义的。在/sys目录下,每个设备都有一个对应的目录,包含了该设备的属性、状态和配置信息。
      /dev目录是Linux系统中的设备文件目录,它包含了系统中所有的设备文件。在Linux系统中,设备文件是一种特殊的文件,用于访问硬件设备、伪设备和虚拟设备等。例如,/dev/sda是一个硬盘设备文件,/dev/tty是一个终端设备文件,/dev/random是一个随机数发生器设备文件,等等。
      tmpfs是一个临时文件系统,它通常用于存储临时文件或运行时数据。与硬盘文件系统不同的是,tmpfs是一个基于内存的文件系统,它的数据存储在系统的内存中,而不是硬盘上。在Linux系统中,tmpfs通常被挂载到/tmp目录或其他临时目录中,用于存储临时文件、网络文件系统的缓存等。由于tmpfs存储在内存中,因此它的读写速度非常快,但是它的容量受到系统内存的限制。tmpfs可以有多个。
  1. 问:/dev/shm 目录是干嘛的
    1. 答:/dev/shm 目录是用于在进程之间共享数据的,程序运行时,会将一些数据存放在 /dev/shm 目录中。
      C语言程序共享数据时,会使用 shm.h 头
  1. 问:install命令是啥?
    1. 答:install 可以新建目录,在后面跟 -m 权限 可以设定改目录的权限。例如
      就新建了 /root 并设定权限为0750,并且新建了 /tmp 和 /var/tmp 并设定权限为777且有粘滞位(不允许从中删除其他用户的文件)
 

参考文章

 
  • GitTalk
Catalog