lfs 6.3實驗筆記

hejinjing_tom_com發表於2018-04-26
在經歷了百般磨難之後,終於厚積薄發,用極短的時間,編譯完成了lfs, 有些內容還需要進一步理解,採用環境是emacs ansi-term做遠端登陸客戶端, 如下作為學習筆記
************************************************************
lfs 有一個livecd, cd 盤裡有了必要的素材。
參考文件:
1. 官網,http://www.linuxfromscratch.org/lfs/
2. 手冊:/usr/share/LFS-BOOK-6.3-HTML/index.html
3. 手把手教你如何建立自己的Linux系統 第二版
本帖目的,兼顧完整性,進一步突出重點。
編後感想:
最詳細的還是參考手冊(可以從cd中取),其次參考手把手文件,本貼僅就幾個關鍵問題進行了描述.
可做大綱參考.
************************************************************
工作概覽:
下載啟動盤livecd,  這裡使用了 lfslivecd-x86-6.3-r2145.iso
建立虛擬機器,建立硬碟來保留編譯結果,
建立新使用者(lfs), 以普通使用者身份編譯臨時工作環境,儲存到硬碟/tools目錄下)
用root使用者,用chroot方式編譯正式工作環境
設定從硬碟啟動
############################################################
1.1. 建立一個虛擬機器
比準備一個裸機可是方便多了
############################################################
要安裝一個全新的linux 系統,首先要有一塊硬碟。在虛擬機器上操作,你不用花錢就建立了一塊硬碟。
建立一個虛擬機器,配置為:
一個ide 硬碟, 8G 大小,這樣顯示為/dev/hda,  目標是在其上安裝定製的linux 作業系統
我用的是vmware11.0, 系統預設採用scsi, 建立完成後,可以新加一個ide硬碟, 刪除scsi 硬碟, 這樣可保證和教材相一致,省去修改的麻煩.

記憶體: 256M
一個網路卡: 採用NAT 方式,
虛擬機器使用主機中的虛擬網路卡vmnet8作為閘道器,可以實現主機和虛擬機器通訊,虛擬機器也能夠訪問網際網路,但是網際網路不能訪問虛擬機器。
vmnet8 還具有dhcp server 功能,為網路分配ip地址, 虛擬機器設定為dhcp 模式,即可自動獲取到ip地址。
使用NAT方式:確保Eidt-Virtual Network Editor中的啟動了DHCP 服務
有了網路,可以啟動secureCRT 登陸。解決控制檯的問題。也可以啟動tftp服務或nfs服務為虛擬機器出借資源。

一個軟盤可以與主機交換資訊,(使用軟盤映像)
一個cdrom 裝載livecd: lfslivecd-x86-6.3-r2145.iso

設定虛擬機器從光碟啟動
虛擬機器啟動太快,根本看不清進入bios 的提示,
修改虛擬機器配置檔案(.vmx):
例如: Other Linux 2.6.x kernel.vmx (每個虛擬機器都有對應的配置檔案)
在最後新增:
bios.bootDelay = "3000"
啟動時延時3秒, 這次啟動看清了,然後從容按"F2"進入了bios 設定。

1.2. 將硬碟分割槽和格式化。(fdisk 和 mkswap, mkfs)
光碟啟動後,這個硬碟是/dev/hda,
lfs 推薦將/dev/hda 劃分為2個分割槽,
第一個分割槽,512M,
第二個分割槽,剩餘,
操作: fdisk /dev/hda
n(new) -> p(primary)....  建立兩個原始分割槽(p,1... p,2... w)
分割槽後,多了兩個塊裝置/dev/hda1, /dev/hda2

然後格式化兩個分割槽,一個為swap, 一個為ext2
swap, (mkswap /dev/hda1),
ext2, (mkfs -t ext2 /dev/hda2)


############################################################
2. 光碟啟動以後,我們幹什麼?
首先啟動sshd 服務,然後我們登陸,方便我們操作.
然後把硬碟掛載到系統上。
建立一個新使用者,這是本節的關鍵.
############################################################
光碟啟動後,我們看到一個原始的linux系統,常用的工具及程式碼都在裡面.
在root根目錄下,有2個txt檔案可以瀏覽一下, 對光碟工具有個瞭解。
也可以等啟動sshd後遠端登陸再瀏覽,會有一個更好的瀏覽控制檯.
----------------------------------------
2.1: 啟動sshd
----------------------------------------
/etc/rc.d/init.d/sshd start
----------------------------------------
2.2: 用ssh 從外部登入。
----------------------------------------
需要先為root使用者設定一個密碼才能登陸: passwd root

ssh root@192.168.150.157  (根據實際情況修改登陸IP)
輸入密碼登陸。

為了方便,我們匯出一個環境變數。這樣我們就可以少打字了。
export LFS=/mnt/lfs
mkdir -pv $LFS            # 建立安裝點, 注意,重啟會丟失

掛載分割槽:
swapon /dev/hda1        # swap 掛載, 記憶體大於256M 也可以不掛載
mount /dev/hda2 $LFS    # $LFS (即/mnt/lfs) 就是該硬碟檔案系統了。
這樣對$LFS 的操作就是對硬碟進行操作了.

硬碟上建立兩個目錄,在硬碟上所做的改動,重啟後不會丟失。
例如建立目錄,修改屬性等。操作一次即可。
mkdir -v $LFS/sources
chmod -v a+wt $LFS/sources
將目錄或檔案的屬性設定為1777,這樣任何人都可以對其進行讀寫, t是防刪除位,非屬主不能刪除
mkdir -v $LFS/tools

如下每次重啟需要重新建立連結,因為光碟啟動後,/目錄後會丟失原有的改動
ln -sv $LFS/tools /        # 這句話是在根下建立一個tools 軟連線,指向$LFS/tools 目錄

----------------------------------------
2.3: 建立一個新使用者lfs,
----------------------------------------
建立一個新使用者lfs,
用新使用者而不是root 來編譯一些工具,這樣做的目的是為了操作的安全性
最初的編譯工具來源於cd.
編譯的工具儲存到/tools (硬碟裡)
# 建立組
2.3.1: groupadd lfs
groupadd 在哪裡檢視輸出? /etc/group 會有變化.

# 建立使用者
2.3.2: useradd -s /bin/bash -g lfs -m -k /dev/null lfs
passwd lfs
useradd 在哪裡檢視輸出? /etc/passwd(使用者), /etc/shadow(密碼)


# 重設硬碟tools, sources 目錄屬主
chown -v lfs $LFS/tools
chown -v lfs $LFS/sources

#切換使用者
2.3.3: su - lfs

# 編寫登陸shell, 非登陸shell 的預設啟動指令碼
# 通常登陸式shell會呼叫.bash_profile, 而非登陸shell呼叫.bashrc,
# 登陸式shell可以主動呼叫非登陸的入口.
2.3.4
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

# 當啟動指令碼改變時,使即時生效(不重啟shell)的方法。
source ~/.bash_profile

#檢查變數設定。
2.3.5 export


############################################################
3.
用新使用者登陸後,做我們自己的事情->編譯臨時工作環境
用宿主機的工具(livecd),構建自己的編譯工具鏈,放到/tools 目錄下。
這裡主要有兩個知識點
a: 升級gcc, 用現有的gcc 編譯一個新的gcc.
b: 升級glibc, 用gcc 編譯glibc.
當更新了glibc後, 要重新編譯gcc,因為gcc 依賴於glibc.
這裡要注意,怎樣才能使用新的gcc, 新的glibc!!
編譯其它的工具.
############################################################
這個過程,與交叉編譯工具鏈的建立, 形式上是一樣的。
由於gcc 會呼叫ld, 所以
------------------------------------------------------------
3.1. 首先編譯binutil, 然後再編譯gcc, 此時,它們使用的是舊的glibc
------------------------------------------------------------
因為binutil 包含了彙編器和聯結器,而gcc 在配置時,要檢查使用了哪個個彙編器和聯結器。

cd $LFS/sources
tar xvf /lfs-sources/binutils-2.17.tar.bz2
cd binutils-2.17

mkdir -v ../binutils-build
cd ../binutils-build
../binutils-2.17/configure --prefix=/tools --disable-nls --disable-werror
make
make install
#接下來為編譯聯結器, 為後面"調整工具鏈"做準備
make -C ld clean
make -C ld LIB_PATH=/tools/lib        #宣告庫路徑是硬碟上的lib
cp -v ld/ld-new /tools/bin
cd ..
rm -rf binutils-build
rm -rf binutils-2.17
----------------------------------------
3.2 編譯gcc
----------------------------------------
想知道gcc 使用了哪個聯結器,使用下面命令
gcc -print-prog-name=ld
gcc -v dummy.c 將顯示在預處理、彙編和編譯各個階段的詳細資訊,包括 gcc檔案包含的搜尋路徑及其順序。

tar xvf /lfs-sources/gcc-4.1.2.tar.bz2
mkdir -v gcc-build
cd gcc-build
../gcc-4.1.2/configure \
--prefix=/tools \
--with-local-prefix=/tools \
--disable-nls \   
--enable-shared --enable-languages=c

# 自舉,會編譯3遍,第一遍編譯出新gcc, 第二遍和第三遍用新gcc編譯gcc程式碼,編譯結果要完全一致才算通過。
make bootstrap                        
make install

# 因為有的程式或指令碼用cc 而不是gcc 來編譯,所以建一個連結. 問,這個gcc 是哪個gcc? 答,系統路徑下gcc.
ln -vs gcc /tools/bin/cc            
cd ..
rm -rf gcc-build
rm -rf gcc-4.1.2


----------------------------------------
3.3 copy linux header 檔案, glibc 編譯會用到核心標頭檔案
----------------------------------------
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

----------------------------------------
3.4 編譯glibc
----------------------------------------
這個glibc, 已經是半新的gcc 在編譯了(/tools/gcc ,它的路徑在前面)
Glibc C庫,包含分配記憶體、搜尋目錄、開啟關閉檔案、讀寫檔案、字串處理、模式匹配、數學計算等等。c語言成功的地方
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
make install
cd ..
rm -rf glibc-build
rm -rf glibc-2.5.1

在安裝 Glibc 的過程中,它會警告缺少 /tools/etc/ld.so.conf 檔案。其實這沒什麼關係,不過下面的命令能修正它:
mkdir -v /tools/etc
touch /tools/etc/ld.so.conf

----------------------------------------
3.5:調整工具鏈及gcc spec, 測試新環境
----------------------------------------
調整工具鏈:, 儲存一下舊的, 再使用新編譯的,
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 spec 檔案,使它執行新的動態聯結器。 (問題: gcc 使用spec 檔案嗎?)
#定義檔案變數,匯出內容,替換內容,刪除變數

SPECFILE=`dirname $(gcc -print-libgcc-file-name)`/specs &&
gcc -dumpspecs > $SPECFILE &&
sed 's@^/lib/ld-linux.so.2@/tools&@g' $SPECFILE > tempspecfile &&
mv -vf tempspecfile $SPECFILE &&
unset SPECFILE


使用變數的好處是替代檔名!
目的就是把gcc 的specs 中/lib/ld-linux.so.2 全部換成/tools/lib/ld-linuux.so.2

#清理GCC INCLUDED 檔案, 這是GCC 在編譯過程中產生的垃圾(中間檔案),可以刪除。
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 的調整
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,Expect,DejaGNU
----------------------------------------
3.6: 用新的glibc, 再次編譯gcc
----------------------------------------
現在glibc 編譯好了, 也調整了工具鏈及gcc spec, 需要第二遍編譯gcc, 這樣就使用了新的glibc及gcc
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2
cd gcc-4.1.2
cp -v gcc/Makefile.in{,.orig}
#禁止./fixinc.sh 指令碼執行
sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig > gcc/Makefile.in   

#新增-fomit-frame-pointer 選項
cp -v gcc/Makefile.in{,.tmp}
sed 's/^XCFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in.tmp > gcc/Makefile.in

# 這個補丁把/usr/include 從gcc 搜尋路徑刪除
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

再檢查elf檔案聯結器應該是/tools/lib/ld-linux.so.2

----------------------------------------
3.7: 用新的glibc 和 gcc 再一次編譯binutil
----------------------------------------
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                
makels
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
Bash-3.2
Bzip2-1.0.4
Coreutils-6.9
Diffutils-2.8.1
Findutils-4.2.31
Gawk-3.1.5
Gettext-0.16.1
Grep-2.5.1a
Gzip-1.3.12
Make-3.81
Patch-2.5.4..
Perl-5.8.8
Sed-4.1.5
Tar-1.18
Texinfo-4.9
Util-linux-2.12r
************************************************************
part II:
假如所有臨時工具都編譯好了,用新建的工具來構建自己的linux系統
************************************************************
概念:
虛擬核心檔案系統(Virtual Kernel File Systems)
由核心產生存在於記憶體但不存在於硬碟的檔案系統,他們被用來與核心進行通訊。
devfs,shm,proc,sysfs 都是核心檔案系統。
udev 未啟動前, 有些需手工建立裝置節點和掛載目錄,然後手工掛載。

建立三個重要目錄
mkdir -pv $LFS/{dev,proc,sys}

建立兩個目標系統所必須的裝置檔案
mknod -m 600 $LFS/dev/console c 5 1
mknod -m 666 $LFS/dev/null c 1 3

利用主系統載入幾個重要的檔案系統,請注意這個步驟對於後面的工作極其重要。
mount -v --bind /dev $LFS/dev
mount -vt devpts devpts $LFS/dev/pts
mount -vt tmpfs shm $LFS/dev/shm
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys

Chroot到目標系統的目錄下,以便不受主系統的影響來製作目標系統
chroot "$LFS" /tools/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/tools/bin/bash --login +h


env 命令屬於coreutils 包,
chroot 也屬於coreutils 包
/tools/bin/bash 屬於bash 包

建立目標系統的目錄結構, 據說i這是FHS(file hierachy standard)檔案層次結構
mkdir -pv /{bin,boot,etc/opt,home,lib,mnt,opt}
mkdir -pv /{media/{floppy,cdrom},sbin,srv,var}
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp
mkdir -pv /usr/{,local/}{bin,include,lib,sbin,src}
mkdir -pv /usr/{,local/}share/{doc,info,locale,man}
mkdir -pv /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
for dir in /usr /usr/local; do
ln -sv share/{man,doc,info} $dir
done
mkdir -pv /var/{lock,log,mail,run,spool}
mkdir -pv /var/{opt,cache,lib/{misc,locate},local}

建立幾個必要的連結,因為在目標系統的編譯過程中,部分編譯程式會用絕對路徑來尋找命令或檔案。
ln -sv /tools/bin/{bash,cat,echo,grep,pwd,stty} /bin
ln -sv /tools/bin/perl /usr/bin
ln -sv /tools/lib/libgcc_s.so{,.1} /usr/lib
ln -sv /tools/lib/libstdc++.so{,.6} /usr/lib
ln -sv bash /bin/sh
touch /etc/mtab

建立root及nobody使用者和必要的組
cat > /etc/passwd << "EOF"
root:x:0:0:root:/root:/bin/bash
nobody:x:99:99:Unprivileged User:/dev/null:/bin/false
EOF
cat > /etc/group << "EOF"
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
usb:x:14:
cdrom:x:15:
mail:x:34:
nogroup:x:99:
EOF

重新載入bash,以使root使用者生效,這樣前面的提示符就不會是“I have no name!”
exec /tools/bin/bash --login +h

到目前為止,建立目標系統的準備工作已基本完成,下面就要開始目標系統的軟體包安裝了。
假定/sources 下是原始碼目錄(cp -a /lfs-sources/* $LFS/sources/), 89個包
export LFS=/sources

下面是安裝列表: 大部分是我們熟悉的名字.編譯50個
1: Linux-2.6.22.5
2: Man-pages-2.63
3: Glibc-2.5.1
4: Binutils-2.17
5: GCC-4.1.2
6: Berkeley DB-4.5.20
7: Sed-4.1.5
8: E2fsprogs-1.40.2
9: Coreutils-6.9
10: Iana-Etc-2.20
11: M4-1.4.10
12: Bison-2.3
13: Ncurses-5.6
14: Procps-3.2.7
15: Libtool-1.5.24
16: Perl-5.8.8
17: Readline-5.2
18: Zlib-1.2.3
19: Autoconf-2.61
20: Automake-1.10
21: Bash-3.2
22: Bzip2-1.0.4
23: Diffutils-2.8.1
24: File-4.21
25: Findutils-4.2.31
26: Flex-2.5.33
27: GRUB-0.97e
28: Gawk-3.1.5
29: Gettext-0.16.1
30: Grep-2.5.1a
31: Groff-1.18.1.4
32: Gzip-1.3.12
33: Inetutils-1.5e
34: IPRoute2-2.6.20-070313
35: Kbd-1.12
36: Less-406
37: Make-3.81
38: Man-DB-2.4.4
39: Mktemp-1.5
40: Module-Init-Tools-3.2.2
41: Patch-2.5.4
42: Psmisc-22.5
43: Shadow-4.0.18.1
44: Sysklogd-1.4.1
45: Sysvinit-2.86
46: Tar-1.18
47: Texinfo-4.9
48: Udev-113
49: Util-linux-2.12r
50: Vim-7.1ma
然後是安裝核心和安裝grub, 就可以用硬碟啟動了.並且具有了不少常用工具.
************************************************************
part III:
遇到問題及解決方法:
1. make glibc-2.5.1 時出錯:
no gen-translit.pl < C-translit.h.in > C-translit.h.tmp
/bin/sh: no: command not found
解決方法: 是perl 工具n不能工作, 因為perl -V 不能執行, 儘管在不chroot時,或者
lfs使用者時都能執行perl, 不知道chroot後perl到底什麼地方出了問題, 還是認真的照
手冊第5章重做一遍,問題解決.
2. make menuconfig 時
Error opening terminal: eterm-color
解決辦法: 我是在emacs 下開ansi-term 遠端登陸操作,但make menuconfig 不支援eterm
所以只能直接在虛擬機器上操作,可以完成make LANG=c LC_All= menuconfig 操作

3. Interface eth0 doesn't exist
在配置核心時,驅動中,
在Device Drivers->Networking support->Ethernet (10 or 100Mbit)加入AMD PCnet32 PCI support的支援,可以採用編譯到核心也可以編譯成模組的方式

enjoy!
************************************************************

相關文章