问题遭遇

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

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

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

r
1> install.package("RProtoBuf")

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

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

r
1> BiocManager::install()

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

问题解决

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

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

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

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

最终,问题得以解决。