为什么我的方法不起作用
首先,UNIX上的共享库旨在模仿存档库的工作方式(首先存在存档库)。特别是这意味着,如果您同时具有
libfoo.so和和
libbar.so,这两个定义符号
foo,则首先加载哪个库才是获胜的:所有对
foo程序中任何位置(包括from
libbar.so)的引用都将绑定到的
libfoo.sos定义
foo。
这模仿了如果您将程序与
libfoo.a和链接时会发生的情况
libbar.a,并且两个存档库都定义了相同的符号
foo。有关存档链接的更多信息,请参见此处。
它应该是从上面清楚的是,如果
libblas.so.3和
libopenblas.so.0定义相同的符号集(他们 这样做
),如果
libblas.so.3被加载到进程,然后再从程序
libopenblas.so.0将 永远不会 被调用。
其次,您已经正确地决定了,由于
R直接链接到
libR.so,并且由于
libR.so直接链接到
libblas.so.3,因此可以确保
libopenblas.so.0赢得这场战斗。
但是,您 错误地 决定
Rscript比较好,但它不是:
Rscript是一个 很小的
二进制文件(我的系统上11K;比较2.4MB的
libR.so),它也几乎全部是
exec的
R。在
strace输出中看到这很简单:
strace -e trace=execve /usr/bin/Rscript --default-packages=base --vanilla /dev/nullexecve("/usr/bin/Rscript", ["/usr/bin/Rscript", "--default-packages=base", "--vanilla", "/dev/null"], []) = 0execve("/usr/lib/R/bin/R", ["/usr/lib/R/bin/R", "--slave", "--no-restore", "--vanilla", "--file=/dev/null", "--args"], []) = 0--- SIGCHLD {si_signo=SIGCHLD, si_pre=CLD_EXITED, si_pid=89625, si_status=0, si_utime=0, si_stime=0} ------ SIGCHLD {si_signo=SIGCHLD, si_pre=CLD_EXITED, si_pid=89626, si_status=0, si_utime=0, si_stime=0} ---execve("/usr/lib/R/bin/exec/R", ["/usr/lib/R/bin/exec/R", "--slave", "--no-restore", "--vanilla", "--file=/dev/null", "--args"], []) = 0--- SIGCHLD {si_signo=SIGCHLD, si_pre=CLD_EXITED, si_pid=89630, si_status=0, si_utime=0, si_stime=0} ---+++ exited with 0 +++这意味着在你的脚本开始执行的时候,
libblas.so.3已经被加载,
libopenblas.so.0将被加载的依赖
mmperf.so不会
真正 被用于任何东西。
是否有可能使其正常工作
大概。我可以想到两种可能的解决方案:
- 假装
libopenblas.so.0
实际上libblas.so.3
R
针对重建整个软件包libopenblas.so
。
对于#1,您需要
ln -s libopenblas.so.0 libblas.so.3,
然后
libblas.so.3通过
LD_LIBRARY_PATH适当设置来确保在系统副本之前找到您的副本。
这似乎为我工作:
mkdir /tmp/libblas# pretend that libc.so.6 is really libblas.so.3cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/libblas/libblas.so.3LD_LIBRARY_PATH=/tmp/libblas /usr/bin/Rscript /dev/nullError in dyn.load(file, DLLpath = DLLpath, ...) : unable to load shared object '/usr/lib/R/library/stats/libs/stats.so': /usr/lib/liblapack.so.3: undefined symbol: cgemv_During startup - Warning message:package ‘stats’ in options("defaultPackages") was not found请注意我是如何得到错误的(我的“假装”
libblas.so.3没有定义期望的符号,因为它实际上是的副本
libc.so.6)。
您还可以通过以下方式确认
libblas.so.3要加载的版本:
LD_DEBUG=libs LD_LIBRARY_PATH=/tmp/libblas /usr/bin/Rscript /dev/null |& grep 'libblas.so.3' 91533: find library=libblas.so.3 [0]; searching 91533: trying file=/usr/lib/R/lib/libblas.so.3 91533: trying file=/usr/lib/x86_64-linux-gnu/libblas.so.3 91533: trying file=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libblas.so.3 91533: trying file=/tmp/libblas/libblas.so.3 91533: calling init: /tmp/libblas/libblas.so.3
对于#2,您说:
我没有要测试的计算机的root访问权限,因此无法实际链接到OpenBLAS。
但这似乎是个虚假的论点:如果可以构建
libopenblas,那么当然也可以构建自己的
R。
更新:
您在一开始提到libblas.so.3和libopenblas.so.0定义了相同的符号,这意味着什么?它们具有不同的SONAME,是否不足以通过系统区分它们?
符号和
SONAME有 没有 做对方。
您可以从输出中看到的符号
readelf -Ws libblas.so.3和
readelf -Wslibopenblas.so.0。与之相关的符号
BLAS,例如
cgemv_,将出现在两个库中。
您
SONAME可能 对Windows
感到困惑。
DLLWindows上的s设计完全不同。特别是,当
FOO.DLL进口象征
bar从
BAR.DLL, 两个 符号(名称
bar)
,并 在
DLL从该符号是进口的(
BAR.DLL)被记录在
FOO.DLL的进口表。
这使得它轻松拥有
R进口
cgemv_从
BLAS.DLL,而
MMPERF.DLL进口的相同符号的
OPENBLAS.DLL。
但是,这使库插入变得困难,并且与存档库的工作方式(甚至在Windows上)完全不同。
对于哪种设计总体上更好,人们意见不一,但是两种系统都不可能改变其模型。
UNIX有多种方法可以模拟Windows样式的符号绑定:请参见
RTLD_DEEPBINDdlopen
手册页。当心:这些问题充满危险,可能使UNIX专家困惑,没有被广泛使用,并且可能存在实现错误。
更新2:
您的意思是我编译R并将其安装在主目录下?
是。
然后,当我要调用它时,应该显式地给出我的可执行程序版本的路径,否则可能会调用系统上的路径?或者,我可以将此路径放在环境变量$
PATH的第一个位置以欺骗系统吗?
无论哪种方式都行。



