I’m packaging the prebuild libtensorflow for OS X.
For the Linux build I’m using patchelf to set the correct rpath in the .so. This however fails on OS X with “not an ELF executable” because the .so is a Mach-O 64-bit x86_64 dynamically linked shared library.
Unfortunately when I build a package that depends on libtensorflow like haskell.packages.ghc822.tensorflow I get a run-time failure when running the test-suite (which doesn’t happen when I build on Linux):
$ nix-build -A haskell.packages.ghc822.tensorflow
these derivations will be built:
/nix/store/m7f1bapd3cm3q62f8wpxbp5lm09rkr7i-tensorflow-0.1.0.2.drv
building '/nix/store/m7f1bapd3cm3q62f8wpxbp5lm09rkr7i-tensorflow-0.1.0.2.drv'...
...
Test suite FFITest: RUNNING...
dyld: Library not loaded: @rpath/libtensorflow.so
Referenced from: /private/tmp/nix-build-tensorflow-0.1.0.2.drv-0/source/tensorflow/dist/build/FFITest/FFITest
Reason: image not found
Test suite FFITest: FAIL
Here’s some information about the current rpath of libtensorflow.so:
$ otool -l $(nix-build -A libtensorflow)/lib/libtensorflow.so
...
Load command 3
cmd LC_ID_DYLIB
cmdsize 48
name @rpath/libtensorflow.so (offset 24)
time stamp 1 Thu Jan 1 01:00:01 1970
current version 0.0.0
compatibility version 0.0.0
Load command 4
cmd LC_DYLD_INFO_ONLY
cmdsize 48
rebase_off 53649408
rebase_size 87208
bind_off 53736616
bind_size 40184
weak_bind_off 53776800
weak_bind_size 2480
lazy_bind_off 53779280
lazy_bind_size 103744
export_off 53883024
export_size 4488
Load command 5
cmd LC_SYMTAB
cmdsize 24
symoff 54053288
nsyms 241471
stroff 57965408
strsize 67297248
Load command 6
cmd LC_DYSYMTAB
cmdsize 80
ilocalsym 0
nlocalsym 239430
iextdefsym 239430
nextdefsym 217
iundefsym 239647
nundefsym 1824
tocoff 0
ntoc 0
modtaboff 0
nmodtab 0
extrefsymoff 0
nextrefsyms 0
indirectsymoff 57916824
nindirectsyms 12146
extreloff 0
nextrel 0
locreloff 0
nlocrel 0
Load command 7
cmd LC_UUID
cmdsize 24
uuid 45142FF3-C3B9-3409-AC92-9D4E1F4F9ED7
Load command 8
cmd LC_VERSION_MIN_MACOSX
cmdsize 16
version 10.12
sdk 10.12
Load command 9
cmd LC_SOURCE_VERSION
cmdsize 16
version 0.0
Load command 10
cmd LC_LOAD_DYLIB
cmdsize 64
name @rpath/libtensorflow_framework.so (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 0.0.0
compatibility version 0.0.0
Load command 11
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libSystem.B.dylib (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 1238.50.2
compatibility version 1.0.0
Load command 12
cmd LC_LOAD_DYLIB
cmdsize 104
name /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 1349.64.0
compatibility version 150.0.0
Load command 13
cmd LC_LOAD_DYLIB
cmdsize 96
name /System/Library/Frameworks/Security.framework/Versions/A/Security (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 57740.51.2
compatibility version 1.0.0
Load command 14
cmd LC_LOAD_DYLIB
cmdsize 88
name /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 275.0.0
compatibility version 1.0.0
Load command 15
cmd LC_LOAD_DYLIB
cmdsize 48
name /usr/lib/libc++.1.dylib (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 307.5.0
compatibility version 1.0.0
Load command 16
cmd LC_LOAD_DYLIB
cmdsize 96
name /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 1349.63.0
compatibility version 300.0.0
Load command 17
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libobjc.A.dylib (offset 24)
time stamp 2 Thu Jan 1 01:00:02 1970
current version 228.0.0
compatibility version 1.0.0
Load command 18
cmd LC_RPATH
cmdsize 32
path @loader_path/ (offset 12)
Load command 19
cmd LC_FUNCTION_STARTS
cmdsize 16
dataoff 53887512
datasize 156136
Load command 20
cmd LC_DATA_IN_CODE
cmdsize 16
dataoff 54043648
datasize 9640
Load command 21
cmd LC_RPATH
cmdsize 216
path /nix/store/yxl7yn6bx55j9wq58y88lvm126nkbadm-Libsystem-osx-10.11.6/lib:/nix/store/gypar7abrwdd13pmdal3wq0rcsgymrj2-clang-5.0.2-lib/lib:/nix/store/8yz1ml3h01rn4qni8nlxifaiq3acd0va-libtensorflow-1.8.0/lib (offset 12)
The non-nix-store paths like /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation look a bit suspicious. Is that normal or should those be replaced by nix-store paths?
I’m clearly not well versed in Nix development on OS X. Anybody who can point me in the right direction?
I do see that on OS X the Haskell builder is adding an RPATH to executables. However, this only happens when enableSharedExecutables is enabled (it defaults to false) and it only applies to installed executables, so not to executables for the test-suite.
@mpickering I don’t understand your suggestion about changing the install name of lib/libtensorflow.so. What should I change it into and why would that help?
We generally don’t use RPATH on darwin, adding $out/lib is disabled in the stdenv because we don’t use it. Dynamic libraries shouldn’t use @rpath since like you noticed this won’t work for packages that link against it unless rpath is configured manually there. CoreFoundation is a special case because we have both a pure and impure version, the RPATH entry enables us to switch to the impure version if necessary without having to rebuild the entire tree.
The way libraries get linked on darwin is using the install_name, see otool -D foo.dylib. The install_name is generally the absolute path to the final install location so in this case $out/lib/libtensorflow.so. This can be patched similar to library references using install_name_tool or our by including our fixDarwinDylibNames setup hook.
Note that if this is used during the check phase the library probably won’t be in place yet, some build systems use @rpath intermediately during the build and patch it before installing, but using the installCheckPhase instead should allow you to avoid that.