0x00 起因
第一次接触 LFS 还是在两年前,我记得当时真的是 2 天 2 夜的时间醒了就继续,困了就躺了,直到现在那个感觉还牢牢的记载心里,然而很多事情不是你自己努努力就可以改变的,就比如那次,我失败了,失败的还算比较彻底,没能跑起来。现在看来那时候失败已经能够看的很清楚了,有几个点没注意到,一个是工具链编译的问题,还有就是 grub 的问题都导致了内核启动到一半不能继续报错。但是那时候我还觉得挺 happy 的,毕竟能够跑了。废话不说了,今天我来重跑一边最新的 LFS 吧过程记录一下,别再让其他人再踩坑了。这次我也要开一个新的系列叫做一站到底,意思是在一件事情上面死磕到底看一个就够了。但是吧,我发现这个名字别人用了,就改成一目了然了,力求追根溯源,尽量浅显简单把事情说明白。
0x01 准备工作
环境
centos7 mini 安装,装好了开发工具,如果你没装也没关系。下面检查软件版本时候我在解决其他问题的时候也会再要求装一遍。
我安装的时候使用的标准分区没有用lvm 而且空余了一个 20 G的空白硬盘没有做分区,下一讲会说到怎么做。
[root@localhost ~]# cat anaconda-ks.cfg
#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# Network information
network --bootproto=dhcp --device=enp2s0 --onboot=off --ipv6=auto --no-activate
network --bootproto=dhcp --device=enp3s0 --onboot=off --ipv6=auto
network --hostname=localhost.localdomain
# Root password
rootpw --iscrypted $6$T85Dms8ATqdAgIhW$x62d4TXvCQFrXqcruaAOFAUyoNNQofMOvzde.lhrvok/7bBLc9H3pB1rxKH3XmAtwT2zEN3Pu5TLNF/tBEEyJ.
# System services
services --enabled="chronyd"
# System timezone
timezone America/New_York --isUtc
user --name=hy --password=$6$FfAdt86GLEd5uobp$gj9hQlHKLtQzU6Uu7Zq6oPY4CFCi/AgF8JyOnTdbFdcBn68wIIxaYHWFMZpH7499ywibHh8H61gyO1SQOcnO01 --iscrypted --gecos="hy"
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --initlabel --list=sda1
# Disk partitioning information
part / --fstype="ext4" --ondisk=sda --size=51200
part swap --fstype="swap" --onpart=sda2
%packages
@^minimal
@core
@development
chrony
kexec-tools
%end
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
可以看出来 下面是已经安装的包 mini core 和 development
%packages
@^minimal
@core
@development
要做的准备工作其实挺多的,准备的越多后面越容易。这方面的投入是非常的值得的。结束以后我也会发一个长文的思维导图的总结。这里使用的书籍是中文版的由 linux中国翻译发布的 systemd 8.4 版本的 LFS 点击链接即可直达 https://lctt.github.io/LFS-BOOK/lfs-systemd/index.html
先准备几个常规的准备工作。
- 升级操作系统
yum update -y
- ssh 远程。这是为了操作另一台机器方便,如果你自己在本机上面做可以忽略
ssh-copy-id root@192.168.8.170
- screen. 配合 ssh 使用,可以有效的避免断线的问题
yum install screen -y # 使用的方法是这样的,首先 screen -S lfs 创建一个叫 lfs 的窗口。 # 断线了以后重新登录 ssh,然后使用screen -list 来看一下 lfs 这个窗口还有, # 然后就可以使用 screen -r lfs 来恢复以前的窗口。比如 编译了一半,他还在进行一点不影响
- vim 文本编辑器,你如果用 nano 就不用装了
yum install vim -y
- 自动补齐命令,我这种懒人还是要的,实际用处不大
yum install bash-completion -y
- 关闭 selinux 为避免它造成的一些不良影响还是先关了吧
SELinux setenforce 0 # 临时关闭 SELinux setenforce 1 # 临时打开 # 开机关闭SELinux 编辑/etc/selinux/config文件,将SELINUX的值设置为disabled # 查看SELinux状态 执行getenforce命令
-
frp 远程,大部分都不用做,除非你有像我一样的需求,机器不在我跟前,我还想这样做一样就要用到 frp 的远程,这块实际上也可以不用这么复杂 frp 提供了 systemd 的文件改改就好了
vim /etc/systemd/system/autoexec.service [Unit] Description=bash script run [Service] User=root ExecStart=/root/autostart.sh [Install] WantedBy=multi-user.target
vim /root/autostart.sh #!/bin/bash nohup /root/frp/frps -c /root/frp/frps.ini
0x02 检查软件版本
看书的第二章 这时候要检查主机操作系统是否能够满足 LFS 编译构建的最低需求。用下面的命令做成一个脚本,并执行一下。
最低版本的要求
Bash-3.2 (/bin/sh 应该是 bash 的符号链接或硬链接)
Binutils-2.25 (不建议使用 2.32 以后的版本,尚未经过测试)
Bison-2.7 (/usr/bin/yacc 应该是指向 bison 或执行 bison 的小型脚本的链接,这块需要在后面手动的更改一下,后面会说到)
Bzip2-1.0.4
Coreutils-6.9
Diffutils-2.8.1
Findutils-4.2.31
Gawk-4.0.1 (/usr/bin/awk 应该是 gawk 的链接)
GCC-5.2 包括 C++ 编译器,g++ (8.2.0 以后的版本不建议使用,尚未经过测试)
Glibc-2.11 (2.29 以后的版本不建议使用,尚未经过测试)
Grep-2.5.1a
Gzip-1.3.12
Linux Kernel-3.2
之所以指定使用这一版本的内核,是因为这是第 6 章构建 glibc 的需求,开发人员如是建议。udev 也有这个需求。
如果宿主机内核早于 3.2,则需使用更新版本的内核将其替换。有两种方法可以解决这个问题。首先,查看你的 Linux 供应商是否提供 3.2 或更高版本内核的软件包。如果提供的话,你便能如愿安装了。如果你的供应商不提供合适的内核(的软件包),或者是你不想直接安装,你也可以自己编译内核。编译内核和配置引导的说明(假设宿主机使用 GRUB)位于 第 8 章。
M4-1.4.10
Make-4.0
Patch-2.5.4
Perl-5.8.8
Python-3.4
Sed-4.1.5
Tar-1.22
Texinfo-4.7
Xz-5.0.0
检测脚本
cat > version-check.sh << "EOF"
#!/bin/bash
# Simple script to list version numbers of critical development tools
export LC_ALL=C
bash --version | head -n1 | cut -d" " -f2-4
MYSH=$(readlink -f /bin/sh)
echo "/bin/sh -> $MYSH"
echo $MYSH | grep -q bash || echo "ERROR: /bin/sh does not point to bash"
unset MYSH
echo -n "Binutils: "; ld --version | head -n1 | cut -d" " -f3-
bison --version | head -n1
if [ -h /usr/bin/yacc ]; then
echo "/usr/bin/yacc -> `readlink -f /usr/bin/yacc`";
elif [ -x /usr/bin/yacc ]; then
echo yacc is `/usr/bin/yacc --version | head -n1`
else
echo "yacc not found"
fi
bzip2 --version 2>&1 < /dev/null | head -n1 | cut -d" " -f1,6-
echo -n "Coreutils: "; chown --version | head -n1 | cut -d")" -f2
diff --version | head -n1
find --version | head -n1
gawk --version | head -n1
if [ -h /usr/bin/awk ]; then
echo "/usr/bin/awk -> `readlink -f /usr/bin/awk`";
elif [ -x /usr/bin/awk ]; then
echo awk is `/usr/bin/awk --version | head -n1`
else
echo "awk not found"
fi
gcc --version | head -n1
g++ --version | head -n1
ldd --version | head -n1 | cut -d" " -f2- # glibc version
grep --version | head -n1
gzip --version | head -n1
cat /proc/version
m4 --version | head -n1
make --version | head -n1
patch --version | head -n1
echo Perl `perl -V:version`
python3 --version
sed --version | head -n1
tar --version | head -n1
makeinfo --version | head -n1 # texinfo version
xz --version | head -n1
echo 'int main(){}' > dummy.c && g++ -o dummy dummy.c
if [ -x dummy ]
then echo "g++ compilation OK";
else echo "g++ compilation failed"; fi
rm -f dummy.c dummy
EOF
bash version-check.sh
来我们看一下结果,把结果里面不符的都得改好
[root@localhost ~]# bash version-check.sh
bash, version 4.2.46(2)-release
/bin/sh -> /usr/bin/bash
Binutils: version 2.27-34.base.el7
bison (GNU Bison) 3.0.4
Usage: /usr/bin/yacc [options] filename
Options:
-b file_prefix set filename prefix (default "y.")
-d write definitions (y.tab.h)
-i write interface (y.tab.i)
-g write a graphical description
-l suppress #line directives
-o output_file (default "y.tab.c")
-p symbol_prefix set symbol prefix (default "yy")
-P create a reentrant parser, e.g., "%pure-parser"
-r produce separate code and table files (y.code.c)
-s suppress #define's for quoted names in %token lines
-t add debugging support
-v write description (y.output)
-V show version information and exit
yacc is
bzip2, Version 1.0.6, 6-Sept-2010.
Coreutils: 8.22
diff (GNU diffutils) 3.3
find (GNU findutils) 4.5.11
GNU Awk 4.0.2
/usr/bin/awk -> /usr/bin/gawk
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
(GNU libc) 2.17
grep (GNU grep) 2.20
gzip 1.5
Linux version 3.10.0-957.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1 SMP Thu Nov 8 23:39:32 UTC 2018
m4 (GNU M4) 1.4.16
GNU Make 3.82
GNU patch 2.7.1
Perl version='5.16.3';
version-check.sh: line 45: python3: command not found
sed (GNU sed) 4.2.2
tar (GNU tar) 1.26
version-check.sh: line 48: makeinfo: command not found
xz (XZ Utils) 5.2.2
g++ compilation OK
为了照顾完全的 mini 安装 没有安装任何其他一点软件的朋友我下面修复的过程是基于 mini 安装什么也不装的情况修复,内容智慧更多不会少。
bison
yum -y install bison
ln -sv /usr/bin/bison /usr/bin/yacc
# 出现结果 ln: failed to create symbolic link ‘/usr/bin/yacc’: File exists
# 这时候要去手动把 /usr/bin/yacc 备份一下
mv /usr/bin/yacc /usr/bin/yacc.bak
# 再来一遍
ln -sv /usr/bin/bison /usr/bin/yacc
# 正常的回显为 ‘/usr/bin/yacc’ -> ‘/usr/bin/bison’
m4
yum install -y m4
makeinfo
yum install -y texinfo
patch
yum install -y patch
python3
装编译用的工具
sudo yum -y groupinstall "Development tools"
sudo yum -y install wget zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
下载源码包
wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
编译安装
tar -xf Python-3.7.3.tar.xz
cd Python-3.7.3/
./configure --prefix=/usr/local/python3
# --enable-optimizations 是一个调优的选项 这次不加
make -j4
# 多核心编译
make install
创建软连接
ln -sv /usr/local/python3/bin/python3 /usr/bin/python3
ln -sv /usr/local/python3/bin/pip3 /usr/bin/pip3
# 加v参数的好处是,弄完了看一下看看到底有没有问题,有没有弄错
make 4.0
这个是必须的,否则后面编译的时候就会报 make 的版本低,会出错
下载源码
wget http://mirrors.ustc.edu.cn/gnu/make/make-4.0.tar.gz
编译安装
./configure
make
make install
重建链接
make -v
# 此时的 make 还是3.82 与环境变量有关系
whereis make
# 找一下都有哪些 make
/usr/local/make/bin/make -v
# 这是我们刚安装的 make 它的版本是4.0
cd /usr/bin/
mv make make.bak
# 把默认的 make 改名
ln -s /usr/local/bin/make /usr/bin/make
# 建立一个软连接
make -v
# 查看一下大功告成
automake
这个是个隐形的条件,LFS book 里面没有提。是我自己发现的。
下载源码
wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
编译安装
tar xf automake-1.15.tar.gz
cd automake-1.15/
./configure --prefix=/usr/local/automake
make
make install
创建链接
cd /usr/bin/
mv automake automake.bak
mv automake-1.13 automake-1.13.bak
mv aclocal aclocal.bak
mv aclocal-1.13 aclocal-1.13.bak
ln -sv /usr/local/automake/bin/aclocal /usr/bin/aclocal
ln -sv /usr/local/automake/bin/aclocal-1.15 /usr/bin/aclocal-1.15
ln -sv /usr/local/automake/bin/automake /usr/bin/automake
ln -sv /usr/local/automake/bin/automake-1.15 /usr/bin/automake-1.15
gcc 5.3
虽然要求的最低是 5.2 保险点还是 5.3 合适
下载源码
wget http://ftp.gnu.org/gnu/gcc/gcc-5.3.0/gcc-5.3.0.tar.bz2
编译安装
tar -xf gcc-5.3.0.tar.bz2
cd gcc-5.3.0
./contrib/download_prerequisites
# 这步是下载依赖
./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
make
make install
最后再检查一遍
bash version-check.sh
得到的结果
bash, version 4.2.46(2)-release
/bin/sh -> /usr/bin/bash
Binutils: version 2.27-34.base.el7
bison (GNU Bison) 3.0.4
/usr/bin/yacc -> /usr/bin/bison
bzip2, Version 1.0.6, 6-Sept-2010.
Coreutils: 8.22
diff (GNU diffutils) 3.3
find (GNU findutils) 4.5.11
GNU Awk 4.0.2
/usr/bin/awk -> /usr/bin/gawk
gcc (GCC) 5.3.0
g++ (GCC) 5.3.0
(GNU libc) 2.17
grep (GNU grep) 2.20
gzip 1.5
Linux version 3.10.0-957.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1 SMP Thu Nov 8 23:39:32 UTC 2018
m4 (GNU M4) 1.4.16
GNU Make 4.0
GNU patch 2.7.1
Perl version='5.16.3';
Python 3.7.3
sed (GNU sed) 4.2.2
tar (GNU tar) 1.26
makeinfo (GNU texinfo) 5.1
xz (XZ Utils) 5.2.2
g++ compilation OK
与之前的 最低配置做一个对比 全部都符合。