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