6.9. Glibc-2.29

Glibc 软件包包含了主要的 C 函数库。这个库提供了分配内存、搜索目录、打开关闭文件、读写文件、操作字符串、模式匹配、基础算法等基本程序。

大致构建用时: 22 SBU
所需磁盘空间: 3.2 GB

6.9.1. 安装 Glibc

[Note]

Note

Glibc 构建系统是独立的,并且会完美地安装,即使编译器指定的文件和链接器仍然指向 /tools。在 Glibc 安装之前,不能调整指定的文件和链接器,因为 Glibc 的 autoconf 测试会给出错误结果并阻碍目标实现干净的构建。

有些 Glibc 程序会用到和 FHS 不兼容的 /var/db 目录来存储它们的运行时数据。打上如下的补丁让这些程序在 FHS 兼容的位置存储它们的运行时数据。

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

首先创建一个兼容性符号链接,以避免在最终的 glibc 中存在 /tool 中的引用:

ln -sfv /tools/lib/gcc /usr/lib

决定 GCC 的 include 目录,并顺应 LSB 规范创建一个软链接。此外,x86_64 情况下,为了使动态加载器正确运作,再创建一个兼容性的软链接:

case $(uname -m) in
    i?86)    GCC_INCDIR=/usr/lib/gcc/$(uname -m)-pc-linux-gnu/8.2.0/include
            ln -sfv ld-linux.so.2 /lib/ld-lsb.so.3
    ;;
    x86_64) GCC_INCDIR=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include
            ln -sfv ../lib/ld-linux-x86-64.so.2 /lib64
            ln -sfv ../lib/ld-linux-x86-64.so.2 /lib64/ld-lsb-x86-64.so.3
    ;;
esac

删除一个以前的构建尝试可能遗留下来的文件:

rm -f /usr/include/limits.h

Glibc 文档里建议在 Glibc 特定编译目录下编译:

mkdir -v build
cd       build

配置 Glibc 准备编译:

CC="gcc -isystem $GCC_INCDIR -isystem /usr/include" \
../configure --prefix=/usr                          \
             --disable-werror                       \
             --enable-kernel=3.2                    \
             --enable-stack-protector=strong        \
             libc_cv_slibdir=/lib
unset GCC_INCDIR

选项和新参数的含义:

CC="gcc -isystem $GCC_INCDIR -isystem /usr/include"

设置 gcc 和系统的 include 目录以避免在调试符号中引入无效路径。

--disable-werror

选项像禁用了传递给 GCC 的 -Werror 选项。为了测试套件,此项必不可少。

--enable-stack-protector=strong

该选项通过添加额外代码检查缓冲区溢出(例如,堆栈粉碎攻击)来增强系统安全性。

libc_cv_slibdir=/lib

该变量为所有系统设置正确的库。我们不希望使用 lib64 。

编译软件包:

make
[Important]

Important

在本小节里,运行 Glibc 的测试套件是很关键的。在任何情况下都不要跳过这个测试。

通常会有一些测试不能通过。若是下面列出的这些失败,通常就可以安心的无视了。

case $(uname -m) in
  i?86)   ln -sfnv $PWD/elf/ld-linux.so.2        /lib ;;
  x86_64) ln -sfnv $PWD/elf/ld-linux-x86-64.so.2 /lib ;;
esac
[Note]

Note

在 chroot 环境的这个阶段需要上面的符号链接以运行测试。在接下来的安装中,这些链接将会被覆盖。

make check

你可能会看到一些失败的测试项。Glibc 的测试套件对宿主系统有一定的依赖。下面是一些 LFS 版本中最常见的问题:

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

  • inet/tst-idna_name_classify 已知会在 LFS 的 chroot 环境中失败。

  • posix/tst-getaddrinfo4posix/tst-getaddrinfo5 可能在某些架构上失败。

  • nss/tst-nss-files-hosts-multi 由于未知的原因,测试可能失败。

  • rt/tst-cputimer{1,2,3} 测试取决于宿主机的系统内核。众所周知,内核版本 4.14.91–4.14.96、4.19.13–4.19.18 和 4.20.0–4.20.5 是会导致这些测试失败的。

  • 如果你系统的 CPU 不是相对较新的 Intel 或 AMD 处理器,数学运算测试有时候会失败。

虽然这只是无关紧要的消息,在安装 Glibc 时会报告找不到 /etc/ld.so.conf 文件。下面的方式可以避免这个警告:

touch /etc/ld.so.conf

修复生成的 Makefile 以跳过一个没有必要的完整性检查,该检查在部分 LFS 环境中会失败:

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

安装软件包:

make install

nscd 安装配置文件并创建运行时目录:

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

nscd 安装系统支持文件:

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

接着,安装可以使系统响应不同语言的地域设置。没有一个地域是必需的,但是如果缺少了其中的某些,可能会导致在未来的软件包测试套件中,跳过了重要的测试项目。

单独的语言环境可以用 localedef 程序安装。例如,下面第一个 localedef 命令将 /usr/share/i18n/locales/cs_CZ 字符表定义组合在一起,并将结果附加到 /usr/share/i18n/charmaps/UTF-8.gz 文件末尾。下面的命令将安装能完美覆盖测试所需语言环境的最小集合:

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 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_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 it_IT -f ISO-8859-1 it_IT
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.SIJS 2> /dev/null || true
localedef -i ja_JP -f UTF-8 ja_JP.UTF-8
localedef -i ru_RU -f KOI8-R ru_RU.KOI8-R
localedef -i ru_RU -f UTF-8 ru_RU.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

另外,安装适合你自己国家/地区、语言和字符集的语言环境。

或者,也可以一次性安装在 glibc-2.29/localedata/SUPPORTED 文件里列出的所有语言环境(包括以上列出的所有语言环境以及其它更多),执行下面这个非常耗时的命令:

make localedata/install-locales

你需要的语言环境几乎不太可能没有列在 glibc-2.29/localedata/SUPPORTED 文件中,但如果真的没有可以使用 localedef 命令创建和安装。

[Note]

Note

当前,Glibc 在解决国际化域名时使用 libidn2。此为运行时依赖。如果需要此功能,可以参考 BLFS libidn2 页 相关的安装指令。

6.9.2. 配置 Glibc

6.9.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

6.9.2.2. 添加时区数据

通过以下命令安装并启动时区数据:

tar -xf ../../tzdata2018i.tar.gz

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

for tz in etcetera southamerica northamerica europe africa antarctica  \
          asia australasia backward pacificnew systemv; 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.9MB,但是一些应用程序或测试套件也许会出错。

zic -L leapseconds ...

这会创建包含时间补偿的 right 时区数据。在嵌入式平台,空间比较紧张而且你也不打算更新时区或者不需要准确时间,你可以忽略 right 目录从而节省 1.9MB。

zic ... -p ...

这会创建 posixrules 文件。我们使用纽约是因为 POSIX 要求夏令时规则与 US 标准一致。

一种确定本地时区的方式是运行下面的脚本:

tzselect

在询问了几个关于位置的问题后,脚本会输出所在时区的名字(比如 America/Edmonton))。在 /usr/share/zoneinfo 文件中也有其它一些可用时区,比如 Canada/EasternEST5EDT,这些时区并没有被脚本列出来但也是可以使用的。

然后运行下面的命令创建 /etc/localtime 文件:

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

将命令中的 <xxx> 替换成你所在实际时区的名字(比如 Canada/Eastern)。

6.9.2.3. 配置动态库加载器

默认情况下,动态库加载器(/lib/ld-linux.so.2)会搜索目录 /lib/usr/lib 查找程序运行时所需的动态库文件。如果库文件不在 /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

如果需要的话,动态库加载器也可以查找目录并包含里面配置文件的内容。通常在这个包含目录下的文件只有一行字指向库目录。运行下面的命令增加这个功能:

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

6.9.3. Glibc 软件包内容

安装的程序: catchsegv, gencat, getconf, getent, iconv, iconvconfig, ldconfig, ldd, lddlibc4, locale, localedef, makedb, mtrace, nscd, pldd, sln, sotruss, sprof, tzselect, xtrace, zdump, 和 zic
安装的库: ld-2.29.so, libBrokenLocale.{a,so}, libSegFault.so, libanl.{a,so}, libc.{a,so}, libc_nonshared.a, libcidn.so, libcrypt.{a,so}, libdl.{a,so}, libg.a, libieee.a, libm.{a,so}, libmcheck.a, libmemusage.so, libnsl.{a,so}, libnss_compat.so, libnss_dns.so, libnss_files.so, libnss_hesiod.so, libnss_nis.so, libnss_nisplus.so, libpthread.{a,so}, libpthread_nonshared.a, libresolv.{a,so}, librpcsvc.a, librt.{a,so}, libthread_db.so, 和 libutil.{a,so}
安装的库: /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/rpcsvc, /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

简要介绍

catchsegv

可以在程序因为段错误终止的时候创建栈调用历史

gencat

生成消息条目

getconf

显示文件系统相关的系统配置变量的值

getent

获取系统数据库的内容

iconv

字符集转换

iconvconfig

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

ldconfig

配置动态链接器的运行时环境

ldd

报告某个程序或动态库所依赖的动态库

lddlibc4

协助 ldd 处理某些目标文件

locale

输出当前语言环境的大量信息

localedef

编译语言环境规格

makedb

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

mtrace

读取并解析内存跟踪文件,然后用方便人阅读的格式显示一个摘要

nscd

一个后台服务程序,提供最常用名字服务请求的缓存

pldd

列出运行中进程正在使用的动态共享目标

sln

一个静态链接的 ln 程序

sotruss

跟踪指定命令里的动态库函数调用

sprof

读取并显示共享目标分析数据

tzselect

询问用户该系统的地理位置并给出相应的时区描述

xtrace

跟踪程序执行过程并打印当前执行的函数

zdump

时区数据输出工具

zic

时区数据编译工具

ld-2.29.so

用于动态库执行的辅助程序

libBrokenLocale

Glibc 内部的一个粗暴破解用来修复损坏程序(比如,一些 Motif 应用)。查看文件 glibc-2.29/locale/broken_cur_max.c 里的注释来了解更多信息

libSegFault

段错误信号处理函数,catchsegv 会用到

libanl

一个异步名字查找库

libc

主要的 C 库

libcidn

Glibc 内部用于在函数 getaddrinfo() 中处理国际化域名

libcrypt

密码学函数库

libdl

动态链接接口函数库

libg

不包含函数的一个空库。以前是 g++ 的运行时库

libieee

链接该模块会强制使用电气与电子工程师协会(IEEE) 定义的数学函数错误处理规则。默认的是 POSIX.1 错误处理

libm

数学运算函数库

libmcheck

链接这个库后会打开内存分配检查

libmemusage

Used by memusage 命令用它来协助收集应用程序里内存使用信息

libnsl

网络服务函数库

libnss

名称服务切换函数库,包含了解析主机名、用户名、组名、别称、服务、协议等等的函数

libpthread

POSIX 线程函数库

libresolv

包含了创建、发送和解析互联网域名服务器封包的函数

librpcsvc

包含了提供杂项 RPC 服务的函数

librt

包含了实现 POSIX.1b 实时扩展里规定的大部分接口的函数

libthread_db

包含了方便构建多线程程序调试工具的函数

libutil

包含各种 Unix 应用程序中用到的「标准」函数的代码