最近正好在研究dpkg和rpm,對Linux依賴有了更深的認識。
在網上看了很多,所有docker、虛擬機、編譯安裝、以及各種另辟蹊徑的答案
都是面向日常繁重的業務沒時間折騰而不得已做出的妥協和讓步。
而我們面向技術的,「從來都喜歡正面硬剛!」
硬剛Linux軟件安裝依賴問題的辦法有很多,我給他分為兩大類!
「一類合法,另一類暴力。」
先說合法的解決方案
也是所有人都知道的解決方案:
sudo apt-get install xxxxx
一般情況下,它會連帶軟件的依賴一起安裝。如果這個過程中依賴安裝失敗,就執行
sudo apt-get -f install
一次不行兩次,只要源里有,只要能保證依賴關系是順暢的,再多的依賴多執行幾次都能裝完。
如果有依賴源里找不到。這個坑就踩不過去了,解決辦法是:
找到缺失的庫的安裝包手動下載下來。然后通過sudo dpkg -i xxxx.deb
安裝。
需要手動下載安裝包的尋找主要有兩個途徑:
- 百度找,直接搜包名+版本號並帶上關鍵字deb
- 通過源。
百度直接找庫就不多說了,額外說一下通過源怎么找。
你在網上搜ubuntu
國內源。會找到很多類似這樣的寫法:
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
這其實即是給apt-get
工具配置的源地址,也是個實際的網址,你可以直接從瀏覽器里訪問到,比如上面這個https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse
它其實代表的是:https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/xenial/這個路徑下的main
,restricted
,universe
,multiverse
這幾個目錄:
apt-get
工具會在這四個的目錄下自動檢索對應的軟件包下載並安裝。
在一些特殊情況,比如機器網絡受限,但瀏覽器開了代理可以訪問外網的情況下。apt-get
無法從源里獲取軟件,你可以從這里手動找到對應的軟件包下載下來然后使用dpkg
安裝。
比如這里,手動找到mysql
的安裝包路徑,再點擊就可以直接下載:
剛才說道apt-get install無法修復依賴,通過手動下載然后把這些缺失的安裝包裝上之后,就可以通過apt把剛才裝不上的包裝上。
這是非常合理合法的解決方案。
再補充一種合法技巧:可以嘗試用「apt-get install安裝本地軟件」。
這是因為:
「依賴檢測」和「軟件安裝」不是apt做的,而是dpkg做的。
依賴不滿足「自動修復依賴」才是apt做的。
所以,如果你下載了一個deb
的安裝包通過dpkg
安裝,但依賴不滿足的話,他只會提示你依賴缺失,但他不會自動尋找並安裝依賴,雖然你仍然可以去下載安裝缺失的依賴,但他如果缺失十個八個的,你再手動下載然后dpkg安裝也不現實了。
舉個例子:我這里下載了一個搜狗輸入法的安裝包,dpkg -i
無法安裝但是可以通過apt-get install
裝上
要注意:通過apt-get
安裝本地軟件一定要寫路徑,相對絕對都可以,但不能只寫包名。不然它會去源里面找不會裝本地的。
上面的方案幾乎可以解決80%的安裝依賴問題。總結一下:
- 安裝軟件就用:「sudo apt-get install xxxx」
- 遇到依賴問題 :「sudo apt-get -f install」
- 如果有缺失無法安裝,就去網上下,缺什么下什么,下載下來后「sudo apt-get install ./xxxx」 把缺的包安裝上,再裝原來的包。
接下來說說暴力的解決方案:
之所以說暴力,是因為剛才的方式,已經是在我的認知里,工具和系統提供的自動化程序能做到的極限。
如果還是出現了依賴無法滿足的問題,比如什么即將安裝xxxx但是現在的系統內的版本高於xxxx。
一般這種情況,系統已經不建議你再搞了,你如果非要硬來,很可能會破壞現有的程序依賴結構。
- 運氣好或者你手高,硬裝上一點問題沒有。
- 影響小一點,你裝了這個軟件,另一個軟件不能用或者會崩。
- 影響大一點,有些系統令子不好使了,界面卡死了,資源管理器崩了等等。
- 影響更大一點,裝完用着啥毛病沒有,重啟后卡在加載過程,再也進不了系統。
「以上這些情況,我全部都遇到過!」
所以下面的搞法,你就當學習知識或看我裝逼都行,自己實操,還是要謹慎地折騰。
至少,別在客戶機器和生產環境的服務器上硬來。
暴力的解決方案有:
- --ignore-depends,忽略依賴直接裝。
- 解壓安裝包,刪掉依賴字段重新打包
- 修改系統中記錄的status文件
- 無視安裝失敗,直接運行。
- 直接拿到根目錄,就地解壓。
- 改掉dpkg源碼,直接不檢測依賴。一個一個說:
1、--ignore-depends
這是所有暴力方案里技術門檻最低的一個,你可以通過dpkg --help
查看--ignore-depends
選項:
這個選項可以指定要忽略的依賴包。所以安裝的時候如果依賴不滿足,你直接加上這個參數把依賴忽略的就完了:
當然,安裝不會有任何問題,但是能不能用就看要造化了。
「並不是依賴不滿足,裝上就一定完全不能用」有時候只是功能不全而已。
比如你裝了一個QQ,它依賴ffmpeg,你忽略了它后直接安裝使用很可能沒問題,但是一點擊視頻通話,程序立馬就崩掉了。(這是個假設,QQ用啥不用啥我也不知道)
這個方案雖然門檻低,有個致命的缺陷就是太麻煩,我這里缺兩個,寫兩個ignore。安裝過程中經常遇到那種一下子缺十個八個的,要寫十個八個這樣的參數屬實費勁。
2、解壓安裝包,刪掉依賴字段重新打包
這個方案可以直接大刀闊斧地把軟件包的依賴全干掉,不過稍微需要點技術底子:
「首先你得會解壓安裝包,其次你得會制作安裝包。」
dpkg -X
只會解壓出安裝包的文件,無法解壓出安裝包帶的腳本和控制信息。
右鍵提取到此處,解壓出來的control
和data
分開兩個壓縮包,也不是打包前完美的狀態。
這里要用的是
dpkg-deb -R sogoupinyin_xxxx.deb ./sogou
這樣解壓出來的就是deb在被打包前完完整整的樣子,我解壓了一個搜狗輸入法的安裝包為例:
其他的我們都不用管,直接打開control
文件:
看到紅框的部分了吧,直接把這行全部干掉。然后再把拆出來的文件重新打回一個安裝包:
fakeroot dpkg-deb --build ./sogou mysogou.deb
這個自己打的mysogou安裝包,和搜狗原生安裝包唯一的區別就是沒有依賴
這下就可以一路暢通無阻,直接裝完。
3、修改系統中記錄的status文件
和剛才那個方案思路差不多,只不過換了一個突破點,比剛才要更方便一點。
剛才我們突破的思路是:安裝包里記錄有對軟件依賴,全部干掉就沒有依賴了。
那么這個方案的思路則是:如果檢測依賴發現系統不滿足,我們給他偽造一個滿足的依賴環境不就完了!
剛才我們說的control
文件,所有的deb都有,安裝過程中(不是安裝后也不是前),他就被記錄在了系統里的:「/var/lib/dpkg/status」文件里。
這個文件里的內容,也是dpkg -l
命令顯示內容的信息來源。
也是我們上面說的,依賴檢測時檢索系統內是否滿足依賴的信息來源。
如果軟件通過dpkg -r
卸載,這個status
文件里的信息不會刪除,只會把Status
字段改為:deinstall ok config-files
。通過dpkg -P
或者dpkg --purge
才會把信息完全抹除。
所以,依賴不滿足的時候,你可以直接打開這個文件,仿照其他軟件的寫法,照抄一段加上,把文件名改為缺失的依賴包的名字就可以!dpkg就會認為,系統里有安裝這個包,從而解決依賴導致的無法安裝的問題。
同樣,如果出現依賴的包需要的版本不滿足的情況,你也可以直接找到文件里對應的包的信息,改掉Version
字段到一個滿足需求的版本就可以。
當然,實際上系統里是沒有安裝這些庫的,我們只是騙過了dpkg。
系統里的軟件信息一般都寫得特別多,這里簡單提供個樣例,實在不會抄系統的就抄這個:
Package: mtest Priority: optional Section: editors Maintainer: Threedog Team <qiugeyafang@gmail.com> Architecture: all Version: 1.0.0 Homepage: http://www.threedog.top Description: test
只要把Package
換成缺失的依賴包的名字,加到status
文件里就可以了。記得和其他軟件信息之間要有空行。
4、無視安裝失敗,直接運行。
這個方案之所以可行,是dpkg對軟件安裝過程的執行機制決定的。dpkg對依賴的處理時機是:「先釋放文件,再檢測依賴,然后再完成最終配置。」
其實control里還可以寫一個字段叫做預依賴:Pre-Depends這個字段的檢測級別和時機與“架構Architecture”字段相當。寫在這個字段里面的依賴,如果檢測不滿足,安裝會直接中斷,不會釋放文件,status中不會記錄,系統中也不會留下任何痕跡。
所以,當dpkg爆出依賴不滿足的問題的時候,其實包里的文件已經釋放到系統里了,只不過沒有做后續的配置。比如:桌面圖標配置、字體配置、文件關聯設置、啟動觸發設置、等等等等。
但這並不妨礙你直接找到他的可執行程序文件直接執行。
如果你不知道他往系統里釋放了哪些文件,第一,可以解壓看下目錄結構,第二,可以通過dpkg --contents xxxx.deb
查看包里包含哪些文件。
也可以用dpkg -S +軟件名
查看已經安裝的軟件在系統里裝了哪些東西。
然后找到二進制可執行文件,一般都會往/usr/bin/
下面放一個,運氣好的話直接執行有可能能跑起來。
5、暴力解壓
這個方案屬實有點過於暴力並且不合理。直接把安裝包移動到根目錄下,然后直接dpkg -X
解壓到當前。然后像剛才一樣找二進制可執行程序調用。
前提是你知道這軟件包里有什么並且明確它不會影響什么的話。
不然如果解壓出的文件破壞了系統的重要文件,那直接就是不可逆的毀降維打擊。
而且這么搞完,如何卸載也是一個問題......
6、改dpkg源碼
這是技術上最硬核的解決方案。
主要操作方法如下:
從這個地址:https://git.dpkg.org/git/dpkg/dpkg.git
clone下來dpkg源碼,在源碼里的packages.c
里面找到這個dependencies_ok
函數。甭管他里面寫了多少東西,直接在最開頭給他return DEP_CHECK_OK;
或者return 2;
反正就是個枚舉。
然后把項目編譯一下生成自己的dpkg用就可以。
我這里自己編譯的dpkg多加了一行輸出,效果明顯一點:
這個函數改的是對Depends
字段的依賴檢測
如果是預依賴,Pre-Depends:
字段,要改的是另一個名為depisok
的函數。
關於dpkg項目源碼的編譯,用的是Linux c項目automake那一套。C/C++老炮閉着眼就編過去了,沒入門的萌新連怎么下手都不知道。像我這種剛入門的菜雞,就得每走一步拿小本本記一下一點,也想這樣玩一下的小伙伴可以參考:https://blog.csdn.net/Three_dog/article/details/103418141
有了這個自己編譯的dpkg,所有軟件都可以無阻礙安裝
不過至於裝完能不能用,會不會有啥問題,恐怕就得看造化了。
dpkg的解決方案全部講完,說說rpm。
之所以對rpm只字未提有兩個原因:
「一是我對它的熟悉程度,遠沒有dpkg這么深入。」
「二是它真的,相比dpkg,難用的令人抓狂。」
在合法的解決方案上,rpm
和dpkg
沒有太大區別。你只需要把上面的對照方案,dpkg+apt-get
換成rpm+yum
就可以。我們不多贅述了。
主要說說非法方案:
rpm的機制,幾乎導致我所有的非法方案完全不可用!
方案一
可用的只有這一個:忽略依賴,這是在rpm上唯一可以對標的非法解決方案,只需要把--ignore-depends
換成--nodeps
就可以。
其他的,幾乎都不行:
方案二
rpm打包的時候,配置信息寫在一個.spec
文件里,對標上面的control
文件,這個文件的寫法規范惡心程度就不說了,重要的是它無法從打好的rpm安裝包里逆向解壓出來。
你只能用rpm --scripts -qa xxxx.rpm
來查看,而且看到的和它原來真正的寫法有很大不同,你甚至可以理解成用objdump
看可執行程序的感覺。
這個機制,導致了上面的方案2(解壓安裝包,刪掉依賴字段重新打包)被斃掉。
方案三
rpm 安裝到系統中的軟件,也有一個文件統一管理,但是!它丫的天殺的居然用的是一個數據庫管理的:
這是編譯rpm時候configure
參數,這三種數據庫編譯時可選,安裝版一般是Berkeley DB
。
用數據庫管理,就存成二進制數據文件了!就不像我們剛才的status
直接修改文本了,而惡心就惡心在(我水平太次也是一方面),這三種數據庫我折騰了半天也沒找下工具能對他們增刪改查!
換句話說這個數據庫內容的操作,只有rpm可以,不面向用戶。
因此,上面的方案3(修改系統中記錄的status軟件)也被斃掉了
方案四
rpm的安裝只有一種依賴檢查的時機,就是在釋放文件前。
所以如果出現依賴問題,包里面的文件一滴也不會漏到系統上來,上面的方案4(無視安裝失敗,直接運行)也被斃掉了。
方案五
方案5,直接暴力解壓是可以的。不過上面也說了,這實在是下下下下下下策。
方案六
最后一個,改rpm的源碼。
以我的水平,說實話還沒有權利對一個成熟的開源項目源碼評頭論足,但一個不爭的事實是:我想像上面那種改dpkg的改法改rpm的源碼。折騰了一圈子確實沒找到咋改。
所以方案6(修改項目源碼)也基本宣告流產。
我想這也是很多人認為dpkg比rpm好用太多的原因之一。
rpm把數據全部用數據庫管理起來,看似增強了安全性,但是對於酷愛折騰的Linuxer來說,這種可操控性上帶來的降維打擊簡直無法忍受。
除此之外,它還有非常難用的命令組合;令人沮喪的軟件源配置方法;以及地獄難度的打包規規范;打包還不留原文件等等讓人覺得它難用的特性在里面!(打包規范真的是折磨人!一不小心打錯了,連原文件都沒得咯!一個都沒得咯!!)
以上,就是以我現有的水平,可以提供的所有針對Linux鬼畜逆天級的軟件依賴關系的解決方案。可以看得出來,有些方案是吃一點兒技術底子的。
很多技術問題都是這樣,當你對准某一方向鑽研到一定深度的時候,很多在常人看來不可能實現的操作,在你手里就可以為所欲為!(我妻善逸:集中一點,登峰造極)
而且我相信,肯定還有我沒想到的好辦法可以解決這些問題,有可以提供方案或者思路的大佬請一定賜教!
最后,再糾正一個很多人的認知誤區:
直到現在,有幾乎80%的科普性文章在介紹rpm和deb
的時候,把他們與redhat和debian
死死的綁定在一起。以至於很多人潛意識里認為:debian系只能用dpkg,紅帽系只能用rpm。
其實完全不是。他們的關系,是系統和軟件的關系,僅僅是debian
自帶dpkg
和apt
,紅帽
自帶rpm
和yum
而已。
ubuntu完全可以通過 sudo apt-get install rpm
安裝一個rpm,然后通過rpm安裝各種rpm格式的安裝包。
而centos,也完全可以通過編譯安裝
(因為yum源里沒有dpkg 噗~) 一個dpkg,然后安裝各種deb格式的安裝包。
只要安裝的軟件所釋放出文件沒有沖突,兩者在系統上的相處模式,甚至可以用舉案齊眉、相敬如賓來形容。
根本不像大多數人認為的那樣老死不相往來: