Archlinux 上 Arpack.jl 构建失败的解决方案

问题背景

我在20年的时候转到了 archlinux。比较方便的一点是可以从软件源直接安装 Julia.
但是官方源的 Julia 有一个问题,就是所有涉及到 Arpack.jl 的包都会编译失败。

RROR: LoadError: InitError: could not load library "~/.julia/artifacts/cdf6dc8aa6771a61c6c65a5a5c1a8d1b75f50a2f/lib/libarpack.so"
libopenblas64_.so: cannot open shared object file: No such file or directory

主要表现就是 libopenblas64_.so 找不到。

问题分析

一种解决方案是将这个库复制到对应的文件夹下面,但是这种方法太麻烦了,每次都要复制一次。

实际上这个库在 /usr/lib/julia 下面,并且 arch 官方对 Julia 打了 patch, 将 /usr/lib/julia 加入了 RPATH,因此 Julia 本身是找得到那个库的。

➜  ~ ls -al /usr/lib/julia/libopenblas64_.so 
lrwxrwxrwx 1 root root 23  5月 9日 19:44 /usr/lib/julia/libopenblas64_.so -> /usr/lib/libopenblas.so

➜  ~ patchelf --print-rpath /usr/bin/julia 
$ORIGIN/../lib:$ORIGIN/../lib/julia

这里 $ORIGINjulia 可执行文件所在的位置,在我的电脑上就是 /usr/bin

问题出在 JLLWrapers.jl ,这个包在 linux 上只认 LD_LIBRARY_PATH 变量,另一个能够用来指定库的搜索路径的变量被设置为了空值。( LIBPATH_default = "")。
相关代码

因此,在没有将 /usr/lib/julia加入到 LD_LIBRARY_PATH 的时候,它不会该路径下找库。就会出现找不到的情况。

我个人觉得应该修改 JLLWrappers.jl,在它的默认搜索路径加入 julia 的 RPATH。但是我还没找到在 Julia 里面要如何获取 RPATH。之前没有正确理解 JLLWrappers.jl 的代码就贸然去提交 pr, 结果不出意外被拒了 :joy:

解决方案

现在主要是有三种解决方案

  1. 手动复制库文件(不推荐)
  2. ~/.julia/config/startup.jl 里面添加 ENV["LD_LIBRARY_PATH"]="/usr/lib:/usr/lib/julia" (我目前用的这个)
  3. 使用 julia-lang 发布的二进制包 julia-bin

个人评价

我个人不倾向于使用第三种方案,因为我还是希望尽量复用系统已经安装的库文件。

其实我不太喜欢 Julia 的各种 artifacts, 一个是下载起来慢,二是重复下载了很多库,浪费空间。在我的电脑上 ~/.julia 占用了 1.7G 空间,其中下面的 artifacts/ 就占用了 817MB 空间。


更新

感觉我现在才算是找到原因了。是 arpckRPATH 有问题。

➜  lib ldd libarpack.so
        linux-vdso.so.1 (0x00007ffd528ad000)
        libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f565c4dd000)
        libopenblas64_.so => not found
        libgfortran.so.5 => /usr/lib/libgfortran.so.5 (0x00007f565c202000)
        libm.so.6 => /usr/lib/libm.so.6 (0x00007f565c11b000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f565c0fb000)
        libquadmath.so.0 => /usr/lib/libquadmath.so.0 (0x00007f565c0b2000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007f565bea3000)
        /usr/lib64/ld-linux-x86-64.so.2 (0x00007f565c56c000)
➜  lib patchelf --print-rpath libarpack.so
$ORIGIN

又看了一下,发现arch 官方的 julia 比 julia-lang 下面的命令少了一个 libopenblas64_.so, 这可能是问题所在。

julia> filter(x -> occursin("64_",x), Libdl.dllist())

但是我不懂为啥 julia-bin 就没有问题。不懂 arch 打包的时候到底搞了什么黑魔法。
老老实实用 ENV["LD_LIBRARY_PATH"] 了。