在一个系统中安装运行多个版本的Glibc-实战篇

上回说到发现了一个神奇的项目LFS,从官网上可以看到,这个项目是教你怎么完全用源码编译一个自已定制化的Linux系统.这跟我们之前说的安装运行多个Glibc有什么联系呢?

来来来,前情提要,上篇 讲到在程序运行的时候会依赖很多动态库,其中Glibc就是一个非常重要的库,程序通过加载ld-linux.so库对这些依赖库的路径进行查找.而ld-linux.so的路径是写死在编译器gcc中的,换一句话说,就是在一个程序在编译的时候,默认情况下它需要加载的ld-linux.so路径已经写死了(这里编译Glibc的时候会生成对应版本的ld-linux.so文件的,所以不同版本的Glibc会生成版本的ld-linux.so哦).

所以需要运行多个版本的Glibc,有两个方法,一个是在编译新的程序时通过-Wl,–dynamic-linker= 参数指定ld-linux.so路径指向其它版本 ,第二是修改gcc源码中ld-linux.so的路径,再用修改过的gcc编译新的程序,这样编译出来的所有程序ld-linux.so的路径都会指向其它版本生成的了.很容易看出来,第一种方法每编译一个程序需要修改程序源码文件,还有可能遇到很多兼容性问题,所以第二种方法可以说是最合适的.

LFS就是教我们怎么用第二种方法编译定制化Linux系统的.

这里我还是要忍不住说一下,学习LFS是很需要毅力的活,不一定一次就能编译成功,很花费时间和精力,我自己重新编译了不下20次….由于对其中的原理不了解必然会踩很多的坑,然后各种查可能也找不出答案(最后还可能发现,我靠这个居然是一个bug..),所以没有深厚兴趣的同学还是慎重考虑一下,我有过好几次,花了两三天都没有成功,然后就放弃了,过一段时间再想着再试试,然后还是不行..如此反复..我这个人还是比较喜欢折腾,最后还是被我试出来了.

回到正题,以我的血泪史来告诉大家一些踩过的坑,先说几问题,也是我刚刚开始学习的时候会想问的

1.我没有root权限,可以安装运行多个Glibc吗?

对于LFS的这个学习流程来说,恐怕是必须要root权限,因为需要一些chroot之类的操作,但是只对于安装运行多个Glibc来说,它只是LFS其中的一部分,不需要替换kernel和chroot这些操作,理论上是不需要root权限,只需要把原来安装运行的路径换成自己用户的HOME目录中就可以 ,但是有root权限会比较方便哈~~

2.需要编译整个Linux系统?时间会不会需要太久呀?

是需要比较长时间的,根据机器的配置不同可能不一样,我原来用一个双核的CPU(忘记是哪个型号了),8G的内存,一切顺利的话一个下午的时间是可以搞定的,建议尽量用多核的CPU,在环境变量中加上多线程编译参数

export MAKEFLAGS="-j $(grep -c ^processor /proc/cpuinfo)"

3.看到LFS中需要安装很多软件,我需要这样每一个都自己去它们的官网下载吗?

当然是需要每一个都下载的,但是你不需要每个都去它们的官网下载,LFS提供了这些软件的集合源码包,在这里的镜像网站 有所有版本的LFS软件包,比如我用是7.9 systemd版本的,直接下载lfs-packages-7.9-systemd.tar,然后解压就可以了.由于国内没有镜像网站,下载速度可能会比较慢,可以先用迅雷之类的下载工具下载 到本地,再用rz命令拉到Linux host上.这里特别需要注意的是,一定要严格使用LFS文档中指定软件版本进行编译,不然会报一些神奇的错误,根本找不到是什么原因(这个也不要问我为什么….)

可以通过阅读LFS的online book 来一步一步学习

我用是7.9-systemd版,各个版本都大同小异,这里我是在自己的机器上进行编译的,所以是有root权限的

准备工作

我们并不需要新建一个分区,只需要新建一个目录/opt/lfs,在lfs中新建两个目录tools存放我们即将需要编译的工具和sources存放刚刚下载解压出来的软件包,然后ln -s /opt/lfs/tools / 建立一个/tools的软链

添加一个lfs用户和lfs用户组,设置用户密码,并把lfs用户配置为tools和sources目录的owner,然后切换到lfs用户su – lfs.之后所有操作都在lfs用户下进行,这样做的好处是,如果在之后的操作出错,导致动态库引用错误,在当前用户环境下执行任何命令都会coredump,可以重新用其它用户登录,修改这个用户的环境变量来恢复

配置lfs用户的环境变量

~/.bash_profile

exec env -i HOME=$HOME TERM=$TERM PS1=”[\[\033[1;36m\]\u\[\033[1;31m\]@\[\033[1;34m\]\A\[\033[1;31m\]@\[\033[1;32m\]\h:\[\033[1;35m\]\w]\[\033[1;31m\]$\[\033[0m\] ” /bin/bash

~/.bashrc

set +h
umask 022
LFS=/opt/lfs #lfs path
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/tools/bin:/bin:/usr/bin:/usr/sbin
export LFS LC_ALL LFS_TGT PATH
alias l=”ls -alh”
export MAKEFLAGS=”-j $(grep -c ^processor /proc/cpuinfo)”

然后source ~/.bash_profile加载配置

开始编译

这里就到了文档5.4节,开始编译各种工具,细节就不表了,按照文档上的来就可以,重点说一些需要注意的流程(最近在某宝上买了一台DIY PC台式机来安装Linux作日常开发用,CPU是e5-2650,8核16线程,加上SSD,编译起来快的飞起呀,而且并不贵,不需要显卡,比一台普通PC台式机便宜多了,投资自己的好方式~~)

为了跨平台,binutils和gcc是需要编译两次的,可以想一想为什么需要这样做呢?答案在下一篇番外篇给出^_^

在5.7节编译完Glibc后,一定要记得按文档中说的对刚刚编译好的gcc进行一下测试

echo ‘int main(){}’ > dummy.c
$LFS_TGT-gcc dummy.c
readelf -l a.out | grep ‘: /tools’

如果[Requesting program interpreter: /tools/lib64/ld-linux-x86-64.so.2]字样,恭喜你,现在用编译好的gcc编译程序时,加载ld-linux.so的路径已经修改到新版本了(这里看不懂的同学请认真读上篇博文和本文开头几段)

到5.9节,开始第二次编译binutils,这里注意看看执行configure之前还指定了用5.5节编译过的gcc对它进行编译的

5.10节进行第二次编译gcc,注意哦,这里也是用之前5.5节编译过的gcc作为编译器来进行第二次gcc的编译,想想为什么呢?

ln -sv gcc /tools/bin/cc后,再对这次编译好的gcc进行测试

echo ‘int main(){}’ > dummy.c
cc dummy.c
readelf -l a.out | grep ‘: /tools’

同样出现[Requesting program interpreter: /tools/lib/ld-linux.so.2],说明跨平台gcc编译成功了.用ldd查看a.out动态库依赖,可以看到,编译生成的文件依赖指向/tools/lib下了

接下来就按第5章里剩下的章节把必要的工具安装完成

在第5章的所有工具安装完成之后,还有一步我们需要安装字符集和时区否则会出现奇怪的bug…想要知道情况请看这里…..

转到6.9章,6.9.1和6.9.2.2有介绍如果安装字符集和时区的,这里就不多说了,安装完之后把系统字符集修改为utf8,把原来~/.bachrc里的LC_ALL=POSIX修改为LC_ALL=en_US.UTF-8,如果提示zic not found试试把/usr/sbin加入$PATH看看

到这里,lfs已经切换到新版本Glibc上了,我们下载编译Python来试试看效果,注意编译时加上–prefix=/tools.安装完成后用ldd查看,所有依赖都指向了/tools目录下

来看看依赖的Glibc库/tools/lib/libc.so.6的版本

已经是新安装的2.23了.大功告成鸟~~

细心的同学会这样安装运行多个Glibc的版本,其实是通过切换$PATH环境变量来实现的,只要在用户的$PATH的最前面加上/tools/bin,执行生效后,当前环境所用的就是我们刚刚编译的Glibc环境中了.

还有就是我们刚才编译的这套软件,类似于跨平台的概念了,不依赖是这套软件包以外的其它库,只依赖于内核的接口,所以只要把/tools下的所有文件打包到其它linux发行版中的/tools目录下,只要kernel的版本在2.6.23以上,把$PATH修改后是可以正常运行的.有兴趣的同学可以 试试~~

嗯..居然还有番外篇…什么鬼..

参考:

Linux From Scratch Version 7.9-systemd

Leave a Reply

Your email address will not be published. Required fields are marked *