bindgen/MacOS/Nix: dyld tries to use temporary build location in bindgen-generated wrapper

TLDR

I'm using bindgen to wrap a library written in C(++) and installed with Nix. This works on Linux, but my CI bulids fail on MacOS, with the error

dyld: Library not loaded: /private/tmp/nix-build-the-c-library.drv-0/the-c-source/libTheCLibrary.so
  Referenced from: /Users/runner/work/dyld_problem/dyld_problem/target/debug/deps/the_wrapper_crate-8b6d261d3c7fa2c7
  Reason: image not found
error: test failed, to rerun pass '-p the_wrapper_crate --lib'

The directory /private/tmp/nix-build-the-c-library.drv-0/ seems to be a temporary workspace used during the build, and has gone by the time dydl tries to load its contents at run-time.

(I don not have local access to a machine with MacOS.)

Details and minimal reproducible example

I have tried to whittle it down to a minimal reproducible example:

Extracting the signal from the noise in the failing run, we can see that, at compile time, the library is written to /private/tmp/nix-build-the-c-library.drv-0/the-c-source/libTheCLibrary.so

direct link to:

-----WORKDIR-----> /private/tmp/nix-build-the-c-library.drv-0/the-c-source
233
ls /private/tmp/nix-build-the-c-library.drv-0/the-c-source:
234
makefile  the_C_source_file.cc
235
/nix/store/vfjv3qfnglnb461af2hbzhx8f16kigcx-clang-wrapper-9.0.1/bin/clang++ -fpic -c -O2 -pg /private/tmp/nix-build-the-c-library.drv-0/the-c-source/the_C_source_file.cc  -o /private/tmp/nix-build-the-c-library.drv-0/the-c-source/the_object_file.o
236
/nix/store/vfjv3qfnglnb461af2hbzhx8f16kigcx-clang-wrapper-9.0.1/bin/clang++ -shared -o       /private/tmp/nix-build-the-c-library.drv-0/the-c-source/libTheCLibrary.so        /private/tmp/nix-build-the-c-library.drv-0/the-c-source/the_object_file.o
237
installing
238
-----WORKDIR-----> /private/tmp/nix-build-the-c-library.drv-0/the-c-source
239
ls /private/tmp/nix-build-the-c-library.drv-0/the-c-source:
240
libTheCLibrary.so  makefile  the_C_source_file.cc  the_object_file.o

... and then dydl tries to load this library at run-time, by which time it is no longer there

direct link to:

   Compiling the_wrapper_crate v0.1.0 (/Users/runner/work/dyld_problem/dyld_problem/the_wrapper_crate)
516
    Finished test [unoptimized + debuginfo] target(s) in 1m 03s
517
     Running target/debug/deps/the_wrapper_crate-8b6d261d3c7fa2c7
518
dyld: Library not loaded: /private/tmp/nix-build-the-c-library.drv-0/the-c-source/libTheCLibrary.so
519
  Referenced from: /Users/runner/work/dyld_problem/dyld_problem/target/debug/deps/the_wrapper_crate-8b6d261d3c7fa2c7
520
  Reason: image not found
521
error: test failed, to rerun pass '-p the_wrapper_crate --lib'
522

523
Caused by:
524
  process didn't exit successfully: `/Users/runner/work/dyld_problem/dyld_problem/target/debug/deps/the_wrapper_crate-8b6d261d3c7fa2c7` (signal: 6, SIGABRT: process abort signal)
525
Error: Process completed with exit code 101.

What needs to be done to eliminate this problem?

It seems that rust doesn't have a dependency on the-c-library-being-wrapped. Maybe adding it will fix the problem?

You mean in shell.nix?

Not sure how you would do that.

Yes. I haven't ever used Nix myself so I don't know how to do that either.

  1. Dynamic libraries on MacOS contain information about their location, known as the install_name.
  2. Nix typically, and in this case too, builds in a temporary directory during the buildPhase and moves those products to their final destination during the installPhase. This results in the install_name not matching the library's real location.
  3. One solution to the problem is to ensure that the library's internal install_name matches its final location, using install_name_tool thus
    install_name_tool -id <final location of the lib file> <the lib file>