nix requires ranlib

2024/09/14

Be forewarned: HER builds with nix require a functional ranlib

This is something seldom known, and a very sharp corner to cut yourself on. But you really want to know if you are using nix.

I lost an entire day trying to figure out mysterious “symbol not found” errors while trying to link a hermetic instance of the nvc VHDL compiler under bazel with rules_foreign_cc, in a HER build, when using link-time optimizations (“LTO”), which is the norm these days.

If this post from discourse.nixos.org is to be believed, apparently nix does not install the LTO plugins for the linker, causing the created libraries not to have a symbol index. Now, this is apparently solved automatically when making a library with the gcc-ar program that supports LTO (you can request by defining AR=gcc-ar when compiling).

For this reason, a lot of default build configurations just short-circuit a ranlib invocation to :. Unfortunately if your ar does not index the libraries, you will get a bunch of libraries that can not be linked correctly. Worse yet, if you build via rules_foreign_cc, you can not pass the name or path of the ranlib binary via the RANLIB env variable, which means even if you attempt to do it, you will still get : as a ranlib binary: effectively a no-op.

As a result, if you have a program that tries to link a bunch of such local static libraries (e.g. lib.a or such) with main.o, you will get link errors for all the symbols defined in those libraries.

A solution that I found, after spending many hours staring at the link errors that do not repro outside of my build sandbox, was to do adjust the call to configure as follows:


env RANLIB=ranlib ./configure # … the rest of the flags

More changes were necessary to make this work, including an upstream patch to nvc, but those were more obvious issues, that had more obvious resolutions.