mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-11-02 02:38:44 +00:00
To decide whether a library directory is in the store, and so belongs in the rpath, ld-wrapper canonicalizes its path with `realpath -s`, and then, while it is outside the store, follows it if it is a symlink. But the linker searches the directory the kernel resolves the path to, and the kernel follows each symlink in the path, including those of ancestor directories, before going on to the next component, so `..` applies to the target of a symlink. So ld-wrapper got these wrong: - A symlink into the store, as in -L/build/link with /build/link pointing to /nix/store/...-foo/lib: after following it, ld-wrapper set dir to the literal string "dir2" rather than "$dir2", so it never added /nix/store/...-foo/lib to the rpath. It would also have resolved a relative target against the current directory, rather than the directory containing the symlink. - A symlink into the store from an ancestor directory, as in -L/build/link/lib with /build/link pointing to /nix/store/...-foo: the path is not a symlink itself, so ld-wrapper treated it as outside the store. - A `..` after a symlink, as in -L/build/link/../lib with /build/link pointing to /nix/store/...-foo/bin: `realpath -s` removed link/.. without following link, so ld-wrapper looked at /build/lib instead of /nix/store/...-foo/lib. The same goes for a symlink in the store, where the result can be a different store path than the one the linker searched. Instead, resolve the path one component at a time, with a new resolveLibDir function, following each symlink as the kernel does. But in the store, still keep a symlink that is not followed by `..` as it is, since resolving symlinks between store paths would refer to their targets instead of the store paths given (#454199). And never resolve the store or its ancestors, as `realpath -s` did not, so that the store is still recognized when /nix is a symlink, which Nix allows with NIX_IGNORE_SYMLINK_STORE. Like the linker, and as `realpath -s` did, take a relative path, as in `ld -L lib`, from the working directory. As a result, ld-wrapper also no longer runs `realpath` for every library directory, which it has since #472652, slowing down every link (#545973). It runs `readlink` only to follow a symlink. Linking an empty C program now starts 7 processes instead of 15. Test all of these cases, including the tests from #566486 for symlinks with absolute and relative targets, and test that ld-wrapper keeps a symlink between store paths in the rpath, that it recognizes a store whose parent is a symlink, and that it resolves relative directories from the working directory. Co-authored-by: Robert Hensing <robert@roberthensing.nl> Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Anders Kaseorg <andersk@mit.edu>