Macos 链接到OSX中带有$ld$hide$os10.X$符号的库
我试图链接OSX中的BLAS实现(Macos 链接到OSX中带有$ld$hide$os10.X$符号的库,macos,linker,Macos,Linker,我试图链接OSX中的BLAS实现(/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib,出于好奇),但我不想链接同一目录中的libLAPACK.dylib,因为我想使用我自己从netlib构建的LAPACK,因为它是最近更新的 我的问题是,BLAS库中有一些符号通常存储在LAPACK库中,因此会导致名称冲突。作为具体示例,spo
/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
,出于好奇),但我不想链接同一目录中的libLAPACK.dylib
,因为我想使用我自己从netlib构建的LAPACK,因为它是最近更新的
我的问题是,BLAS库中有一些符号通常存储在LAPACK库中,因此会导致名称冲突。作为具体示例,spotrf
函数在libBLAS.dylib
中定义:
$ nm /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib | grep spotrf
0000000000010c05 T $ld$hide$os10.7$_spotrf
0000000000010c05 T $ld$hide$os10.8$_spotrf
000000000000746e T _spotrf
前两个符号让我有点怀疑,所以为了再次检查,我还检查了libLAPACK.dylib
:
$ nm /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib | grep spotrf
00000000000010c8 T $ld$hide$os10.4$_spotrf
00000000000010c8 T $ld$hide$os10.5$_spotrf
00000000000010c8 T $ld$hide$os10.6$_spotrf
000000000000765b T _spotrf
据我所知,如果用户是根据给定的OSX版本进行编译,那么这个前缀似乎以某种方式指示动态链接器忽略这些符号。如果苹果将符号从libBLAS.dylib
移动到libLAPACK.dylib
10.6到10.7之间,这是有意义的
我的问题是,如何通知动态链接器它应该隐藏
spotrf
等。。。在libBLAS.dylib
?首先,您实际上不需要做任何特殊的事情来获得所需的行为,因为您正在动态链接。确保您的netlib内置LAPACK在link命令中显示在-lblas之前,并且所有LAPACK接口都将从netlib LAPACK中拾取(ld
将所有未定义的符号按顺序与链接的每个库进行匹配)
或者,假设您的netlib LAPACK链接到系统BLAS,您应该能够配置LAPACK的链接,以便它重新导出所有BLAS符号。然后,您可以简单地针对LAPACK进行链接,并将-lblas完全排除在链接命令之外
当且仅当您针对系统BLAS和系统LAPACK LIB进行链接时,
$show$
和$hide$
符号才起作用。一个简单的示例将显示它们在这种情况下的工作方式:
Kronecker:~ scanon$ cat foo.c
void dgetrf_(void);
int main(void) { dgetrf_(); return 0; }
在10.9上构建此代码,并在dgetrf\uuu
上中断,我们看到该符号是从libLAPACK.dylib
中拾取的,即使-lblas
首先出现在build命令中。这是因为当目标为10.9时,符号隐藏在libBLAS.dylib
中:
Kronecker:~ scanon$ clang foo.c -lblas -llapack
Kronecker:~ scanon$ lldb a.out
Current executable set to 'a.out' (x86_64).
(lldb) b dgetrf_
Breakpoint 1: 2 locations.
(lldb) run
...
frame #0: 0x00007fff89237b70 libLAPACK.dylib`dgetrf
libLAPACK.dylib`dgetrf:
...
如果我们指定-mmacosx version min=10.6
(告诉编译器和链接器我们想要生成一个可在10.6 Snow Leopard上运行的可执行文件),我们将看到符号是从libBLAS.dylib
中提取的。这是因为10.6上的libLAPACK.dylib
中不存在符号,因此如果使用libLAPACK.dylib
中的符号,我们的可执行文件将无法在该平台上运行:
Kronecker:~ scanon$ clang foo.c -lblas -llapack -mmacosx-version-min=10.6
Kronecker:~ scanon$ lldb a.out
Current executable set to 'a.out' (x86_64).
(lldb) b dgetrf_
Breakpoint 1: 2 locations.
(lldb) run
...
frame #0: 0x00007fff8c9d6841 libBLAS.dylib`DGETRF_
libBLAS.dylib`DGETRF_:
...
你能详细说明一下你所经历的名称冲突吗?OSX使用两级名称空间应该允许具有相同名称的符号出现在运行时加载的不同库中。静态链接器将在构建时记录它在哪个动态库中找到给定符号,动态加载程序将在运行时使用该信息在适当的库中加载和解析它。这是的一部分,我们有一个JIT编译器,它使用LLVM作为后端。LLVM有一些,我们在添加符号之前检查符号表中是否已经存在符号,并向用户打印一条警告,因为这不是我们真正希望发生的事情。冲突发生在为Julia编译的外部第三方共享库(
liblapack.dylib
)和外部OSX提供的共享库(libBLAS.dylib
)之间。我希望动态链接器忽略libBLAS.dylib
中的这些冲突符号,我很确定它们只应该出现在OSX 10.6和更早版本中。我输入了编译器而不是上面的动态链接器,我会马上修复它。对于那些尝试使用gcc
并注意到它仍然不起作用的人,请确保将macosx version
标志传递给gcc
的编译器和链接器部分:-mmacox version min=10.6-Wl,-macosx\u version\u min,10.6
。回答得很好,谢谢!