Linux制作一個deb包如此簡單:Ubuntu的deb安裝包文件的內(nèi)部組成分析與使用原理
deb 文件是包含數(shù)據(jù)的存檔。標(biāo)有擴展名,用于輕松分發(fā)和安裝 Linux Debian 及其衍生發(fā)行版適合的程序。當(dāng)您的應(yīng)用程序需要處理其他依賴項、將自身與桌面集成、運行安裝前和安裝后腳本等時,Deb 文件非常方便。(與deb格式功能類似的另一種包格式是Fedora系列發(fā)行版常用的rpm文件。)
本文通過實例演示了如何制作一個簡單的deb包,講解了deb包的內(nèi)部各個文件的作用,以及安裝后在系統(tǒng)中如何生效、如何維護。
deb 包剖析
deb 是一個標(biāo)準(zhǔn)的 Unix ar 存檔格式[1],其中包含應(yīng)用程序和其他實用程序文件。最重要的一個是控制文件(control),它存儲了有關(guān) deb 包及其安裝的程序的信息。
- 在內(nèi)部,deb包 包含了模擬 Linux 的典型文件系統(tǒng)目錄結(jié)構(gòu)的文件集合,例如 /usr 、/usr/bin 、/opt等 。在安裝過程中,放置在其中一個目錄中的文件將被復(fù)制到實際文件系統(tǒng)中的同一位置。例如 軟件包內(nèi)的<.deb>/usr/bin/binaryfile 這樣的二進制文件將安裝到系統(tǒng)的 /usr/bin/binaryfile。
- 在外部,所有 deb 包文件都遵循特定的命名約定:
<軟件名稱>_<主版本號>-<修訂版本號>_<硬件架構(gòu)>.deb
假設(shè)您要發(fā)布名為 mynano 的程序,版本 1.0,該程序是為 64 位處理器(AMD64)構(gòu)建的。您的 deb 文件名將類似于 mynano_1.0-0_amd64.deb
制作 deb 包
現(xiàn)在,我們已準(zhǔn)備好生成包。確保您的系統(tǒng)中安裝了 dpkg-deb 工具(來自 dpkg 軟件包,可通過sudo apt install dpkg 安裝):稍后將使用dpkg-deb 生成最終deb包。
(1) 創(chuàng)建工作目錄 創(chuàng)建一個臨時工作目錄以將包放入其中。遵循我們之前看到的相同命名約定。例如:
mkdir mynano_1.0-1_amd64/
(2) 創(chuàng)建內(nèi)部結(jié)構(gòu) 將程序文件放在目標(biāo)系統(tǒng)上應(yīng)安裝的位置。假設(shè)您希望將可執(zhí)行文件安裝到:/usr/bin/
首先創(chuàng)建目錄:
mkdir -p mynano_1.0-1_amd64/usr/bin/
mkdir命令的-p標(biāo)志將創(chuàng)建嵌套目錄,如果其中任意目錄不存在則自動創(chuàng)建。然后將可執(zhí)行文件復(fù)制到其中:
# 假設(shè)你開發(fā)的程序可執(zhí)行文件為 ~/YourProjects/mynano/src/targets/release/mynano
cp ~/YourProjects/mynano/src/targets/release/mynano mynano_1.0-1_amd64/usr/bin/
(3) 創(chuàng)建文件control 該文件位于DEBIAN目錄中(注意目錄名為大寫字母)
先創(chuàng)建文件夾:DEBIAN
mkdir mynano_1.0-1_amd64/DEBIAN
然后創(chuàng)建空文件:control
touch mynano_1.0-1_amd64/DEBIAN/control
填寫control文件內(nèi)容:
Package: mynano
Version: 1.0
Architecture: amd64
Maintainer: linuxlibs <info@linuxlibs.com>
Description: 基于nano的自定義編輯器
Depends: nano (>= 5.0)
其中:
- Package– 程序名稱;
- Version– 程序版本;
- Architecture— 目標(biāo)架構(gòu);
- Maintainer– 包裹維護負責(zé)人的姓名和電子郵件地址;
- Description– 程序的簡要說明。
- Depends- 本軟件包依賴的其他軟件包。
該文件可能包含其他有用的字段,例如Depends指出deb包的依賴項列表。那么如果借助 apt 命令安裝 deb包的時候,就會先安裝上 nano>=5.0版本的軟件包,再安裝 mynano。
(5) 最后一步:構(gòu)建 deb 包 按如下方式調(diào)用dpkg-deb:
dpkg-deb --build --root-owner-group <package-dir>
在我們的示例中:
dpkg-deb --build --root-owner-group <mynano_1.0-1_amd64>
這里的 --root-owner-group 標(biāo)志使所有 deb 包內(nèi)容都歸 root 用戶所有,這是標(biāo)準(zhǔn)方法。如果沒有這樣的標(biāo)志,所有文件和文件夾的屬主都為您當(dāng)前的用戶,但考慮到 deb 軟件包將安裝到的系統(tǒng)中并不一定存在與你同名賬號,所以使用--root-owner-group 更合理。
上面的命令將在工作目錄旁邊生成一個.deb的文件,或者如果包內(nèi)有錯誤或丟失,則打印錯誤。如果操作成功,就可以分發(fā)這個生成的 deb 包給他人了。
(6) 使用deb包安裝到系統(tǒng):可以看到,通過apt方式安裝我們制作的deb包的時候,會自動安裝上依賴項:nano 軟件包
# apt install ./mynano_1.0-1_amd64.deb
正在讀取軟件包列表... 完成
正在分析軟件包的依賴關(guān)系樹... 完成
正在讀取狀態(tài)信息... 完成
注意,選中 'mynano' 而非 './mynano_1.0-1_amd64.deb'
將會同時安裝下列軟件:
nano
建議安裝:
hunspell
下列【新】軟件包將被安裝:
mynano nano
升級了 0 個軟件包,新安裝了 2 個軟件包,要卸載 0 個軟件包,有 79 個軟件包未被升級。
需要下載 280 kB/1,135 kB 的歸檔。
解壓縮后會消耗 881 kB 的額外空間。
您希望繼續(xù)執(zhí)行嗎? [Y/n] y
獲取:1 /root/my-nano-editor-src/mynano_1.0-1_amd64.deb mynano amd64 1.0.0 [855 kB]
獲取:2 https://mirrors.ustc.edu.cn/ubuntu jammy/main amd64 nano amd64 6.2-1 [280 kB]
已下載 280 kB,耗時 1秒 (422 kB/s)
正在選中未選擇的軟件包 nano。
(正在讀取數(shù)據(jù)庫 ... 系統(tǒng)當(dāng)前共安裝有 231799 個文件和目錄。)
準(zhǔn)備解壓 .../archives/nano_6.2-1_amd64.deb ...
正在解壓 nano (6.2-1) ...
正在選中未選擇的軟件包 mynano。
準(zhǔn)備解壓 .../mynano_1.0-1_amd64.deb ...
正在解壓 mynano (1.0.0) ...
正在設(shè)置 nano (6.2-1) ...
update-alternatives: 使用 /bin/nano 來在自動模式中提供 /usr/bin/editor (editor)
update-alternatives: 使用 /bin/nano 來在自動模式中提供 /usr/bin/pico (pico)
正在設(shè)置 mynano (1.0.0) ...
正在處理用于 install-info (6.8-4build1) 的觸發(fā)器 ...
正在處理用于 man-db (2.10.2-1) 的觸發(fā)器 ...
Scanning processes...
Scanning processor microcode...
Scanning linux images...
(7) 【非必須】卸載安裝的軟件 mynano:
# apt remove mynamo -y
正在讀取軟件包列表... 完成
正在分析軟件包的依賴關(guān)系樹... 完成
正在讀取狀態(tài)信息... 完成
下列軟件包將被【卸載】:
mynano
升級了 0 個軟件包,新安裝了 0 個軟件包,要卸載 1 個軟件包,有 79 個軟件包未被升級。
解壓縮后會消耗 0 B 的額外空間。
您希望繼續(xù)執(zhí)行嗎? [Y/n] y
(正在讀取數(shù)據(jù)庫 ... 系統(tǒng)當(dāng)前共安裝有 231872 個文件和目錄。)
正在卸載 mynano (1.0.0) ...
(8) 【非必須】查詢 mynano_0.1-1_amd64.deb 的依賴關(guān)系:dpkg -I ./mynano*deb
以上制作deb包的方式,還有哪些可改進的地方:
以上并沒有加入文件安裝后的額外處理腳本,而實際的deb軟件包,很多在安裝前、安裝后還要執(zhí)行一些初始化服務(wù)配置腳本;或執(zhí)行測試命令驗證安裝效果是否正常;安裝后通過腳本啟動后臺服務(wù)。
如何實現(xiàn)?
deb的規(guī)范支持添加 preinst、postinst、prerm 和 postrm 這4個腳本。置于/DEBIAN/目錄下。注意,這4個文件對于制作deb包來說,不是必須的,有需要的時候才添加。
例如我們?yōu)閙ynano在mynano_1.0-1_amd64/DEBIAN/ 目錄下添加4個文件:
preinst 文件內(nèi)容為:
#!/bin/bash
echo "來自preinst的消息"
postinst 文件內(nèi)容為:
#!/bin/bash
echo "一些適合在安裝后執(zhí)行的處理邏輯"
prerm 文件內(nèi)容為:
#!/bin/bash
echo "一些適合在卸載軟件前執(zhí)行的處理邏輯"
postrm 文件內(nèi)容為:
#!/bin/bash
echo "一些適合在卸載軟件后執(zhí)行的處理邏輯"
并設(shè)置文件權(quán)限為0555或0755,以避免報錯:
dpkg-deb: 錯誤: 維護者的腳本 preinst 的權(quán)限位是 644 (必須 >=0555 且 小于等于0775)`。
重新制作安裝包:
# chmod 755 mynano_1.0-1_amd64/DEBIAN/{preinst,postinst,prerm,postrm} ```
# cp -pr mynano_1.0-1_amd64 mynano_1.0-2_amd64 #修訂版本從1變?yōu)?
# 確保 preinst 等文件已在DEBIAN/目錄下。
# dpkg-deb --build --root-owner-group mynano_1.0-2_amd64
得到新的修訂版的mynano deb包文件:mynano_1.0-2_amd64.deb
安裝新包:
# apt install ./mynano_1.0-2_amd64.deb
正在讀取軟件包列表... 完成
正在分析軟件包的依賴關(guān)系樹... 完成
正在讀取狀態(tài)信息... 完成
注意,選中 'mynano' 而非 './mynano_1.0-2_amd64.deb'
下列【新】軟件包將被安裝:
mynano
升級了 0 個軟件包,新安裝了 1 個軟件包,要卸載 0 個軟件包,有 79 個軟件包未被升級。
需要下載 0 B/855 kB 的歸檔。
解壓縮后會消耗 0 B 的額外空間。
獲取:1 /root/tmp/my-nano-editor-src/mynano_1.0-2_amd64.deb mynano amd64 1.0.0 [855 kB]
正在選中未選擇的軟件包 mynano。
(正在讀取數(shù)據(jù)庫 ... 系統(tǒng)當(dāng)前共安裝有 231871 個文件和目錄。)
準(zhǔn)備解壓 .../mynano_1.0-2_amd64.deb ...
來自 preinst 的消息
正在解壓 mynano (1.0.0) ...
正在設(shè)置 mynano (1.0.0) ...
Scanning processes...
Scanning processor microcode...
Scanning linux images...
可以看到此時安裝中輸出了一段話:
正式 我們的preinst腳本的效果。
那么mynano的deb包安裝后,這些文件會被放置于 /var/lib/dpkg/info/ 目錄下,如mynano的腳本文件安裝后存儲于 /var/lib/dpkg/info/ 目錄下,以 mynano.*字符開頭的文件名就是 mynano的相關(guān)配置腳本:
# ls -lht /var/lib/dpkg/info/mynano.*
-rw-r--r-- 1 root root 49 1月 17 12:33 /var/lib/dpkg/info/mynano.md5sums
-rw-r--r-- 1 root root 33 1月 17 12:33 /var/lib/dpkg/info/mynano.list
-rwxr-xr-x 1 root root 44 1月 17 12:23 /var/lib/dpkg/info/mynano.preinst
# cat /var/lib/dpkg/info/mynano.preinst
#!/bin/bash
echo "來自preinst的消息"
下面分別介紹每個腳本文件的作用:
- preinst 安裝前做一些初始化工作,如目錄創(chuàng)建,文件創(chuàng)建,配置文件初始化等。
- postInst 安裝后做一些服務(wù)設(shè)置的處理。
- prerm 此腳本通常會停止與包關(guān)聯(lián)的任何守護程序。它在刪除與包關(guān)聯(lián)的文件之前執(zhí)行。
- postrm 此腳本用于修改鏈接或相關(guān)文件,然后刪除安裝包對應(yīng)的系統(tǒng)文件。
參考資料:
Unix ar 存檔格式: http://fileformats.archiveteam.org/wiki/AR