Ubuntu误删kernel-package和essential-build软件包问题的解决方案

回眸只為那壹抹淺笑 提交于 2019-12-04 12:00:30

先说起因(略长),操作系统是Ubuntu xenial (16.04.10 LTS) server版,原本打算安装perl5-16,但是在make test的时候总是有各种奇怪的问题,尝试的了许多个版本(perl5-14, perl5-16, perl5-18)都没能成功安装,而perl5-20以上的版本能够安装成功,似乎很多人都在Ubuntu上遇到的了这个问题https://github.com/gugod/App-perlbrew/issues/611,但是目前我还没有找到解决方案。回到正题,因为在CentOS能够成功安装,于是我考虑问题有可能是出在编译器上(因为安装成功的CentOS上配置的是gcc 4.x,这个安装失败的Ubuntu上配置的是gcc 5.x,gcc 5.x似乎在ABI上有所改变,这个问题会导致有些使用旧版编译器编译的库文件无法正常的和使用新版编译器编译的程序正常工作),总之就是尝试安装一个旧版编译器,然后试试能否安装成功。但是安装旧版gcc的过程中,遇到了缺少依赖GMP、MPFR、MPC的问题,后来找了一个deb包用apt-get来安装,结果就出现了这篇博客的问题,因为这几个库十分底层,是很多上层软件的依赖,使用apt-get安装的时候把很多软件给移除掉了,最要命的是移除掉了kernel-package、build-essential、gcc等包,特别是其中的build-essential包,这个包在编译软件的过程中非常重要。

 

下面是解决方案,首先将/var/log/apt/history.log这个日志文件复制一份到其它地方,这个文件记录了我们使用apt-get的记录,包括了install了哪些包,在这个过程中remove掉了哪些包等信息,接下来根据这个文件上记录的最近移除的包再使用apt-get安装回来,如果电脑连接到了公网上,那这个问题这样就已经解决了,直接使用apt-get工具先安装build-essential,再安装kernel-package就好,但是实际上的问题是,这台计算机没有连接到公网上,无法使用apt-get工具联网下载软件包。

 

解决方案

流程:在另外一个主机上(最好是与待修复的主机使用同一版本的系统,在虚拟上操作可能会更方便,如果能够重现一下问题,然后在这台能联网的主机上使用apt-get install下载安装全部需要的软件包是最方便的了)下载全部需要的软件包→配置本地apt源目录→打压缩包→上传到出现问题的主机→解压缩并配置本地apt源→使用apt-get install安装缺少的东西

详述:

在另一个工作正常且能连接公网的主机上下载全部需要的软件包

首先将这台电脑上以前下载的deb包删除(注意:只是删除安装包),这是为了方便找到之后新下载的软件包,使用

sudo apt-get clean

执行后可以看到在/var/cache/apt/archives下已经没有了任何deb包,只有lock文件以及partial目录。

接着就可以下载软件包了,

我使用的是:

sudo apt-get -d install <package_name> --reinstall

这个命令,

-d表示仅下载不安装,--reinstall表示重新安装, <package_name>填写软件包名。 从history.log中找到的被remove的包的信息大致如下:

libmpc3:amd64 (1.0.3-1), libopenblas-dev:amd64 (0.2.18-1ubuntu1), g++-4.9:amd64 (4.9.3-13ubuntu2), cpp-5:amd64 (5.4.0-6ubuntu1~16.04.10), libatlas-base-dev:amd64(3.10.2-9), cpp:amd64 (4:5.3.1-1ubuntu1), gcc-4.9:amd64 (4.9.3-13ubuntu2), g++:amd64(4:5.3.1-1ubuntu1), gfortran:amd64 (4:5.3.1-1ubuntu1), ubuntu-desktop:amd64 (1.361.1), gcc:amd64 (4:5.3.1-1ubuntu1), liblapack-dev:amd64 (3.6.0-2ubuntu2), dkms:amd64 (2.2.0.3-2ubuntu11.5), nvidia-prime:amd64 (0.8.2), build-essential:amd64 (12.1ubuntu2), x11-session-utils:amd64 (7.7+2), kernel-package:amd64 (13.018)

这里省去了一些, 可以看到包名就是冒号前面的部分,如果要指定版本就在填写报名时直接加上=版本号, 如

g++-5=5.4.0-6ubuntu1~16.04.10

注意: 这里的版本号一定要根据自己主机上的来, 特别是gcc、gcc-base、cpp这些包, 对于版本要求特别严格, 版本一定要完全匹配, 不然在安装时可能会提示类似于:Depend: xxxxx (= a.a.a.a) but xxxxx b.b.b.b is to be installed之类的提示,这个就是说,主机上安装过依赖的软件包, 但是版本不匹配, 现在apt-get找到包依赖的是a.a.a.a版本的xxxxx, 但是电脑上安装着b.b.b.b版本的xxxxx, 这就需要在apt-get install <package>时用=指定版本信息了。

因为安装的软件包很多, 最好写一个shell脚本或者C程序来自动处理, 我比较习惯C就写了一个C程序, 思路就是从上面的软件包列表里读入字符串, 可以发现, 每一个软件包的包名都是以':'结束的,于是读入的时候用scanf使用正则表达式%[^:]表示读到:停止, 接着将读入的字符串与命令字符串(前缀是"sudo apt-get -d install ",后缀是" --reinstall")拼接一下, 再作为stdlib.h中的system(char *)函数的参数传递, 这个函数是用来执行系统指令的,最后处理掉这个软件包名字符串多余的部分,也就是上面的":amd64 (x.x.x-x),",使用正则表达式%[^,]就可以将输入停在逗号处, 之后用%[^a-zA-Z]来读处理掉逗号和空格(根据情况来,我这里用a-zA-Z判断是因为我缺少的软件包名全是以字母开头的)。

这样deb包就下载好了, 在/var/cache/apt/archives/可以找到新增的.deb包, 拷贝到一个目录下, 我就放到了/var/debs下, 修改debs目录权限,之后用dpkg-scanpackages命令生成索引文件Package.gz。 【搭建本地apt源的方法参考了别人的博客:https://blog.csdn.net/candcplusplus/article/details/52156324,在此感谢博主分享】

sudo mkdir /var/debs
sudo cp /var/cache/apt/archives/*.deb /var/debs
cd /var
sudo chmod -R 777 debs
sudo dpkg-scanpackages debs /dev/null | gzip > /debs/Packages.gz

之后打包(此时在/var目录下,因为debs目录我放在了/var下)

sudo tar -cvzf debs.tar.gz debs

把这个压缩包想办法放到待修复的主机上(U盘拷贝、搭局域网后传等等), 我还是解压到/var下

sudo tar -xvzf debs.tar.gz -C /var

接着修改/etc/apt/sources.list, 这是apt源列表, 修改前最好先备份, 我把备份文件命名为sources.list.bak,

cd /etc/apt
sudo cp sources.list sources.list.bak
sudo vim sources.list

在sources.list中把非本地源都用#注释掉, 加入一行

deb file:/var debs/

如果这个/etc/apt目录下还有目录sources.list.d,则这个目录里的文件也会作为apt源的描述文件,建议先把这个目录下的文件备份后删除或重新建一个空目录,如下

cd /etc/apt
sudo mv sources.list.d sources.list.d.bak
sudo mkdir sources.list.d

更新apt-get的源列表

sudo apt-get update

接着就是安装了,需要什么apt-get install安装什么就行,先重新安装好build-essential包和kernel-package包,其它包安装就简单了,可能会提示需要安装它们依赖的gcc等包,依赖什么就安装什么就可以,有本地源缺少的包可以去另外下载后再做一个源像上面一样下载, deb包除了像上面apt-get里下载,还可以从https://packages.ubuntu.com/xenial/cpp-5这边找。

特别注意: 尤其是安装gcc这类的包时, 注意版本, 有可能在本地apt源里配置的包与现在主机上的包不一致, 在安装的过程中, 留意提示信息, 如果提示要removed掉很多现有的包, 就不要执行了, 多半是因为本地源和已安装的包版本不一致, 去下载一个对应版本的包再配一个apt源,apt-get install的时候指定版本就好了。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!