《Linux From Scratch》第三部分:構建LFS係統 第六章:安裝基本的係統軟件- 6.3. 軟件包管理
軟件包管理是我們經常收到希望添加到 LFS
手冊裏的需求。一個軟件包管理器可以追蹤安裝的文件,這樣可以在移除或升級軟件包時輕鬆地清理。不僅是二進製執行文件和庫文件,包管理器還會處理配置文件的安裝。在你遐想之前提醒一下,不!——本節不涉及也不建議任何一個特定的包管理器,而是關於軟件包管理的更一般的技術的綜合概述。最適合你的包管理器可能就在這些技術裏,或者可能是兩個或更多的組合。本節還會簡要提到升級軟件包可能碰到的問題。
關於為什麼 LFS 或 BLFS 手冊裏不采用任何軟件包管理器的一些原因:
-
軟件包管理偏離了本手冊的主要目標——教大家 Linux 係統是如何構建出來的。
-
存在很多軟件包管理的解決方案,每一個都有自己的長處和缺點。很難選擇一種適合所有人的方式。
關於軟件包管理有很多資料,請訪問 Hints Project 看看是否有一個能適合你的需求。
6.3.1. 升級問題
軟件包管理器可以在軟件新版本發布後輕鬆升級。一般來說 LFS 和 BLFS 手冊裏的指令可以用來升級到新版本。下麵是一些在你準備升級軟件包時需要注意的事情,特別是在一個運行中的係統。
-
如果需要升級 Glibc 到新版本(比如,從 glibc-2.19 升級到 glibc-2.20),重新構建整個 LFS 會比較安全。雖然你也許能夠按依賴關係重新編譯所有的軟件包,不過我們不建議這樣做。
-
如果某個包含的動態庫的軟件包升級了,而且庫名字有改變,那麼所有動態鏈接到這個庫的軟件包都需要重新鏈接新的庫。(請注意軟件包版本和庫名字並不存在相關性。)舉個例子,某個軟件包 foo-1.2.3 安裝了一個名叫
libfoo.so.1
的動態庫。然後假設你把這個軟件包升級到了新版本 foo-1.2.4,而新版本會安裝名叫libfoo.so.2
的動態庫。在這種情況下,所有動態鏈接到libfoo.so.1
的軟件包都需要重新編譯鏈接到libfoo.so.2
。注意在所有依賴軟件包重新編譯完成之前,請不要刪除舊版的庫文件。
6.3.2. 軟件包管理技術
下麵介紹一些常見的軟件包管理技術。在決定用哪種包管理方式之前,先研究一下各種不同的技術,特別是了解特定體係下的不足。
6.3.2.1. 所有一切都在我腦袋裏!
是的,這也算一種軟件包管理技術。有些人覺得不需要管理軟件包,是因為他們非常熟悉軟件包,知道每個包都安裝了哪些文件。也有些用戶不需要管理軟件包,是因為他們會在某個軟件包有更改後重建整個係統。
6.3.2.2. 在獨立目錄裏安裝
這是一種簡單的軟件包管理方式,不需要其他額外的軟件來管理軟件的安裝。每一個軟件包都被裝到一個獨立的目錄裏。例如,軟件包 foo-1.1 安裝到目錄 /usr/pkg/foo-1.1
裏並創建一個軟鏈接 /usr/pkg/foo
指向 /usr/pkg/foo-1.1
。在安裝新版本 foo-1.2 的時候,它會被裝到目錄 /usr/pkg/foo-1.2
裏,然後將之前的軟鏈接替換成指向新版本軟件的位置。
類似 PATH
、LD_LIBRARY_PATH
、MANPATH
、INFOPATH
和 CPPFLAGS
之類的環境變量需要包含 /usr/pkg/foo
目錄。在管理大量軟件包時,這種方式就不可行了。
6.3.2.3. 軟鏈接方式軟件包管理
這是前一種軟件包管理技術的變種。每個軟件包都和之前方式一樣的安裝。但不是建立目錄的軟鏈接,而是把每個文件都鏈接到 /usr
目錄結構裏。這樣就不需要擴展環境變量了。通過自動創建這些可由用戶自己創建的鏈接,許多軟件包管理器都采用了這種方式。幾個比較流行的有 Stow、Epkg、Graft 和 Depot。
這種安裝方式需要偽裝,這樣軟件包會認為自己被裝到了 /usr
目錄下,而實際上它被裝到了 /usr/pkg
目錄結構中。在這種方式下,安裝並不是一件瑣碎的小事。例如,假如你準備安裝一個軟件包 libfoo-1.1。下麵的指令可能不會正確地安裝:
./configure --prefix=/usr/pkg/libfoo/1.1 make make install
安裝本身倒是沒有問題,但是可能一些依賴包不會像你期望的那樣鏈接 libfoo 庫。如果要編譯一個鏈接 libfoo 的軟件,你可能會注意到它實際上鏈接的是 /usr/pkg/libfoo/1.1/lib/libfoo.so.1
而不是你所期望的 /usr/lib/libfoo.so.1
。正確的方式是使用 DESTDIR
策略來偽裝軟件包的安裝過程。這種方式需要像下麵這樣操作:
./configure --prefix=/usr make make DESTDIR=/usr/pkg/libfoo/1.1 install
大多數軟件包支持這種方式,但也有一些例外。對於不兼容的軟件包,你可能需要自己手動安裝,或許你會發現將這些有問題的包安裝到 /opt
目錄下會更簡單些。
6.3.2.4. 基於時間戳
在這種方式裏,在安裝之前會創建一個時間戳文件。在安裝之後,用一行簡單的 find 命令加上合適的參數就可以生成在時間戳文件創建之後所安裝的所有文件列表。有一個采用這種方式的包管理器叫做 install-log。
這種方式的優點是非常簡單,但是它有兩個缺陷。比如,在安裝過程中,所安裝文件采用的是其它時間戳而不是當前時間,那這些文件將不能被軟件包管理器跟蹤到。還有,這種方式隻能在一次安裝一個軟件包的情況下使用。如果在不同的終端裏同時安裝兩個不同的軟件包,此時的安裝日誌就不可靠了。
6.3.2.5. 追蹤安裝腳本
在這種方式裏,安裝腳本所使用的命令都會被記錄下來。有兩種技術,一種技術是:
設定環境變量 LD_PRELOAD
指向一個在安裝前預加載的庫。在安裝過程中,這個庫會追蹤軟件包安裝腳本裏所包含的各種執行文件比如 cp、install、mv,以及追蹤會修改文件係統的係統調用。要讓這種方式有效的話,所有的執行文件需要動態鏈接到沒有 suid 或 sgid 標誌位的庫。預加載這個庫可能會引起安裝過程中一些意外的副作用。不過,建議做一些測試以保證軟件包管理器不會造成破壞並且記錄了所有適當的文件。
第二種技術是使用 strace 命令,它會記錄下安裝腳本執行過程中所有的係統調用。
6.3.2.6. 創建軟件包存檔
在這種方式裏,像之前的軟鏈接軟件包管理方式裏所描述的那樣,軟件包被偽裝安裝到一個獨立的目錄樹裏。在安裝完成後,會將已安裝文件打包成一個軟件包存檔。然後這個存檔會用來在本地機器或其他機器上安裝軟件包。
這種方式為商業發行版中的大多數包管理器所采用。一些例子是 RPM(它順便也是 Linux 標準規範 裏所要求的)、pkg-utils、Debian 的 apt、以及 Gentoo 的 Portage 係統。該頁麵描述了如何在 LFS 係統裏采用這種包管理方式: https://www.linuxfromscratch.org/hints/downloads/files/fakeroot.txt。
創建帶有依賴關係的軟件包存檔非常複雜,已經超出 LFS 手冊範圍了。
Slackware 使用一個基於 tar 的係統來創建軟件包存檔。這套係統不像那些更複雜的包管理器,有意地不處理包依賴關係。關於 Slackware 包管理器的詳細信息,請參看 https://www.slackbook.org/html/package-management.html。
6.3.2.7. 基於用戶的軟件包管理
在這種方式,是 LFS 特有的,由 Matthias Benkmann 所設計,可以在 Hints Project 裏能找到。在這種方式裏,每個軟件包都由一個單獨的用戶安裝到標準的位置。屬於某個軟件包的文件可以通過檢查用戶 ID 輕鬆識別出來。關於這種方式的特性和短處非常複雜,在本節裏說不清楚。詳細的信息請參看 https://www.linuxfromscratch.org/hints/downloads/files/more_control_and_pkg_man.txt。
6.3.3. 在多個係統上布置 LFS
LFS 係統的一個優點是沒有會依賴磁盤係統裏文件位置的文件。克隆一份 LFS 到和宿主機器相似配置的機器上,簡單到隻要對包含根目錄的 LFS 分區(對於一個基本的 LFS 構建不壓縮的話大概有 250MB)使用 tar命令打包,然後通過網絡傳輸或光盤拷貝到新機器上展開即可。在這之後,還需要調整一些配置文件,包括:/etc/hosts
、/etc/fstab
、/etc/passwd
、/etc/group
、/etc/shadow
和 /etc/ld.so.conf
。
根據係統硬件和原始內核配置文件的差異,可能還需要重新編譯一下內核。
最後,需要使用 8.4 “用 GRUB 設置引導過程”裏所介紹的方法讓新係統可引導。
創建者:Gerard Beekmans
編輯者:Matthew Burgess 和 Armin K.
翻譯團隊:LCTT
譯者/校對:zpl1025,wxy
最後更新:2017-11-07 17:03:57