颜林林的个人网站

Linlin Yan's Personal Website

解决Linux系统升级后R包加载失败的问题

2020-01-02 20:30
#r #linux #ldd

问题遭遇

今天升级了Linux系统的一堆底层运行时库,结果发现R包RProtoBuf加载失败了,报出如下错误:

1
2
3
4
> library(RProtoBuf)
Error: package or namespace load failed forRProtoBufin dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/home/yanll/R/x86_64-pc-linux-gnu-library/3.6/RProtoBuf/libs/RProtoBuf.so':
   libprotobuf.so.19: cannot open shared object file: No such file or directory

过去遇到这种问题时,我通常的解决方法,就是重新安装相应的R包,就可解决问题:

1
> install.package("RProtoBuf")

不过,有时候涉及很多包都受到影响,就需要逐个重新编译。但因为不知道到底有多少包需要重新安装,于是整个过程可能就需要手工进行多次尝试才能完全解决。

这个问题,并不能通过如下方式解决:

1
> BiocManager::install()

因为该命令只能根据R包之间的版本关系来进行更新,而并不能检查到“unable to load shared object”的错误。

问题解决

为此,我尝试了如下的bash命令,用来列举到底有哪些动态库(*.so文件)出现了依赖问题,预期通过重新安装它们所属的R包即可:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ Rscript -e 'cat(.libPaths(), sep = "\n")' \
    | while read d; do \
        ( \
            cd $d; \
            find -type f -name '*.so' -executable \
                | while read f; do \
                if [ "$(ldd $f | grep "not found" | wc -l)" -gt 0 ]; then \
                    echo "$d/$f"; \
                fi; \
            done \
        ) \
    done

如下命令,则将这些输出.so文件所属包名(上级目录名)取出,用awk构造了R语言的安装命令,提交给Rscript进行安装:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ Rscript -e 'cat(.libPaths(), sep = "\n")' \
    | while read d; do \
        ( \
            cd $d; \
            find -type f -name '*.so' -executable \
                | while read f; do \
                if [ "$(ldd $f | grep "not found" | wc -l)" -gt 0 ]; then \
                    echo $f; \
                fi; \
            done \
        ) \
    done \
    | cut -d/ -f2 \
    | awk '{print"install.packages(\""$0"\")"}' \
    | Rscript /dev/stdin

最终,问题得以解决。