staticfloat
staticfloat

Reputation: 7050

Linking to libraries with $ld$hide$os10.X$ symbols in OSX

I'm trying to link against the BLAS implementation in OSX (/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib, for the curious) but I don't want to link against the libLAPACK.dylib in that same directory, as I want to use my own build of LAPACK from netlib, as it is much more recent and up to date.

My problem is that there are symbols in the BLAS library that are typically stored in an LAPACK library, and as such are causing name clashes. As a concrete example, the spotrf function is defined in 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

Those first two symbols made me a little suspicious, so to double-check, I check out libLAPACK.dylib as well:

$ 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

From what limited information I have been able to find, it seems that this prefix somehow instructs the dynamic linker to ignore these symbols if the users is compiling against a given OSX version. This makes sense if Apple moved symbols from libBLAS.dylib to libLAPACK.dylib between 10.6 and 10.7.

My question is, how can I inform the dynamic linker that it SHOULD hide spotrf etc... that are inside libBLAS.dylib?

Upvotes: 4

Views: 493

Answers (1)

Stephen Canon
Stephen Canon

Reputation: 106267

First off, you don’t actually need to do anything special to get your desired behavior, as you’re linking dynamically. Ensure that your netlib-built LAPACK appears before -lblas in the link command, and all LAPACK interfaces will be picked up from the netlib LAPACK (ld matches all the undefined symbols it can against each of the libraries being linked against in order).

Alternatively, assuming that your netlib LAPACK is linked against the system BLAS, you should be able to configure the link of LAPACK so that it reexports all of the BLAS symbols. Then you can simply link against your LAPACK and leave -lblas out of your link command entirely.


The $show$ and $hide$ symbols come into play if and only if you are linking against both the system BLAS and the system LAPACK libs. A simple example will show how they work in that case:

Kronecker:~ scanon$ cat foo.c
void dgetrf_(void);
int main(void) { dgetrf_(); return 0; }

Building this on 10.9 and breaking on dgetrf_, we see that the symbol was picked up from libLAPACK.dylib, even though -lblas appears first in the build command. This is because the symbol is hidden in libBLAS.dylib when targeting 10.9:

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:
...

If we specify -mmacosx-version-min=10.6 (telling the compiler and linker that we want to produce an executable that can run on 10.6 Snow Leopard), we will see that the symbol is picked up from libBLAS.dylib instead. This is because the symbol doesn’t exist in libLAPACK.dylib on 10.6, so our executable wouldn’t be able to run on that platform if the symbol in libLAPACK.dylib were used:

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_:
...

Upvotes: 3

Related Questions