8.5. Glibc-2.37

Glibc 软件包包含主要的 C 语言库。它提供用于分配内存、检索目录、打开和关闭文件、读写文件、字符串处理、模式匹配、算术等用途的基本子程序。

估计构建时间: 11 SBU
需要硬盘空间: 2.9 GB

8.5.1. 安装 Glibc

一些 Glibc 程序使用与 FHS 不兼容的 /var/db 目录存放它们的运行时数据。应用一个补丁,使得这些程序在 FHS 兼容的位置存放运行时数据:

patch -Np1 -i ../glibc-2.37-fhs-1.patch

修复上游发现的安全问题:

sed '/width -=/s/workend - string/number_length/' \
    -i stdio-common/vfprintf-process-arg.c

Glibc 文档推荐在一个新建的目录中构建 Glibc:

mkdir -v build
cd       build

确保将 ldconfigsln 工具安装到 /usr/sbin 目录中:

echo "rootsbindir=/usr/sbin" > configparms

准备编译 Glibc:

../configure --prefix=/usr                            \
             --disable-werror                         \
             --enable-kernel=3.2                      \
             --enable-stack-protector=strong          \
             --with-headers=/usr/include              \
             libc_cv_slibdir=/usr/lib

配置选项的含义:

--disable-werror

该选项禁用 GCC 的 -Werror 选项。这对于运行测试套件来说是必须的。

--enable-kernel=3.2

该选项告诉构建系统 Glibc 可能被与 3.2 这样老版本的内核一起使用。这样,Glibc 会生成代码,在后续版本引入的系统调用不可用时绕过它们。

--enable-stack-protector=strong

该选项通过加入额外代码,对栈溢出攻击等导致的缓冲区溢出进行检查,以提高系统安全性。

--with-headers=/usr/include

该选项指定构建系统搜索内核 API 头文件的位置。

libc_cv_slibdir=/usr/lib

这个变量纠正库文件安装位置。我们不希望使用 lib64 目录。

编译该软件包:

make
[重要]

重要

我们认为,在本节中,Glibc 的测试套件十分关键。在任何情况下都不要跳过它。

通常来说,可能会有极少数测试不能通过,下面列出的失败结果一般可以安全地忽略。执行以下命令进行测试:

make check

您可能看到一些失败结果。Glibc 的测试套件和宿主系统之间有某种依赖关系。在 5000 多项测试中,如果只有几项测试失败,一般可以忽略它们。下面列出在一些版本的 LFS 上发现的,最常见的问题:

  • 已知 io/tst-lchmod 在 LFS chroot 环境中会失败。

  • 已知 misc/tst-ttyname 在 LFS chroot 环境中会失败。

  • 已知 stdlib/tst-arc4random-thread 在宿主内核版本较低时会失败。

  • 一些测试,例如 nss/tst-nss-file-hosts-multi,在较慢的系统运行时会由于其内部发生超时而失败。

在安装 Glibc 时,它会抱怨文件 /etc/ld.so.conf 不存在。尽管这是一条无害的消息,执行以下命令即可防止这个警告:

touch /etc/ld.so.conf

修改 Makefile,跳过一个在 LFS 的不完整环境中会失败的完整性检查:

sed '/test-installation/s@$(PERL)@echo not running@' -i ../Makefile

安装该软件包:

make install

改正 ldd 脚本中硬编码的可执行文件加载器路径:

sed '/RTLDLIST=/s@/usr@@g' -i /usr/bin/ldd

安装 nscd 的配置文件和运行时目录:

cp -v ../nscd/nscd.conf /etc/nscd.conf
mkdir -pv /var/cache/nscd

安装 nscd 的 systemd 支持文件:

install -v -Dm644 ../nscd/nscd.tmpfiles /usr/lib/tmpfiles.d/nscd.conf
install -v -Dm644 ../nscd/nscd.service /usr/lib/systemd/system/nscd.service

下面,安装一些 locale,它们可以使得系统用不同语言响应用户请求。这些 locale 都不是必须的,但是如果缺少了它们中的某些,在运行一些软件包的测试套件时,可能跳过重要的测试。

可以用 localedef 程序安装单独的 locale。例如,下面的第二个 localedef 命令将 /usr/share/i18n/locales/cs_CZ 中的字符集无关 locale 定义和 /usr/share/i18n/charmaps/UTF-8.gz 中的字符映射定义组合起来,并附加到 /usr/lib/locale/locale-archive 文件。以下命令将会安装能够覆盖测试所需的最小 locale 集合:

mkdir -pv /usr/lib/locale
localedef -i POSIX -f UTF-8 C.UTF-8 2> /dev/null || true
localedef -i cs_CZ -f UTF-8 cs_CZ.UTF-8
localedef -i de_DE -f ISO-8859-1 de_DE
localedef -i de_DE@euro -f ISO-8859-15 de_DE@euro
localedef -i de_DE -f UTF-8 de_DE.UTF-8
localedef -i el_GR -f ISO-8859-7 el_GR
localedef -i en_GB -f ISO-8859-1 en_GB
localedef -i en_GB -f UTF-8 en_GB.UTF-8
localedef -i en_HK -f ISO-8859-1 en_HK
localedef -i en_PH -f ISO-8859-1 en_PH
localedef -i en_US -f ISO-8859-1 en_US
localedef -i en_US -f UTF-8 en_US.UTF-8
localedef -i es_ES -f ISO-8859-15 es_ES@euro
localedef -i es_MX -f ISO-8859-1 es_MX
localedef -i fa_IR -f UTF-8 fa_IR
localedef -i fr_FR -f ISO-8859-1 fr_FR
localedef -i fr_FR@euro -f ISO-8859-15 fr_FR@euro
localedef -i fr_FR -f UTF-8 fr_FR.UTF-8
localedef -i is_IS -f ISO-8859-1 is_IS
localedef -i is_IS -f UTF-8 is_IS.UTF-8
localedef -i it_IT -f ISO-8859-1 it_IT
localedef -i it_IT -f ISO-8859-15 it_IT@euro
localedef -i it_IT -f UTF-8 it_IT.UTF-8
localedef -i ja_JP -f EUC-JP ja_JP
localedef -i ja_JP -f SHIFT_JIS ja_JP.SJIS 2> /dev/null || true
localedef -i ja_JP -f UTF-8 ja_JP.UTF-8
localedef -i nl_NL@euro -f ISO-8859-15 nl_NL@euro
localedef -i ru_RU -f KOI8-R ru_RU.KOI8-R
localedef -i ru_RU -f UTF-8 ru_RU.UTF-8
localedef -i se_NO -f UTF-8 se_NO.UTF-8
localedef -i ta_IN -f UTF-8 ta_IN.UTF-8
localedef -i tr_TR -f UTF-8 tr_TR.UTF-8
localedef -i zh_CN -f GB18030 zh_CN.GB18030
localedef -i zh_HK -f BIG5-HKSCS zh_HK.BIG5-HKSCS
localedef -i zh_TW -f UTF-8 zh_TW.UTF-8

另外,安装适合您自己国家、语言和字符集的 locale。

或者,也可以执行这个需要很长时间的命令,直接安装 glibc-2.37/localedata/SUPPORTED 中列出的所有 locale (包括上面列出的所有 locale,以及其他很多):

make localedata/install-locales

如果需要,再使用 localedef 命令创建和安装 glibc-2.37/localedata/SUPPORTED 中没有列出的 locale。例如,本章中后续的一些测试可能需要安装两个 locale:

localedef -i POSIX -f UTF-8 C.UTF-8 2> /dev/null || true
localedef -i ja_JP -f SHIFT_JIS ja_JP.SJIS 2> /dev/null || true
[注意]

注意

目前 glibc 在解析国际化域名时使用 libidn2。这形成了一个运行时依赖关系。如果需要使用解析国际化域名的功能,参阅 BLFS libidn2 页面安装 libidn2。

8.5.2. 配置 Glibc

8.5.2.1. 创建 nsswitch.conf

由于 Glibc 的默认值在网络环境下不能很好地工作,需要创建配置文件 /etc/nsswitch.conf

执行以下命令创建新的 /etc/nsswitch.conf

cat > /etc/nsswitch.conf << "EOF"
# Begin /etc/nsswitch.conf

passwd: files
group: files
shadow: files

hosts: files dns
networks: files

protocols: files
services: files
ethers: files
rpc: files

# End /etc/nsswitch.conf
EOF

8.5.2.2. 添加时区数据

输入以下命令,安装并设置时区数据:

tar -xf ../../tzdata2022g.tar.gz

ZONEINFO=/usr/share/zoneinfo
mkdir -pv $ZONEINFO/{posix,right}

for tz in etcetera southamerica northamerica europe africa antarctica  \
          asia australasia backward; do
    zic -L /dev/null   -d $ZONEINFO       ${tz}
    zic -L /dev/null   -d $ZONEINFO/posix ${tz}
    zic -L leapseconds -d $ZONEINFO/right ${tz}
done

cp -v zone.tab zone1970.tab iso3166.tab $ZONEINFO
zic -d $ZONEINFO -p America/New_York
unset ZONEINFO

zic 命令的含义:

zic -L /dev/null ...

该命令创建没有闰秒的 POSIX 时区。一般的惯例是将它们安装在 zoneinfozoneinfo/posix 两个目录中。必须将 POSIX 时区安装到 zoneinfo,否则若干测试套件会报告错误。在嵌入式系统上,如果存储空间十分紧张,而且您永远不会更新时区信息,您可以不使用 posix 目录,以节约 1.9 MB,但个别程序或测试套件可能会失败。

zic -L leapseconds ...

该命令创建正确的,包含闰秒的时区。在嵌入式系统上,如果存储空间十分紧张,而且您永远不会更新时区信息,也不关心系统时间是否正确,您可以跳过 right 目录,以节约 1.9 MB。

zic ... -p ...

该命令创建 posixrule 文件。我们使用纽约时区,因为 POSIX 要求与美国一致的夏令时规则。

一种确定本地时区的方法是运行脚本:

tzselect

在回答关于当前位置的若干问题后,脚本会输出对应时区的名字 (例如America/Edmonton)。在 /usr/share/zoneinfo 中还有一些该脚本不能识别,但可以使用的时区,如 Canada/Eastern 或者 EST5EDT

确定时区后,执行以下命令,创建 /etc/localtime

ln -sfv /usr/share/zoneinfo/<xxx> /etc/localtime

<xxx> 替换成选定时区的名称 (例如 Canada/Eastern)。

8.5.2.3. 配置动态加载器

默认情况下,动态加载器 (/lib/ld-linux.so.2) 在 /usr/lib 中搜索程序运行时需要的动态库。然而,如果在除了 /usr/lib 以外的其他目录中有动态库,为了使动态加载器能够找到它们,需要把这些目录添加到文件 /etc/ld.so.conf 中。有两个目录 /usr/local/lib/opt/lib 经常包含附加的共享库,所以现在将它们添加到动态加载器的搜索目录中。

运行以下命令,创建一个新的 /etc/ld.so.conf

cat > /etc/ld.so.conf << "EOF"
# Begin /etc/ld.so.conf
/usr/local/lib
/opt/lib

EOF

如果希望的话,动态加载器也可以搜索一个目录,并将其中的文件包含在 ld.so.conf 中。通常包含文件目录中的文件只有一行,指定一个期望的库文件目录。如果需要这项功能,执行以下命令:

cat >> /etc/ld.so.conf << "EOF"
# Add an include directory
include /etc/ld.so.conf.d/*.conf

EOF
mkdir -pv /etc/ld.so.conf.d

8.5.3. Glibc 的内容

安装的程序: gencat, getconf, getent, iconv, iconvconfig, ldconfig, ldd, lddlibc4, ld.so (到 ld-linux-x86-64.so.2 或 ld-linux.so.2 的符号链接), locale, localedef, makedb, mtrace, nscd, pcprofiledump, pldd, sln, sotruss, sprof, tzselect, xtrace, zdump, 以及 zic
安装的库: ld-linux-x86-64.so.2, ld-linux.so.2, libBrokenLocale.{a,so}, libanl.{a,so}, libc.{a,so}, libc_nonshared.a, libc_malloc_debug.so, libcrypt.{a,so}, libdl.{a,so.2}, libg.a, libm.{a,so}, libmcheck.a, libmemusage.so, libmvec.{a,so}, libnsl.so.1, libnss_compat.so, libnss_dns.so, libnss_files.so, libnss_hesiod.so, libpcprofile.so, libpthread.{a,so.0}, libresolv.{a,so}, librt.{a,so.1}, libthread_db.so, 以及 libutil.{a,so.1}
安装的目录: /usr/include/arpa, /usr/include/bits, /usr/include/gnu, /usr/include/net, /usr/include/netash, /usr/include/netatalk, /usr/include/netax25, /usr/include/neteconet, /usr/include/netinet, /usr/include/netipx, /usr/include/netiucv, /usr/include/netpacket, /usr/include/netrom, /usr/include/netrose, /usr/include/nfs, /usr/include/protocols, /usr/include/rpc, /usr/include/sys, /usr/lib/audit, /usr/lib/gconv, /usr/lib/locale, /usr/libexec/getconf, /usr/share/i18n, /usr/share/zoneinfo, /var/cache/nscd, 以及 /var/lib/nss_db

简要描述

gencat

生成消息目录

getconf

显示文件系统指定的系统配置变量值

getent

从管理数据库取得条目

iconv

转换给定文件的字符集

iconvconfig

创建可快速加载的 iconv 模块配置文件

ldconfig

配置动态链接器运行时绑定

ldd

报告给定程序或共享库依赖于哪些共享库

lddlibc4

辅助 ldd 处理目标文件。它在 x86_64 等较新的架构上不存在

locale

给出当前 locale 的一些信息

localedef

编译 locale 规范

makedb

从文本输入创建简单的数据库

mtrace

读取并解析内存跟踪文件,以人类可读的形式输出内存跟踪信息

nscd

一个缓存最常见命名服务请求的守护进程

pcprofiledump

显示基于程序计数器的性能剖析数据

pldd

列出正在运行的进程使用的共享库

sln

静态链接的 ln 程序

sotruss

跟踪特定命令对共享库中子程序的调用

sprof

读取并显示共享库性能剖析数据

tzselect

询问用户系统所在的位置并报告对应的时区

xtrace

显示正在执行的函数以跟踪程序执行

zdump

输出当前时间在多个时区中的表示

zic

时区编译器

ld-*.so

动态链接器/加载器

libBrokenLocale

被 Glibc 内部用作使某些不正确的程序 (例如某些 Motif 程序) 正常运行的粗糙手段,参阅 glibc-2.37/locale/broken_cur_max.c 中的注释了解更多信息

libanl

异步的命名查找库

libc

主要的 C 运行库

libc_malloc_debug

预加载该库时启用内存分配检查

libcrypt

密码学库

libdl

没有功能的空库。曾经是动态链接接口库,但其功能已经并入 libc

libg

没有功能的空库,曾经是 g++ 的运行库

libm

数学库

libmvec

向量数学库,在使用 libm 时自动按需链接。

libmcheck

链接到该库时启用内存分配检查

libmemusage

memusage 用于收集程序内存使用信息

libnsl

网络服务库,已经弃用

libnss_*

命名服务开关模块,包含用于解析域名、用户名、组名、代号、服务、协议等的函数。由 libc 根据 /etc/nsswitch.conf 的配置进行加载。

libpcprofile

可以预加载它,以对程序进行基于程序计数器的性能剖析

libpthread

没有功能的空库。曾经包含 POSIX.1b 实时扩展要求的多数接口函数,但这些函数现已并入 libc

libresolv

包含用于创建、发送和解析因特网域名服务数据包的函数

librt

包含 POSIX.1b 实时扩展要求的多数接口

libthread_db

包含用于构建多线程程序调试的函数器

libutil

没有功能的空库。曾经包含一些 Unix 工具使用的标准函数。这些函数已经并入 libc