.. _lfs_prepare: ================== LFS准备工作 ================== .. note:: 中文社区翻译的LFS文档在2024年3月1日发布翻译版本12.2已经紧跟官方文档,非常方便实践,主要参考 .. note:: LFS分为两个分支: - `Linux From Scratch 版本 12.2-systemd-中文翻译版 发布于 2024 年 9 月 1 日 `_ - `Linux From Scratch 版本 12.2-中文翻译版 发布于 2024 年 9 月 1 日 `_ 考虑到我的底座系统是为了运行 :ref:`kvm` 和 :ref:`docker` ,没有复杂的主机服务,纯粹是运行环境,所以我目前采用 sysv 版本 .. warning:: 实际上官方文档包括中文版已经非常严谨,理论上按照文档一步步走下来必然能够完成构建。所以我不是完整摘抄文档,而是做一些笔记,以便后续能够自己重复完成,并且构建自动完成系统,定制能够充分发挥我的现有硬件性能的系统。 请参考管官方文档为准,本章节是一些笔记和自己的补充信息 目标架构 ============= LFS的目标架构是 AMD/Intel 的 x86(32位) 和 x86_64(64位) CPU (需要修订一些指令才能适用于Power PC和 :ref:`arm` 架构的CPU)。 构建LFS至少需要一个现有的Linux系统: - 可以是一个已经正在运行的Linux系统,现代Linux发行版(需要较新版本,对内核有和工具链有要求),我在 :ref:`lfs_mba` 中先安装一个 :ref:`arch_linux` 作为编译基础环境(同时也是向arch linux发行版学习软件组合和配置方法) - 也可以是某个发行版的LiveCD运行一个编译环境,例如我就使用 :ref:`fedora` 的一个LiveCD来完成,具体是通过 :ref:`create_vm` 运行Fedoraa LiveCD系统来编译构建 32位 vs. 64位 ---------------- - LFS官方文档是构建纯粹的64位系统,也就是值运行64位可执行程序 - 如果要构建 ``multi-lib`` 系统(同时支持32位和64位)则需要两次编译很多应用(考虑到现代硬件需要巨大的内存,远超4GB,所以我也按照官方文档构建 **纯粹64位系统** 以便获得一个精简的能够用于物理主机host底座的OS) .. _lfs_wget: 软件包选择 ============= **LFS的目标是构建一个完整且基本可用的系统** ,但是LFS并不是最小可用系统,因为LFS中有一些软件包并不是必须安装的(具体列表见 `LFS vi. 本书选择软件包的逻辑 `_ ) 勘误和安全公告 ====================== - `LFS 12.1 勘误表列出的所有修正项 `_ - `LFS 12.1 手册发布后发现的安全缺陷列表 `_ 请根据安全公告建议在构建过程中对相关操作进行修正 - **要将 LFS 系统实际用作桌面或服务器系统,那么即使在 LFS 系统构建完成后,也要继续关注安全公告并修复列出的所有安全缺陷** 准备宿主机 ============= 宿主机(也就是用来编译构建LFS的物理主机): - 建议至少4个CPU,内存8GB - `LFS 宿主系统需求 `_ 列出了基本软件包版本要求(大多数发行版都能满足),并且提供了一个检查脚本 .. literalinclude:: lfs_prepare/version-check.sh :caption: 执行检查主机环境 :language: bash - 如果和我一样使用 :ref:`lfs_vm` ,并且是 :ref:`fedora` ,可以先安装基本开发工具链: .. literalinclude:: lfs_prepare/dnf_install_env :caption: 在Fedora环境安装LFS编译环境 不过,这里还有一个报错:: ERROR: yacc is NOT Bison 参考 `How can i change yacc to bison (LFS) `_ 执行以下脚本命令: .. literalinclude:: lfs_prepare/yacc :caption: 设置yacc :language: bash 分阶段构建LFS ===================== LFS被设计成在一次会话中构建完成,也就是架设整个编译过程中,系统不会关闭或重启。不过,并非要求严格地一气呵成,需要注意如果重启后继续编译LFS,根据进度不同,可能需要再次进行某些操作。 .. _lfs_partitions: LFS分区 =========== LFS对分区没有硬性规定,但是有一些建议: - 最小的系统大约需要10G空间来存储源代码并编译所有软件包,不过作为日常Linux系统,建议使用30G空间以便后续添加功能 - 内存RAM需要8G以上,不建议使用SWAP(会影响性能)而是建议如果出现使用swap情况则扩容内存 - LFS分区建议使用成熟的文件系统,例如 :ref:`ext` 或 :ref:`xfs` ,对于后续存储数据可以使用更为高级的文件系统,如 :ref:`zfs` (这是我的建议) - 如果启动磁盘采用GUID分区表(GPT),则必须创建一个小的大约1MB的分区,这个分区不能格式化,但是必须被启动引导器GRUB发现,且这个分区在 ``fdisk`` 下显示为 ``BIOS Boot`` 分区,而使用 ``gdisk`` 命令则显示分区类型代号位 ``EF02`` 常用分区 ------------- 以下是建议使用的分区(作为参考): - ``/boot`` 分区,存储内核以及引导信息。为了减少大磁盘可能引起的问题,建议将 ``/boot`` 分区设置为第一块磁盘的第一个分区,建议分配 512MB 或 1GB (我的建议,因为需要存储不同内核进行测试;原文建议200MB,对于我的实践经验来看这样大小的分区可能不能存储2个或以上内核) - ``/boot/efi`` EFI系统分区,对于使用UEFI引导系统是必要的 - ``/home`` 分区,这个分区我准备后续用 :ref:`zfs` 来构建 - ``/usr`` 分区通常不用独立划分(可选,我没有使用独立分区) - ``/opt`` 分区(可选,我没有使用独立分区) - ``/tmp`` 分区,一般是配置瘦客户机时使用,如果系统有足够内存,可以在 ``/tmp`` 挂载一个 ``tmpfs`` 以加速访问临时文件 - ``/usr/src`` 用于存储BLFS源代码,并且可以在多个LFS系统之间共享;可以用来编译BLFS软件包,通常划分 30-50 GB LFS假设根文件系统 ``/`` 采用 ext4 文件系统 (考虑到简化内核且根分区并没有极端的性能要求,我目前按照官方文档采用默认的 ext4 文件系统) 我的分区 ---------------- - ``/dev/sda1`` vfat 格式, ``EFI System`` ,设置200M - ``/dev/sda2`` :ref:`ext` 4 文件系统,挂载为 ``/boot`` 分区,设置512M - ``/dev/sda3`` :ref:`ext` 4 文件系统,直接挂载 ``/`` 根分区 - 如果是物理服务器 :ref:`hpe_dl360_gen9` ,我会把大容量SSD磁盘再划分一个 ``/dev/sda4`` 作为 :ref:`zfs` 存储(虚拟机则单独配置一块虚拟磁盘来构建ZFS) 分区实践: .. literalinclude:: lfs_prepare/parted :caption: 对LFS分区 完成后执行 ``parted /dev/vdb print`` 输出信息类似如下: .. literalinclude:: lfs_prepare/parted_output :caption: 对LFS分区后分区信息 :emphasize-lines: 8-10 设置环境变量 ================= - 在 ``/etc/profile`` 中配置: .. literalinclude:: lfs_prepare/env :caption: ``/etc/profile`` 中添加LFS环境变量 挂载分区 ============ - 创建 ``/mnt/lfs`` 目录,并挂载分区 .. literalinclude:: lfs_prepare/mount :caption: 挂载分区 - 完成后使用 ``df -h`` 检查 .. literalinclude:: lfs_prepare/mount_output :caption: 挂载分区情况 准备工作已经完成,现在可以开始准备软件包了 软件包下载 ================ - 创建软件包和补丁的存放目录,按照文档,建议 ``$LFS/sources`` 目录: .. literalinclude:: lfs_prepare/sources :caption: 创建 ``$LFS/sources`` 目录用于存放源代码 - 官方 `wget-list-sysv `_ 作为 :ref:`wget` 命令的输入来下载所有软件包和补丁: .. literalinclude:: lfs_prepare/wget :caption: 下载所有 wget-list-sysv 列出的软件包和补丁 使用LFS提供的 `md5sums `_ 文件校验下载的软件包: .. literalinclude:: lfs_prepare/md5sum :caption: 使用LFS提供的 md5sums 文件校验下载的软件包 .. note:: 对于LFS稳定版,可以从 `LFS官方镜像网站直接下载打包好的软件包文件 `_ .. note:: 部分文件可能会因为上游下载源更改无法下载,需要手工处理 此外,还需要 `下载LFS必要的补丁 `_ (需要按照文档内容) 在LFS文件系统中创建有限目录布局 ================================== - 以root身份执行以下命令创建所需目录布局: .. literalinclude:: lfs_prepare/mkdir :caption: 创建目录布局 :language: bash .. literalinclude:: lfs_prepare/mkdir_output :caption: 创建目录布局的输出信息 - 此外为交叉编译器准备一个专用目录,使得其和其他程序分离: .. literalinclude:: lfs_prepare/tools :caption: 创建交叉编译器目录 :language: bash .. warning:: LFS不使用 ``/usr/lib64`` 目录,一定要确保该目录不存在,否则可能破坏系统。需要经常检查并确认该目录不存在 但是,我发现 :ref:`ubuntu_linux` 就具有 ``/usr/lib64`` ,而且这个目录里面只有一个软链接: .. literalinclude:: lfs_prepare/ubuntu_lib64 :caption: :ref:`ubuntu_linux` 使用了 ``/usr/lib64`` ,该目录下有一个非常关键的软链接 :emphasize-lines: 3 **但是 但是** 在 :ref:`ubuntu_linux` 这个 ``/usr/lib64`` 目录 ``千万不能移除`` ,不要看只有一个软链接,现在系统中有太多软件依赖这个遗留的软链接。我好死不活尝试移除这个目录: .. literalinclude:: lfs_prepare/ubuntu_mv_lib64 :caption: 尝试移除 ``/usr/lib64`` ,整个系统无法运行了 接下来发现,任何系统命令都无法运行,都显示文件不存在:: # groupadd -bash: /usr/sbin/groupadd: No such file or directory ``ssh`` 登陆也会提示bash不存在:: Last login: Tue Dec 10 10:59:43 2024 from 192.168.7.221 /bin/bash: No such file or directory Shared connection to 192.168.7.200 closed. 也就是说, ``bash`` 运行依赖这个库文件软链接,没有它系统无法工作 添加LFS用户 ============= - 创建 ``lfs`` 用户,避免微小错误损坏或摧毁系统: .. literalinclude:: lfs_prepare/lfs_user :caption: 创建lfs用户 :language: bash 如果是使用 ``root`` 用户身份切换到 ``lfs`` 用户,则不要求 ``lfs`` 用户帐号设置过密码;其他用户如果要切换到 ``lfs`` 用户,则需要为 ``lfs`` 用户设置密码( ``passwd lfs`` ) - 将 ``lfs`` 设置为 ``$LFS`` 中所有目录的所有者,这样 ``lfs`` 就对它们拥有 **完全访问权** : .. literalinclude:: lfs_prepare/chown_lfs :caption: 设置 ``$LFS`` 目录属主为 ``lfs`` 用户 :language: bash - 从 ``root`` 切换身份到 ``lfs`` ,后续操作以 ``lfs`` 用户身份来执行(避免出现误操作破坏系统):: su - lfs 配置环境 ============= 为了配置良好工作环境,需要为bash创建两个新的启动脚本,以下命令以 ``lfs`` 身份执行,创建一个新的 ``.bash_profile`` : .. literalinclude:: lfs_prepare/bash_profile :caption: 创建 ``lfs`` 用户的 ``.bash_profile`` :language: bash 上述 ``.bash_profile`` 中采用 ``exec env -i .../bin/bash`` 可以确保除了 ``HOME, TERM 以及 PS1`` 之外没有任何环境变量的 shell,防止宿主机环境中有不需要和有潜在风险的环境变量进入构建环境。 - 由于新的shell实例是 **非登录shell** ,所以它不会读取和执行 ``/etc/profile`` 或者 ``.bash_profile`` 中内容,而是读取并执行 ``.bashrc`` ,所以我们现在需要创建一个 ``.bashrc`` 文件: .. literalinclude:: lfs_prepare/lfs_bashrc :caption: 为 ``lfs`` 的非登录shell创建一个独立使用的 ``~/.bashrc`` :language: bash ``.bashrc`` 中设置含义(部分摘录参考): - ``set +h`` 关闭bash的散列功能。bash使用一个散列表维护各个可执行文件的完整路径,这样就不用每次都在 ``PATH`` 指定的目录中搜索可执行文件。这是一个非常有用的功能,但是在LFS构建中,我们希望总是使用最新安装的工具,所以关闭散列功能来强制shell在运行程序的时候总是搜索PATH - ``umask 022`` 将用户的文件创建掩码(umask)设置为 ``022`` ,确保只有文件的所有者可以写新创建的文件和目录,但是其他任何人都可以读取、执行它们 - ``LFS=/mnt/lfs`` LFS 环境变量必须被设定为之前选择的挂载点 - ``C_ALL=POSIX`` 将 LC_ALL 设置为 “POSIX” 或者 “C”(这两种设置是等价的) 可以保证在交叉编译环境中所有命令的行为完全符合预期,而与宿主的本地化设置无关 - ``LFS_TGT=$(uname -m)-lfs-linux-gnu`` LFS_TGT变量设定了一个非默认,但与宿主系统兼容的机器描述符。该描述符被用于构建交叉编译器和交叉编译临时工具链 - ``PATH=/usr/bin`` 许多现代 Linux 发行版合并了 /bin 和 /usr/bin。在这种情况下,标准 PATH 变量应该被设定为 /usr/bin - ``if [ ! -L /bin ]; then PATH=/bin:$PATH; fi`` 如果 /bin 不是符号链接,则它需要被添加到 PATH 变量中 - ``PATH=$LFS/tools/bin:$PATH`` 将 $LFS/tools/bin 附加在默认的 PATH 环境变量之前,一旦安装了新的程序,shell 就能立刻使用它们 - ``CONFIG_SITE=$LFS/usr/share/config.site`` 如果没有设定这个变量,configure 脚本可能会从宿主系统的 /usr/share/config.site 加载一些发行版特有的配置信息。覆盖这一默认路径,避免宿主系统可能造成的污染。 - ``export ...`` 设定了一些变量,为了让所有子 shell 都能使用这些变量 对于多CPU core的主机,可以并行执行make,所以在 ``.bashrc`` 添加以下配置(如果不希望所有cpu core被使用,则将 ``$(nproc)`` 替换成希望使用的cpu core数量: .. literalinclude:: lfs_prepare/makeflags :caption: 为make程序设置使用的cpu core数量 :language: bash .. note:: `LFS optimize.txt `_ 介绍了类似 :ref:`gentoo_linux` 配置 ``make.conf`` 的优化方法。也就是可以进一步配置GCC optimize级别以及生成针对CPU架构优化的执行程序。 所以,我参考 :ref:`install_gentoo_on_mbp` 的配置,修订了上述 make 的参数 `Is optimisation level -O3 dangerous in g++? `_ 讨论了O3级别优化,可以参考 `gentoo linux wiki: GCC optimization `_ 有详细的说明,建议参考 不过,我注意到实际运行编译参数是 ``-g -O2 -O3 -mach=native ...`` 那么究竟是 ``O3`` 还是 ``O2`` 优化呢? 参考 `GCC官方文档: Options That Control Optimization `_ : ``If you use multiple -O options, with or without level numbers, the last such option is the one that is effective.`` ,也就是说,后一个 ``-O`` 参数实际生效,也就是 ``-O3`` 最后确保构建临时工具所需环境就绪,强制bash shell读取刚才创建的配置文件: .. literalinclude:: lfs_prepare/source_profile :caption: 强制shell读取配置文件 :language: bash 参考 ====== - `Linux From Scratch 版本 12.2-中文翻译版 发布于 2024 年 9 月 1 日 `_