起因

服务器当然是学CS必然会接触的事物之一了,如何配置一个舒适安心的环境让我们去应对各种不同环境配置的实验复现同样也是令人头痛的问题之一。在PKU的未名一号、一些超算集群以及个人课题组的服务器上,我都有一系列账号,但是带来的问题必然是服务器资源并不属于你一个人,所以你不能在上面为所欲为,虽然可以通过module add加载大部分通用软件,但如果版本不对应或者不存在对应软件,就得自己去安装。

安装程序or软件

通常想要安装某版本的软件(如GCC-7,Cuda-10,LLVM-9.0等),linux用户都会搜到用apt get install/yum install直接安装,多么省力省事的命令啊,但现实是服务器并不是个人pc,我们没有sudo权限,大部分软件默认安装路径是/usr/bin或/usr/local/bin,安装时需要将可执行文件复制到这些目录下,而普通用户没有目录的写权限,于是提示无权限导致安装失败,所以非root用户只能安装软件到home目录下。上篇说道Redhat版本的rpm包就相当于windows中的安装文件,它会自动处理软件包之间的依赖关系,但是rpm一般都是预先编译好的文件,它可能已经绑定到某种CPU或者发行版上面了。所以没有sudo权限的我们是不能通过这种方式来安装软件的,就算是管理员也不能擅自用这种方式安装,因为公共的环境变量不允许我们这样做(具体不展开,有兴趣可以搜索Linux动态库的运行时查找顺序)。所以我们只得采用另一种方式,利用下载好的软件的开源代码压缩包即压缩文件格式,在本地环境下进行编译安装,然后进行安装三部曲,./configure, make, make install 进行安装。 下面介绍Linux下非root用户安装软件的一般流程(并且以gcc安装为例):

  1. 获取源代码:通常做法是复制源码链接,然后利用wget命令接从url下载,ubuntu可以用apt-get source来获取仓库中软件源代码;搜索源码链接的方式一般为github网址后接/releases或从软件官方网站的download界面寻找。

    ` wget https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz `

  2. 解压源代码安装包,源代码程序包多为gzip过的tar包,一般使用tar -zxvf xxx.tar.gz即可(其实-xf即可);

    tar -xf gcc-10.2.0.tar.gz

  3. 切换到解压后的目录,运行 ./configure。./configure –help可以列出配置项,非root用户最重要的配置项是安装目录prefix,例如 ./configure –prefix=/path/to/bin,这里的prefix必须设置在个人home目录下。其实大部分软件在这一步需要解决的问题就是依赖问题,如gcc其实提供了一键命令下载依赖,而在无法自动找到依赖库位置的情况下,通常用 –with-xx-dir=xxx 的形式配置依赖库位置。

     cd gcc-10.2.0
     ./contrib/download_prerequisites #安装依赖
     ../configure --disable-checking --enable-languages=c,c++,fortran --disable-multilib --prefix=/home/path/to/software/gcc9 --enable-threads=posix#gcc可编译语言很多,可以选择all,但会耗时更久
    
  4. 另一种情况:有些时候源码里并没有configure文件,那如何生存makefile文件呢,就需要借助cmake。此时的操作流程一般为创建build文件夹,指定编译过程中使用的gcc和g++,通过-DCMAKE_INSTALL_PREFIX=指示安装路径。以LLVM官方命令为例:

     mkdir build
     cd build
     CC=$HOME/toolchains/bin/gcc CXX=$HOME/toolchains/bin/g++ cmake .. -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$HOME/toolchains/lib64 -L$HOME/toolchains/lib64" -DCMAKE_INSTALL_PREFIX=/home/path/to/software/LLVM/
    
  5. 拥有makefile后,就可以编译源代码并复制可执行文件到指定的安装目录: make && make install。这两条命令最好分开执行(因为不确定会不会报错),make时指定 -j 参数并行编译,能显著减少编译耗时(单进程编译GCC需要几个小时,开启并行编译后可缩短到十几分钟)

     make -j
     make install#安装的路径就是前面指定的perfix
    
  6. 修改环境变量:更新PATH变量,命令行窗口运行此命令只对本次会话中有效,可将其写到.bashrc或者.bash_profile中;而如果安装的是动态链接库,则需要更新动态链接库路径即LD_LIBRARY_PATH。所以我建议不太熟悉的用户直接打开bashrc,对照安装目录下的文件夹名称把能修改的变量都修改了,一般有如下四个:

     vi ~/.bashrc
     #添加以下命令
     export PATH=$HOME/path/to/software/gcc/bin:$PATH
     export CPATH=$HOME/path/to/software/gcc/include:$CPATH
     export LD_LIBRARY_PATH=$HOME/path/to/software/gcc/lib:$LD_LIBRARY_PATH
     export LIBRARY_PATH=path/to/software/gcc/lib:$LIBRARY_PATH
     #esc后:wq保存
     source ~/.bashrc #使环境变量生效
    
  7. 程序测试:可以查看软件对应版本或者直接使用来检查

     gcc --version
     which gcc
     gcc -o main main.cpp
    

问题

在安装过程肯定会因为服务器的种种原因,在configure或者编译的过程中因为某些问题如缺少依赖或系统缺少某个版本动态库导致出错,只有配合错误信息进行google或者联系服务器管理员才能一步一步解决。非root用户编译安装软件确实是一件比较痛苦的事情,但是我相信这对于熟悉Linux确实是一个很好的途径。

有一个很想吐槽的点就是不同软件的适配问题,最出名的莫过于GCC和CUDA的版本适配了,辛辛苦苦下载的gcc9和cuda10.1并不能兼容。以下是英伟达的cuda工具链对于gcc版本支持的对应情况:

另外还有包括如何利用python源程序中的setup.py来安装第三方包packages以及如何创建python虚拟环境解决多版本软件环境问题等等,网上都有一系列教程,还是得多动手尝试才能解决问题。