有一些工程或者项目,它们编译或者运行需要依赖的命令和库的版本可能高于现有系统自带的版本,这时候就需要用root用户安装或者升级。但是出于安全方面的考虑,一般我们登录服务器都是以普通用户的权限登录的,切换root用户则是不被许可或者需要严格审批的。所以就需要满足这样一种场景:在普通用户的权限下安装或使用高版本的依赖。
这种情况仔细想想其实比较普遍:
- 以root用户登录需要比较复杂繁琐的流程,尤其是生产服务器
- 能够以root用户登录,但升级一些库或工具可能造成兼容问题,服务器上的其它应用会受到影响
GCC就是这样一种同时受这两种条件限制的依赖包。首先生产环境服务器升级自带的gcc可能需要经过非常严格的审批,甚至不如新增一台带高版本gcc机器来的方便;其次升级后系统不稳定性立马上升,根本不可能知道什么情况下会出现什么问题。总之,我们需要在普通用户的权限下就能够使用高版本gcc。注意,这种方式并不是从源码安装。源码安装根据环境,操作起来有麻烦的也有简单的,因为当前的系统非常古老,缺失的依赖可能非常多,另外源码安装需要的参数可能非常多,需要对这些命令和参数非常熟悉,才有可能达到预期效果。
当前一个项目刚好遇到了这种情况:因为有cpp的代码,所以需要本地编译,但是机器的gcc版本是4.8,而升级是肯定不可能的。这个情况可以说让人非常难受,折腾了一番总算成功了,目前满足了我们验证一些功能的目的,其它情况需要自己斟酌。
受这篇帖子的启发,我们只需要将依赖包解压到指定目录下,再配置正确的环境变量就可以高版本gcc了,不过帖子的结尾作者也说明了,像gcc这种工具最好还是用conda工具。不过因为我们配置conda的环境同样比较麻烦,所以先用这种方式试一试。
1. 准备依赖包
因为一些原因,我们使用的是一个切换gcc的工具devtoolset-9
,这是一个在centOS上才可用的工具,这是与其它系统不同的地方,其它Linux系统的安装并没有试过。但我们希望安装的是gcc-c++-9.5
,也就是最终希望能使用g++-9.5
命令,但这个安装包还有其它的依赖包,通过yum deplist
命令可以罗列安装包的所有其它依赖,但需要root权限,这篇贴子介绍了一些无需root用户来查看依赖的方法,不过依赖包的依赖包没法列出。依赖包很多,有binutils-2
, libstdc++-devel-9.3
等等。
2. 解压依赖包
依赖包下载目录是./rpm
, 准备安装在./work
目录下
cd work && for r in $(ls ../rpm/*.rpm); do rpm2cpio $r | cpio -id; done && cd -
3. 配置环境变量
其实最重要的是这一步,主要配置2个环境变量。首先是配置命令,这一步好理解,平常用到的比较多,主要是配置PATH
环境变量:
export PATH=$PWD/work/usr/bin:$PWD/work/opt/rh/devtoolset-9/root/usr/bin:$PATH
我们需要把高版本gcc的搜索目录放置在系统搜索目录之前,这样引用命令的时候首先去我们的目录下去寻找。
其次配置LD_LIBRARY_PATH
:
L='/lib:/lib64:/usr/lib:/usr/lib64'
export LD_LIBRARY_PATH="$PWD/work/opt/rh/devtoolset-9/root/usr/lib:$PWD/work/usr/lib64:$PWD/work/opt/rh/devtoolset-9/root/usr/lib64:$L"
LD_LIBRARY_PATH
的作用是查找共享库,也就是各种.so文件,显然也需要放置在系统共享库目录之前,系统共享库目录就是那个L
环境变量。
这样就能引用gcc
了,本地验证编译并且运行竟然一点问题没有,异常简单!不过这种方式让人隐隐有不安全感。系统的低版本gcc实际始终存在,一旦在某一应用中环境变量没有引用正确,可能会引发不可预料的问题。
另一种方案
如果只是为了验证一些功能,其实也没必要非安装gcc不可。我们可以用高版本gcc预编译需要的可执行文件或者共享.so文件,直接带入低版本服务器中即可。但这种方式也有一定门槛:
- 迁移机器的指令集必须一致,别把windows的可执行文件放在Linux上,别把x86的lib文件传到arm64上。
- 需要对待验证的功能非常了解。是需要二进制可执行文件还是一个lib库文件?用来验证的基本用法是什么,如何与既有系统对接?
- 确保依赖完整。待验证的文件的依赖文件,是否在低版本机器中都存在,如果不存在如何能生成高版本依赖并在低版本机器环境下正确引用,这需要了解不少系统知识。
- 确保系统调用函数在兼容低版本系统。针对项目代码的细节了解,避免有一些方法在低版本系统中失效或调用失败。
- 确保验证的应用能正确通过环境变量运行命令、加载类库
虽然看似是一些浅显明白、一目了然的要求,但一和具体的部署环境结合起来问题无穷无尽,docker不就是在这种情况下催生的么~