LFS对初识Linux的人而言是一个非常不错的训练教材,流程虽说复杂,但也简单,只是单纯按照开发步骤执行即可。倘若能真正理解开发过程中的每一个步骤,那么Linux对你而言只不过是个“玩具”罢了,接下来是详细的开发步骤,每一步骤都有相应的代码以及必要的解释,有时会有截图加以辅助,适合初学者使用。
环境准备
首先是开发环境的准备,这里使用的是VMware 10.0.1有汉化版的,下载链接我就不提供了,网上一大堆,安装完后还需要序列号,这个网上也有,可以自行搜索。其实其他版本的VMware也是可以的,不过VMware10.0以上的版本才提供代码复制黏贴功能(该功能对往后的开发有极大的好处),若是VMware10.0以下的版本的话,其实也可以通过ssh链接来实现复制黏贴功能,不过有些复杂,具体实现可以看我的另一篇文章《LFS附加版——利用XShell和WinSCP辅助开发》;
对于LFS所选用的系统,这里选用的是lfslivecd-x86-6.3-r2145,下载链接如下:http://ftp.osuosl.org/pub/lfs-livecd/lfslivecd-x86-6.3-r2145.iso
首先了解一下VMWare其中一个使用技巧——快照:快照是一种可以很方便保存虚拟机当前工作状态的一种工具,其按钮位于工具栏里虚拟机按键的子按键里,点击即可为当前工作状态进行保存。在管理快照方面VMware也是尽可能更人性化,只要双击相应快照名称即可恢复到之前保存的工作状态。对于本次开发而言,快照能有效防止因中途出现某些错误而得重头做起的悲剧。不过,快照宜少不宜多,至于什么时候需要快照,凭感觉就行~
另外,虚拟机还有挂起功能,挂起的图标跟暂停一样,很容易辨识,有了挂起,在开发过程中可以随时暂停做其他事~
还有一点需要注意,虽然代码可以复制黏贴,但最好还是逐行复制黏贴,一来便于了解工作流程,二来出错时才知道哪里出错了。
新建虚拟机
点击创建新的虚拟机,选择自定义(高级)
保持默认,点击下一步
选择稍后安装操作系统,选择下一步
客户机操作系统选择Linux,版本选择其他 Linux2.6.x 内核,选择下一步
命名虚拟机,虚拟机名称自己定,位置的话最好放在一个至少有20G空间的磁盘下的一个新建文档里,文档名最好就是虚拟机的名称。比如我虚拟机名称为myLFS,文件位置就在F:\myLFS,然后下一步
接着处理器配置上,处理器的数量和每个处理器的核心数量自定,也不能说越多越好,但多点速度或许会快点,比如我就分配了一个处理器以及2个核心,当然一个处理器一个核心也是够用的,然后下一步
接着是内存的大小,一般默认推荐内存即可,不过如果想速度更快点的话可以选择最大推荐内存,不过前提是电脑的内存得够用以及后面的相关操作的数值得记得做出相应修改,我保持了默认大小,然后下一步
网络连接选择使用网络地址转换(NAT),然后下一步
SCSI控制器选择默认的LSI Logic即可,然后下一步
虚拟磁盘类型选用IDE,然后下一步
接着选择创建新虚拟磁盘,然后下一步
最大磁盘大小默认8G即可,然后选择将虚拟磁盘存储为单个文件,然后下一步
保持默认,直接下一步
选择完成
接着就可以看见myLFS的主界面了,然后选择编辑虚拟机设置
在CD/DVD(IDE)的位置那,选择使用ISO映像文件,点击浏览,把lfslivecd-x86-6.3-r2145.iso的位置添加进去,然后确定退出后,点击开启此虚拟机即可
系统初始化
把鼠标移到窗口里并点击一下使焦点位于虚拟机中,按下回车即可
接下来选择系统时间,一般选择Asia/Shanghai
然后选择Localtime
接下来语言设置,推荐使用English,USA(UTF-8),接着都按回车即可
磁盘分区
输入代码(这时就可以使用复制黏贴功能了,主要利用“Ctrl+C”和“Ctrl+V”,在文章中将代码“Ctrl+C”复制,然后选中虚拟机(记得不要把鼠标点进LFS系统里面),然后“Ctrl+V”即可实现把代码黏贴进去)
cfdisk /dev/hda
正常情况:
出错情况:
遇到这种情况有两种解决方法,第一种解决方法是输入如下代码:
cd /dev
ls | grep hd
这样可以查找到可以用的磁盘名称,这是由于系统分配磁盘时不一定用hda作为名称,有可能是hdd或其他名称的,只要把名称找到并修改成相应的代码即可进入下一步,不过这样做的话后面的全部hda都得记住改成相应的hdX,否则会出错;
第二种解决方法是直接把myLFS删掉重头开始重新建立,我更倾向于这种因为后面不一定会记得当初所分配的磁盘名叫什么了,也有碍于代码的复制黏贴
然后通过上下左右键回车选中New –> Primary –> size填512 –> Beginning 获得如下hda1,即为交换分区
然后向下选中第二行,执行 New –> Primary –> size默认回车即可 –> Beginning获得如下hda2,即为根分区
然后选择Write –> Quit 退出即可
然后进行磁盘分区格式化
mkswap /dev/hda1
mkfs.xfs /dev/hda2
开始制作LFS
创建LFS的“创作基地”
export LFS=/mnt/lfs
mkdir -pv $LFS
相关知识点
export LFS=/mnt/lfs这条命令的作用是为了后面引用“创作基地”的绝对路径方便而设置LFS这样的环境变量。
加载/dev/hda2到“创作基地”
mount /dev/hda2 $LFS
创建必要的目录并设置属性
创建源代码编译用目录
mkdir -v $LFS/sources
chmod -v a+wt $LFS/sources
相关知识点
chmod a+wt是将目录或文件的属性设置为1777,这样任何人都可以对其进行读写。
创建工具链目录
mkdir -v $LFS/tools
ln -sv $LFS/tools /
注意
ln -sv $LFS/tools执行后应该会输出
‘/tools’ -> ‘/mnt/lfs/tools’
表示正确。
相关知识点
上面这两句就建立了神奇的工具链目录(是工具链目录不是工具链),这样的创建方式是为了在创建工具链和使用工具链创建目标系统的时候对于工具链的位置都是/tools,这样可保证工具链的正常使用
创建lfs用户
groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
设置lfs密码,设置为空就行了,也就是输入密码的时候直接回车就成
passwd lfs
将tools和sources目录的用户改为lfs,以便后面使用lfs来操作这两个目录
chown -v lfs $LFS/tools
chown -v lfs $LFS/sources
登陆到lfs用户
su - lfs
注意
这时候你会发现命令行提示符已经由#改为了$
相关知识点
其实如果不使用lfs用root也是能完成工具链的,不过需要对root的环境变量进行修改,还要防止因为输入错误而导致覆盖主系统下的文件,所以LFS手册中制作工具链部分就是为了解决这种意外的发生而用lfs用户来建立工具链
建立lfs用户的环境
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF
cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
PATH=/tools/bin:/bin:/usr/bin
export LFS LC_ALL PATH
EOF
source ~/.bash_profile
相关知识点
这里利用了bash的环境变量的设置文件将lfs的环境设置为符合编译工具链要求的最少的环境参数
这里面最重要的就是PATH这个参数,目的是为了能够利用工具链里面的工具制作工具链:首先查找/tools/bin下是否有需要的命令,如果没有再到/bin和/usr/bin下找,然后用/bin或/usr/bin下面的命令来帮助生成需要的命令并放在/tools/bin下,这样此消彼涨,最终可完成一个自给自足的工具链。
进入LFS包编译目录
cd $LFS/sources
Binutils-2.17 - Pass 1
tar xvf /lfs-sources/binutils-2.17.tar.bz2
cd binutils-2.17
相关知识点
大家可以注意到后面所有的解包命令均使用tar xvf来完成,而不管文件的压缩方式是bz2还是gz,这是因为较新的tar程序都具有自动识别后缀名并自动调用相应的解压缩工具的能力,所以可以不需要指定压缩方式,但对于早期的tar命令则可能不具备这个功能因此需要你根据包的压缩方式来指定,如bz2使用j,gz使用z,对应上面的binutils则是tar xvjf /lfs-sources/binutils-2.17.tar.bz2
因LFS的LiveCD中提供的tar版本比较新,后面制作的tar版本也比较新,因此支持自动识别的能力,同时为了使文章的解压命令看起来比较统一方便维护(同样对于想制作成脚本的朋友也会比较方便)因此后面统一使用tar xvf来解压
接着我们需要建立一个目录,因为binutils建议使用一个空目录来编译,所以
mkdir -v ../binutils-build
cd ../binutils-build
CC="gcc -B/usr/bin/" ../binutils-2.17/configure --prefix=/tools --disable-nls --disable-werror
make
make install
make -C ld clean
make -C ld LIB_PATH=/tools/lib
cp -v ld/ld-new /tools/bin
cd ..
rm -rf binutils-build
rm -rf binutils-2.17
GCC-4.1.2 - Pass 1
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2
mkdir -v gcc-build
cd gcc-build
CC="gcc -B/usr/bin/" ../gcc-4.1.2/configure --prefix=/tools --with-local-prefix=/tools --disable-nls --enable-shared --enable-languages=c
make bootstrap
make install
ln -vs gcc /tools/bin/cc
cd ..
rm -rf gcc-build
rm -rf gcc-4.1.2
注意
CC=”gcc -B/usr/bin/” ../gcc-4.1.2/configure –prefix=/tools –with-local-prefix=/tools –disable-nls –enable-shared –enable-languages=c
这是完整的一行代码,不可分成两行输入
Linux-2.6.22.5 API Headers
tar xvf /lfs-sources/linux-2.6.22.5.tar.bz2
cd linux-2.6.22.5
make mrproper
make headers_check
make INSTALL_HDR_PATH=dest headers_install
cp -rv dest/include/* /tools/include
cd ..
rm -rf linux-2.6.22.5
Glibc-2.5.1
tar xvf /lfs-sources/glibc-2.5.1.tar.bz2
cd glibc-2.5.1
mkdir -v ../glibc-build
cd ../glibc-build
../glibc-2.5.1/configure --prefix=/tools \
--disable-profile --enable-add-ons \
--enable-kernel=2.6.0 --with-binutils=/tools/bin \
--without-gd --with-headers=/tools/include \
--without-selinux
make
mkdir -v /tools/etc
touch /tools/etc/ld.so.conf
make install
cd ..
rm -rf glibc-build
rm -rf glibc-2.5.1
相关知识点
这里的参数–enable-kernel=2.6.0,只是为了说明kernel的大版本,所以不需要根据实际的kernel版本来改,即使是用linux-2.6.15也一样只写2.6.0就可以了
调整工具链
mv -v /tools/bin/{ld,ld-old}
mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old}
mv -v /tools/bin/{ld-new,ld}
ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld
gcc -dumpspecs | sed 's@^/lib/ld-linux.so.2@/tools&@g' > `dirname $(gcc -print-libgcc-file-name)`/specs
GCC_INCLUDEDIR=`dirname $(gcc -print-libgcc-file-name)`/include
find ${GCC_INCLUDEDIR}/* -maxdepth 0 -xtype d -exec rm -rvf '{}' \;
rm -vf `grep -l "DO NOT EDIT THIS FILE" ${GCC_INCLUDEDIR}/*`
unset GCC_INCLUDEDIR
相关知识点
工具链的调整方法有好几种,而且不同版本GCC的specs可能会有不同,但实际上都是把specs文件中的/lib/ld-linux.so.2替换成了/tools/lib/ld-linux.so.2,所以即使有些文章在调整工具链上的命令和LFS手册上的不一样也不用太奇怪,当然也可以直接用gcc-dumpspecs导出后手工直接编辑specs文件
测试工具链的调整
echo 'main(){}' > dummy.c
cc dummy.c
readelf -l a.out | grep 'tools'
注意
如果输出大致如下 [Requesting program interpreter: /tools/lib/ld-linux.so.2]
则表示调整成功,因为所有的库已经连接到了/tools/lib下。
删除测试
rm -rf a.out dummy.c
测试工具安装(Tcl-8.4.15,Expect-5.43.0,DejaGNU-1.4.4)
tar xvf /lfs-sources/tcl8.4.15-src.tar.gz
cd tcl8.4.15/unix
./configure --prefix=/tools
make
make install
make install-private-headers
ln -sv tclsh8.4 /tools/bin/tclsh
cd $LFS/sources
tar xvf /lfs-sources/expect-5.43.0.tar.gz
cd expect-5.43
patch -Np1 -i /lfs-sources/expect-5.43.0-spawn-1.patch
cp configure{,.bak}
sed 's:/usr/local/bin:/bin:' configure.bak > configure
./configure --prefix=/tools --with-tcl=/tools/lib --with-tclinclude=/tools/include --with-x=no
make
make SCRIPTS="" install
cd $LFS/sources
tar xvf /lfs-sources/dejagnu-1.4.4.tar.gz
cd dejagnu-1.4.4
./configure --prefix=/tools
make install
cd ..
rm -rf tcl8.4.15
rm -rf expect-5.43
rm -rf dejagnu-1.4.4
GCC-4.1.2 - Pass 2
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2
cd gcc-4.1.2
cp -v gcc/Makefile.in{,.orig}
sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig > gcc/Makefile.in
cp -v gcc/Makefile.in{,.tmp}
sed 's/^XCFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in.tmp > gcc/Makefile.in
patch -Np1 -i /lfs-sources/gcc-4.1.2-specs-1.patch
mkdir -v ../gcc-build
cd ../gcc-build
../gcc-4.1.2/configure --prefix=/tools \
--with-local-prefix=/tools \
--enable-clocale=gnu --enable-shared \
--enable-threads=posix --enable-__cxa_atexit \
--enable-languages=c,c++ --disable-libstdcxx-pch
make
make install
cd ..
rm -rf gcc-build
rm -rf gcc-4.1.2
再次测试工具链的调整
echo 'main(){}' > dummy.c
cc dummy.c
readelf -l a.out | grep 'tools'
注意
如果输出大致如下 [Requesting program interpreter: /tools/lib/ld-linux.so.2]
则表示调整成功,因为所有的库已经连接到了/tools/lib下。
删除测试
rm -rf a.out dummy.c
Binutils-2.17 - Pass 2
tar xvf /lfs-sources/binutils-2.17.tar.bz2
mkdir -v binutils-build
cd binutils-build
../binutils-2.17/configure --prefix=/tools --disable-nls --with-lib-path=/tools/lib
make
make install
make -C ld clean
make -C ld LIB_PATH=/usr/lib:/lib
cp -v ld/ld-new /tools/bin
cd ..
rm -rf binutils-build
rm -rf binutils-2.17
Ncurses-5.6
tar xvf /lfs-sources/ncurses-5.6.tar.gz
cd ncurses-5.6
./configure --prefix=/tools --with-shared --without-debug --without-ada --enable-overwrite
make
make install
cd ..
rm -rf ncurses-5.6
Bash-3.2
tar xvf /lfs-sources/bash-3.2.tar.gz
cd bash-3.2
patch -Np1 -i /lfs-sources/bash-3.2-fixes-5.patch
./configure --prefix=/tools --without-bash-malloc
make
make install
ln -vs bash /tools/bin/sh
cd ..
rm -rf bash-3.2
Bzip2-1.0.4
tar xvf /lfs-sources/bzip2-1.0.4.tar.gz
cd bzip2-1.0.4
make
make PREFIX=/tools install
cd ..
rm -rf bzip2-1.0.4
Coreutils-6.9
tar xvf /lfs-sources/coreutils-6.9.tar.bz2
cd coreutils-6.9
./configure --prefix