1. 前言 還記得大學第一次接觸Ubuntu和Linux的時候,覺得用apt安裝想要的軟體非常方便。但是有時候出現了問題,各種報錯,自己又不懂原理,就會非常抓狂。現在稍微理解一點了,故以較為容易理解的方式記錄在這裡,方便他人。 2. 軟體包與包管理器dpkg Linux里的軟體就是一些可執行文件。就 ...
1. 前言
還記得大學第一次接觸Ubuntu和Linux的時候,覺得用apt安裝想要的軟體非常方便。但是有時候出現了問題,各種報錯,自己又不懂原理,就會非常抓狂。現在稍微理解一點了,故以較為容易理解的方式記錄在這裡,方便他人。
2. 軟體包與包管理器dpkg
Linux里的軟體就是一些可執行文件。就像是你自己寫個main.c
,裡面printf("hello world");
,然後用gcc編譯出來的可執行文件一樣。
但是實際上的一個軟體不會這麼簡單,除了可執行文件本體以外,還會有一些庫、配置文件、圖標資源、文檔等。把這些東西打一個包,就是所謂的軟體包,例如:
- 在Debian系的Linux發行版(如Ubuntu、Raspbian、Armbian)中,軟體包尾碼名是
.deb
- 在RedHat系的Linux發行版(如CentOS、Fedora)中,軟體包尾碼名是
.rpm
- ...
要安裝一個下載好的.deb
軟體包,可以使用dpkg
工具。例如:
sudo dpkg -i xxxxxx.deb
所謂的安裝過程,其實就是根據.deb
包里的記述,把這些可執行文件、文檔、圖標、快捷方式等文件放到它們該在的位置。
如何知道一個軟體包到底安裝了哪些文件,這些文件安裝在哪些目錄下?可以使用dpkg -L
命令,例如:
dpkg -L gcc
要刪除一個.deb
包,可以使用dpkg -r <package_name>
。
dpkg
的更多使用方式,本文就不多介紹了,可自行搜索。
3. 包管理器apt與包的依賴關係
在Ubuntu中,更多時候我們是使用apt
來管理軟體包。那麼apt
和dpkg
有什麼關係和區別?
簡單來說,dpkg
是一個離線的本地包管理器,在安裝軟體包時,它只管把文件解壓出來並拷貝到對應的目錄下;在卸載軟體包時,它只管把之前安裝的文件從對應的位置刪除。也就是說,如果兩個軟體包內的文件有重覆的目錄名稱,使用dpkg
先後安裝這兩個軟體包時,也會直接覆蓋,dpkg不會管那麼多。
而apt
是一個“線上”的包管理器,apt
的底層其實就是dpkg
,但是apt
不需要自己提前下好.deb
包,它可以從apt源網站直接自動下載.deb
包併進行安裝。
但是apt的作用不止於此。這要從Unix系統的設計風格講起,通常,一些軟體包不會包含這個軟體執行所需要的全部文件,而是儘量去使用其他.deb
包提供的.so
動態鏈接庫等資源。這樣就形成了一個包對另一個包的依賴關係。這樣,Unix系統就可以形成全局的一個依賴樹,最好是所有庫都只保存一份,從而滿足了早期Unix程式員大佬們的“潔癖”。
你可以用dpkg -I /path/to/deb
來查看一個deb包的依賴信息。
所以,當你用apt
安裝一個軟體時,apt
會檢查你的電腦上是否有這個包的依賴包,如果缺少的話,apt會幫你把這個包的依賴包也安裝好。當你要卸載包時,apt
會幫你把當初裝的,現在用不到的那些依賴包們也同時卸載掉。
具體來說:
sudo apt install <package>
可以安裝一個包及其依賴項sudo apt remove <package>
可以卸載一個包,以及用不到的依賴項
再列舉一個場景,你從網上下載了一個deb包,使用sudo opkg -i
進行安裝,但是發現這個deb包有一些依賴項在你的電腦上是缺少的。這時你可以嘗試使用sudo apt install --fix-broken
來自動安裝這個deb包的依賴項。
4. 軟體源
Ubuntu官方會維護一個軟體包的倉庫,apt其實就是從這個倉庫下載軟體包。你可以使用apt update
來把本地的軟體包列表與軟體源進行同步,然後使用apt upgrade
來把本地所有軟體更新到最新。在安裝想要的軟體包之前也執行apt update
是一個好習慣。
官方軟體源的地址記錄在/etc/etc/apt/sources.list
中。
如果你覺得訪問官方源的速度太慢,也可以選擇國內的鏡像源,例如阿裡、清華、中科大等單位提供的鏡像源。
此外,如果官方的軟體源沒有收錄你想要的軟體,也可以添加PPA(Personal Package Archives)源,這樣你就可以從這些第三方倉庫中下載到你想要的軟體了。
5. 解決依賴問題
隨著Linux的發展,現在各種各樣的軟體實在是太多了,而且新舊版本不一定相容。舉一個常見的抓狂場景:你想使用A和B兩個軟體,A和B軟體包都依賴C軟體包,但是一個依賴1.0版本的C,一個依賴2.0版本的C,互相不相容,然後apt源下載到的還是1.5版本。
為瞭解決這個問題,你有好幾個選擇:
- 如果A和B都依賴的庫文件名不同(例如文件名攜帶版本號的情況),你可以去Ubuntu源站分別下載到這兩個版本的C軟體包,然後都用dpkg安裝一下即可;
- 如果A和B都依賴同一路徑下的同名但不同版本的庫,就麻煩了。A和B你只能留一個,另一個就得拉取源碼編譯,編譯的時候手動指定一個另外的路徑來鏈接對應版本的依賴包;
6.其他軟體安裝方式
為什麼我們比較少見到Windows上出現依賴的問題?因為軟體公司們在發佈軟體安裝包的時候,把所有依賴都打包在一起了,從而確保他們的軟體能在用戶的電腦上能直接運行。從商業上看這種行為確實是合理的,至於浪費了用戶的硬碟空間就無所謂了,反正現在2T的SSD也就五六百塊錢了。
在Linux上也有這種軟體,那就是AppImage
,它們打包了所有的依賴庫,可以直接運行。犧牲了空間,保證了穩定性。
不過AppImage需要自己從命令行執行,如果是GUI軟體的話,每次都要打開命令行運行比較麻煩。為瞭解決這個問題,可以安裝AppImageLauncher.
sudo add-apt-repository ppa:appimagelauncher-team/stable
sudo apt update
sudo apt install appimagelauncher
然後從GNOME桌面Applications菜單中找到appimagelauncher,設置好自己存放AppImage的目錄。這些AppImage就會出現在GNOME桌面系統的Applications菜單中了。
類似的思路,也可以使用Docker容器。不精確地講,容器就像虛擬機,把所有的依賴都準備好,然後把鏡像分享給別人,從而確保程式能夠運行。當然容器和虛擬機完全不是一個東西,本文不多介紹了。