你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Linux软件安装依赖问题的办法

[复制链接]
gaosmile 发布时间:2020-5-18 11:09

最近正好在研究dpkg和rpm,对Linux依赖有了更深的认识。+ M: {/ i+ c' E+ s8 E# e+ `

在网上看了很多,所有docker、虚拟机、编译安装、以及各种另辟蹊径的答案

都是面向日常繁重的业务没时间折腾而不得已做出的妥协和让步。

而我们面向技术的,「从来都喜欢正面硬刚!」

硬刚Linux软件安装依赖问题的办法有很多,我给他分为两大类!

「一类合法,另一类暴力。」


, A  Y' {: a+ G6 F3 s. z" y% X. Y

先说合法的解决方案! d# L2 Q/ L' D6 ~; g6 H
2 W  `  n- W+ _' z
% I6 d/ Y* y% F8 Y

也是所有人都知道的解决方案:

sudo apt-get install xxxxx
2 |2 n9 w0 g- p! F1 n0 z8 `  Q5 G+ f/ i$ B4 z4 ]- F5 e4 l

一般情况下,它会连带软件的依赖一起安装。如果这个过程中依赖安装失败,就执行

sudo apt-get -f install2 i/ c$ a- Y  Y: d; i6 }

2 k! y( q4 y/ V* W

一次不行两次,只要源里有,只要能保证依赖关系是顺畅的,再多的依赖多执行几次都能装完。

如果有依赖源里找不到。这个坑就踩不过去了,解决办法是:

找到缺失的库的安装包手动下载下来。然后通过sudo dpkg -i xxxx.deb安装。

4 G6 n. z& s& X4 H/ m

需要手动下载安装包的寻找主要有两个途径:

  • 百度找,直接搜包名+版本号并带上关键字deb
  • 通过源。
    3 C4 t* n' _0 F- ^) O


( Q' m8 [- Q# [

百度直接找库就不多说了,额外说一下通过源怎么找。

你在网上搜ubuntu国内源。会找到很多类似这样的写法:

deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse8 c0 |$ e0 o2 F' g0 z1 `

这其实即是给apt-get工具配置的源地址,也是个实际的网址,你可以直接从浏览器里访问到,比如上面这个http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse

它其实代表的

是:http://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/xenial/这个路径下的main,restricted,universe,multiverse 这几个目录:

微信图片_20200518105024.png

apt-get工具会在这四个的目录下自动检索对应的软件包下载并安装。

在一些特殊情况,比如机器网络受限,但浏览器开了代理可以访问外网的情况下。apt-get无法从源里获取软件,你可以从这里手动找到对应的软件包下载下来然后使用dpkg安装。

比如这里,手动找到mysql的安装包路径,再点击就可以直接下载:

! O. Q7 y8 f" {

微信图片_20200518105028.png


1 X7 L$ q. ^  P) z" [- q

刚才说道apt-get install无法修复依赖,通过手动下载然后把这些缺失的安装包装上之后,就可以通过apt把刚才装不上的包装上。

这是非常合理合法的解决方案。

6 i7 ?+ F8 k2 i" t" G0 Q

再补充一种合法技巧:可以尝试用「apt-get install安装本地软件」。

这是因为:

「依赖检测」和「软件安装」不是apt做的,而是dpkg做的。
1 p7 k/ u$ K5 G+ |$ D依赖不满足「自动修复依赖」才是apt做的。


: }3 J. F0 f4 k" d4 Z% ?

所以,如果你下载了一个deb的安装包通过dpkg安装,但依赖不满足的话,他只会提示你依赖缺失,但他不会自动寻找并安装依赖,虽然你仍然可以去下载安装缺失的依赖,但他如果缺失十个八个的,你再手动下载然后dpkg安装也不现实了。

举个例子:我这里下载了一个搜狗输入法的安装包,dpkg -i无法安装但是可以通过apt-get install装上

微信图片_20200518105031.png

要注意:通过apt-get安装本地软件一定要写路径,相对绝对都可以,但不能只写包名。不然它会去源里面找不会装本地的。

上面的方案几乎可以解决80%的安装依赖问题。总结一下:

  • 安装软件就用:「sudo apt-get install xxxx」
  • 遇到依赖问题 :「sudo apt-get -f install」
  • 如果有缺失无法安装,就去网上下,缺什么下什么,下载下来后「sudo apt-get install ./xxxx」 把缺的包安装上,再装原来的包。& k+ @; S0 e6 F9 C


- g$ o6 D$ f. a/ ~$ d
* S2 F7 a2 c0 K4 @. {
接下来说说暴力的解决方案:
* T( o/ f# E( S4 d9 d0 g& W! H6 a! m, `. M( @: {' i

  U$ u# b0 r; u5 Q$ j0 r

之所以说暴力,是因为刚才的方式,已经是在我的认知里,工具和系统提供的自动化程序能做到的极限。

如果还是出现了依赖无法满足的问题,比如什么即将安装xxxx但是现在的系统内的版本高于xxxx。

一般这种情况,系统已经不建议你再搞了,你如果非要硬来,很可能会破坏现有的程序依赖结构。

  • 运气好或者你手高,硬装上一点问题没有。
  • 影响小一点,你装了这个软件,另一个软件不能用或者会崩。
  • 影响大一点,有些系统令子不好使了,界面卡死了,资源管理器崩了等等。
  • 影响更大一点,装完用着啥毛病没有,重启后卡在加载过程,再也进不了系统。
    * R6 ^) L2 T8 ?9 \$ ~

「以上这些情况,我全部都遇到过!」

5 g7 S. G% M( h; K2 m

所以下面的搞法,你就当学习知识或看我装逼都行,自己实操,还是要谨慎地折腾。

至少,别在客户机器和生产环境的服务器上硬来。

暴力的解决方案有:

  • --ignore-depends,忽略依赖直接装。
  • 解压安装包,删掉依赖字段重新打包
  • 修改系统中记录的status文件
  • 无视安装失败,直接运行。
  • 直接拿到根目录,就地解压。
  • 改掉dpkg源码,直接不检测依赖。一个一个说:. P2 o' d# y2 j( A
' Q  O+ K7 F3 ~; a3 Q
3 ~9 w9 }/ F; q4 P* l
1、--ignore-depends& u8 O- s/ H1 P
' I1 e6 E3 d- f- `
7 a  d3 o% j# I4 m2 i& C1 {( c

这是所有暴力方案里技术门槛最低的一个,你可以通过dpkg --help 查看--ignore-depends选项:

选项:8 O4 y9 ^' e0 ~5 w" e
......其它选项
6 ~+ |' H; N, h. H  --ignore-depends=<软件包>,...! ^; M% `  R0 @" m1 `& l, ]
                             忽略关于 <软件包> 的所有依赖关系。/ L: q8 E6 v4 b$ S% G
  --force-...                忽视遇到的问题(参见 --force-help)。
5 X% V; B3 W) O3 E; w2 v5 x* }8 X......其它选项
5 U* \! h7 T- \  X

这个选项可以指定要忽略的依赖包。所以安装的时候如果依赖不满足,你直接加上这个参数把依赖忽略的就完了: 微信图片_20200518105034.png

当然,安装不会有任何问题,但是能不能用就看要造化了。

「并不是依赖不满足,装上就一定完全不能用」有时候只是功能不全而已。

比如你装了一个QQ,它依赖ffmpeg,你忽略了它后直接安装使用很可能没问题,但是一点击视频通话,程序立马就崩掉了。(这是个假设,QQ用啥不用啥我也不知道)

这个方案虽然门槛低,有个致命的缺陷就是太麻烦,我这里缺两个,写两个ignore。安装过程中经常遇到那种一下子缺十个八个的,要写十个八个这样的参数属实费劲。

3 S* p! B; s( X; C" l2 W0 @

2、解压安装包,删掉依赖字段重新打包- t1 X4 M' z! z# U1 h8 L1 V

( q; t" \  x- {) A( p1 l. F

" r+ V7 x# G8 T1 [0 H$ h; l

这个方案可以直接大刀阔斧地把软件包的依赖全干掉,不过稍微需要点技术底子:

「首先你得会解压安装包,其次你得会制作安装包。」

dpkg -X 只会解压出安装包的文件,无法解压出安装包带的脚本和控制信息。

右键提取到此处,解压出来的control和data分开两个压缩包,也不是打包前完美的状态。

这里要用的是

dpkg-deb -R sogoupinyin_xxxx.deb ./sogou+ W5 g: }' t; ^7 J

这样解压出来的就是deb在被打包前完完整整的样子,我解压了一个搜狗输入法的安装包为例:

微信图片_20200518105037.png

其他的我们都不用管,直接打开control文件:

微信图片_20200518105041.png

看到红框的部分了吧,直接把这行全部干掉。然后再把拆出来的文件重新打回一个安装包:

fakeroot dpkg-deb --build ./sogou mysogou.deb
0 O8 |! t# B3 [4 }1 ^

这个自己打的mysogou安装包,和搜狗原生安装包唯一的区别就是没有依赖

这下就可以一路畅通无阻,直接装完。

, _! l; Q7 ~1 {! j3 f# }/ I% M

3、修改系统中记录的status文件, ^2 d  \# t+ ~. s6 N2 Q
0 A* v5 c9 {+ N) u* c

) B( d- m3 ^3 O# t& l

和刚才那个方案思路差不多,只不过换了一个突破点,比刚才要更方便一点。

刚才我们突破的思路是:安装包里记录有对软件依赖,全部干掉就没有依赖了。

那么这个方案的思路则是:如果检测依赖发现系统不满足,我们给他伪造一个满足的依赖环境不就完了!

刚才我们说的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
+ F* q: S1 `5 Y$ B: O0 ]Priority: optional
. W2 K( \$ C1 s, SSection: editors
4 s8 K  A1 T/ E$ q, |! |: [; QMaintainer: Threedog Team <qiugeyafang@gmail.com>( [' w' |; G7 w8 n
Architecture: all
) |( U& E7 @; \/ B( Y' r& y' B% W( ?Version: 1.0.0
) W, g" J" K4 ^: e& E( ZHomepage: http://www.threedog.top
( l3 I' O, B  FDescription: test

# U5 }* ?  Y  ~

只要把Package换成缺失的依赖包的名字,加到status文件里就可以了。记得和其他软件信息之间要有空行。

6 v8 z; W6 l2 I

4、无视安装失败,直接运行。
" i' c; J" h$ b) I( D9 E1 E7 q
. n# b$ Q) p' m1 m) v. ^) s: y

$ ~5 U% N4 u' G

这个方案之所以可行,是dpkg对软件安装过程的执行机制决定的。dpkg对依赖的处理时机是:「先释放文件,再检测依赖,然后再完成最终配置。」

其实control里还可以写一个字段叫做预依赖:Pre-Depends这个字段的检测级别和时机与“架构Architecture”字段相当。写在这个字段里面的依赖,如果检测不满足,安装会直接中断,不会释放文件,status中不会记录,系统中也不会留下任何痕迹。

所以,当dpkg爆出依赖不满足的问题的时候,其实包里的文件已经释放到系统里了,只不过没有做后续的配置。比如:桌面图标配置、字体配置、文件关联设置、启动触发设置、等等等等。

但这并不妨碍你直接找到他的可执行程序文件直接执行。

如果你不知道他往系统里释放了哪些文件,第一,可以解压看下目录结构,第二,可以通过dpkg --contents xxxx.deb查看包里包含哪些文件。

也可以用dpkg -S +软件名查看已经安装的软件在系统里装了哪些东西。

然后找到二进制可执行文件,一般都会往/usr/bin/下面放一个,运气好的话直接执行有可能能跑起来。

0 a" E0 \& u! t$ ^& p8 A! `

5、暴力解压; q& O  S/ M- j- L% @# v. n
, |' A" g$ g$ G+ p3 J* _/ p
6 S: U& e7 {* n" u! Z' U4 n; b% I% o

这个方案属实有点过于暴力并且不合理。直接把安装包移动到根目录下,然后直接dpkg -X解压到当前。然后像刚才一样找二进制可执行程序调用。

前提是你知道这软件包里有什么并且明确它不会影响什么的话。

不然如果解压出的文件破坏了系统的重要文件,那直接就是不可逆的毁降维打击。

而且这么搞完,如何卸载也是一个问题......

- G+ [% g2 s- Y' O  b! b6 o

6、改dpkg源码
3 {/ Z& A% M" [! T+ o+ f2 ~% f9 o; B- K# l7 n/ V$ c# L
0 m3 l4 O9 W: q2 N" A# B* Q

这是技术上最硬核的解决方案。

主要操作方法如下:

从这个地址:http://git.dpkg.org/git/dpkg/dpkg.git

clone下来dpkg源码,在源码里的packages.c里面找到这个dependencies_ok函数。甭管他里面写了多少东西,直接在最开头给他return DEP_CHECK_OK; 或者return 2;反正就是个枚举。

然后把项目编译一下生成自己的dpkg用就可以。

我这里自己编译的dpkg多加了一行输出,效果明显一点:

微信图片_20200518105044.png

这个函数改的是对Depends字段的依赖检测

如果是预依赖,Pre-Depends:字段,要改的是另一个名为depisok的函数。

关于dpkg项目源码的编译,用的是Linux c项目automake那一套。C/C++老炮闭着眼就编过去了,没入门的萌新连怎么下手都不知道。像我这种刚入门的菜鸡,就得每走一步拿小本本记一下一点,也想这样玩一下的小伙伴可以参考:http://blog.csdn.net/Three_dog/article/details/103418141

有了这个自己编译的dpkg,所有软件都可以无阻碍安装

不过至于装完能不能用,会不会有啥问题,恐怕就得看造化了。


dpkg的解决方案全部讲完,说说rpm。

之所以对rpm只字未提有两个原因:

「一是我对它的熟悉程度,远没有dpkg这么深入。」
2 ]0 J: |$ G# K3 V「二是它真的,相比dpkg,难用的令人抓狂。」

在合法的解决方案上,rpm和dpkg没有太大区别。你只需要把上面的对照方案,dpkg+apt-get换成rpm+yum就可以。我们不多赘述了。

主要说说非法方案:

rpm的机制,几乎导致我所有的非法方案完全不可用!

% t+ t3 q) T, a

方案一

可用的只有这一个:忽略依赖,这是在rpm上唯一可以对标的非法解决方案,只需要把--ignore-depends 换成--nodeps就可以。

其他的,几乎都不行:

% \' W* j. P# A# w5 p1 {: H

方案二

rpm打包的时候,配置信息写在一个.spec文件里,对标上面的control文件,这个文件的写法规范恶心程度就不说了,重要的是它无法从打好的rpm安装包里逆向解压出来。

你只能用rpm --scripts -qa xxxx.rpm来查看,而且看到的和它原来真正的写法有很大不同,你甚至可以理解成用objdump看可执行程序的感觉。

这个机制,导致了上面的方案2(解压安装包,删掉依赖字段重新打包)被毙掉。

0 U* |- L$ G5 \+ W  c

方案三

rpm 安装到系统中的软件,也有一个文件统一管理,但是!它丫的天杀的居然用的是一个数据库管理的:

微信图片_20200518105047.png

这是编译rpm时候configure参数,这三种数据库编译时可选,安装版一般是Berkeley DB。

用数据库管理,就存成二进制数据文件了!就不像我们刚才的status直接修改文本了,而恶心就恶心在(我水平太次也是一方面),这三种数据库我折腾了半天也没找下工具能对他们增删改查!

换句话说这个数据库内容的操作,只有rpm可以,不面向用户。

因此,上面的方案3(修改系统中记录的status软件)也被毙掉了

4 Y$ A/ c0 T. _) V# x8 f

方案四

rpm的安装只有一种依赖检查的时机,就是在释放文件前。

所以如果出现依赖问题,包里面的文件一滴也不会漏到系统上来,上面的方案4(无视安装失败,直接运行)也被毙掉了。


  O7 U: k) w0 U8 \

方案五

方案5,直接暴力解压是可以的。不过上面也说了,这实在是下下下下下下策。

1 t' `/ d+ S9 S( A1 E

方案六

最后一个,改rpm的源码。

以我的水平,说实话还没有权利对一个成熟的开源项目源码评头论足,但一个不争的事实是:我想像上面那种改dpkg的改法改rpm的源码。折腾了一圈子确实没找到咋改。

所以方案6(修改项目源码)也基本宣告流产。

我想这也是很多人认为dpkg比rpm好用太多的原因之一。

rpm把数据全部用数据库管理起来,看似增强了安全性,但是对于酷爱折腾的Linuxer来说,这种可操控性上带来的降维打击简直无法忍受。

除此之外,它还有非常难用的命令组合;令人沮丧的软件源配置方法;以及地狱难度的打包规规范;打包还不留原文件等等让人觉得它难用的特性在里面!(打包规范真的是折磨人!一不小心打错了,连原文件都没得咯!一个都没得咯!!)

以上,就是以我现有的水平,可以提供的所有针对Linux鬼畜逆天级的软件依赖关系的解决方案。可以看得出来,有些方案是吃一点儿技术底子的。

很多技术问题都是这样,当你对准某一方向钻研到一定深度的时候,很多在常人看来不可能实现的操作,在你手里就可以为所欲为!(我妻善逸:集中一点,登峰造极)

而且我相信,肯定还有我没想到的好办法可以解决这些问题,有可以提供方案或者思路的大佬请一定赐教!



! c- u/ N, u4 p3 S' l

最后,再纠正一个很多人的认知误区:


$ n% F" J( Z5 o4 ]5 k

直到现在,有几乎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格式的安装包。

只要安装的软件所释放出文件没有冲突,两者在系统上的相处模式,甚至可以用举案齐眉、相敬如宾来形容。

根本不像大多数人认为的那样老死不相往来:

微信图片_20200518105050.png

赞 收藏 评论0 发布时间:2020-5-18 11:09

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版