How to use install_name_tool on Darwin?

Dynamic libraries on Darwin contain information about their own location. The usual Nix procedure of building in a temporary location, and then moving the build products to $out results in mismatches between the true location of the library and what it has to say about its location, leading to all sorts of fun problems, frequently of the form

dyld: Library not loaded: <somewhere>
Referenced from: <somewhere else>
Reason: image not found

AFAICT, solutions to this include:

  • Using a flag to inform the compiler where the library will end up.
  • Messing around with DYLD_LIBRARY_PATH.
  • Using install_name_tool to set the correct internal metadata.

I have 2 questions about the install_name_tool approach.

  1. Yes, I can apply this on a per-file basis, by hand. But is there some Nix tool that essentially allows me to say ‘track down all the dylibs in this derivation and fix their metadata’?

  2. At the moment I’m resorting to install_name_tool <args> || true to avoid crashes on Linux (where install_name_tool does not exist). What is the correct way of conditionally executing some line inside the buildPhase or fixupPhase, depending on system?

There is fixDarwinDylibNames, which can be used by adding it to nativeBuildInputs.

Use lib.optionalString or lib.optionals. Both functions take a boolean expression as their first argument and respectively a string (optionalString) or a list (optionals) as their second argument. If the boolean expression evaluates to true, then the given string/list is returned, otherwise the empty string or list is returned.

So, you can do something like:

  nativeBuildInputs = [
    # Native build inputs for every platform.
  ] ++ lib.optionals stdenv.isDarwin [
    # Native build inputs for Darwin.
  ];

or:

  postInstall = ''
    # Post-install script for every platform
  '' + lib.optionalString stdenv.isDarwin ''
    # Post-install script for Darwin.
  '';

(There is also lib.optional, but it is generally disliked and lib.optionals is preferred.)

2 Likes

fixDarwinDylibNames looks like just the thing I was looking for, except that it searches for .dylib files, and I have a situation in which the extension is .so, which install_name_tool handles without a problem.

Is there a sensible way to get fixDarwinDylimNames to work on .so?

(If not, it’s not a tragedy in this case, as I do have a working solution that usese install_name_tool.)

I don’t think so, the library extension is currently hardcoded in the fixDarwinDylibNames hook:

https://github.com/NixOS/nixpkgs/blob/736957987ede6b439e00de864c0a91d6c623cbde/pkgs/build-support/setup-hooks/fix-darwin-dylib-names.sh#L39

Though I guess you could call fixDarwinDylibNames, but then there is not much benefit anymore over manually calling install_name_tool.