Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken rpath output when building Zig with Nix #18612

Open
erikarvstedt opened this issue Jan 18, 2024 · 12 comments
Open

Broken rpath output when building Zig with Nix #18612

erikarvstedt opened this issue Jan 18, 2024 · 12 comments
Labels
bug Observed behavior contradicts documented or intended behavior os-linux regression It worked in a previous version of Zig, but stopped working.
Milestone

Comments

@erikarvstedt
Copy link
Contributor

erikarvstedt commented Jan 18, 2024

Since #17917, when building Zig within a Nix environment, the rpath of the resulting Zig binary is faulty/broken:

  1. libgcc, the lib providing the direct dependency libstdc++.so, is missing from rpath.
    This causes an error when running zig:

    zig: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
    

    Previously, libgcc was correctly included in rpath.

  2. Include paths from NIX_CFLAGS_COMPILE are present in rpath.
    These paths contain no shared objects and should not be present in rpath.
    Examples:

    /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev/lib
    /nix/store/fak09pxs42fqcgngf2yznw83f88kmw7s-zlib-1.3-dev/lib
    ...
    

Details

Zig rpath before #17917:

/home/user/src/outputs/out/lib
/nix/store/rzx1szlgxck2wj4dqhq1q3p4330nj47j-llvm-17.0.6-lib/lib
/nix/store/lprrvg44cyn9ajpq77lh7rlnp4kzdqzs-zlib-1.3/lib
/nix/store/8g3myidcxw02mv9pzyvwq9cv0y9nayi7-libxml2-2.11.5/lib
/nix/store/fmkdf1b03w5v9yzk2mm3b4yqg1gwhrf5-ncurses-6.4/lib
/nix/store/lqrynl0j2ph8ggsfcc41nqcw5di0va50-clang-17.0.6-lib/lib
/nix/store/dghjv6hfz0s0z4kffa5ahyw2mhp79215-gcc-12.3.0-lib/lib     (Missing after #17917)
/nix/store/9y8pmvk8gdwwznmkzxa6pwyah52xy3nk-glibc-2.38-27/lib

Zig rpath after #17917:

/nix/store/rzx1szlgxck2wj4dqhq1q3p4330nj47j-llvm-17.0.6-lib/lib
/nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev/lib (Include path)
/nix/store/fak09pxs42fqcgngf2yznw83f88kmw7s-zlib-1.3-dev/lib       (Include path)
/nix/store/lprrvg44cyn9ajpq77lh7rlnp4kzdqzs-zlib-1.3/lib
/nix/store/8g3myidcxw02mv9pzyvwq9cv0y9nayi7-libxml2-2.11.5/lib
/nix/store/v1wj8jz1ap5rf5yqh1wn5ykqg9fr5vds-clang-17.0.6-dev/lib   (Include path)
/nix/store/lqrynl0j2ph8ggsfcc41nqcw5di0va50-clang-17.0.6-lib/lib
/nix/store/q6af8zwgwpr7lkfk8rcxc9pyvmmrclhd-lld-17.0.6-dev/lib     (Include path)
/nix/store/pakl6wfmh8vkir27kjlfdb6677pix001-lld-17.0.6-lib/lib
/nix/store/zpxb1xsx483qdzxf9ps3vjyqija5pms0-llvm-17.0.6-dev/lib    (Include path)
/nix/store/ifx5q9x3vcck3b01wb9h47x7va00snkd-ncurses-6.4-dev/lib    (Include path)
/nix/store/fmkdf1b03w5v9yzk2mm3b4yqg1gwhrf5-ncurses-6.4/lib
/home/main/d/zig-dev/zig/outputs/out/lib

When the Zig src is located in /home/user/src/zig, the path to the nonexisting dir /home/user/src/outputs/out/lib is added to rpath.
This is probably also an error, but this was already present before #17917.

Reproduce

# Enter Nix dev env for Zig.
# This sets up a build environment, setting env vars like `NIX_CFLAGS_COMPILE`, `NIX_LDFLAGS`, ...
nix develop github:erikarvstedt/nix-zig-build/f3ef222402b1e75e691c9122e17ac4f96ffd8af4
                                                                                                                                        
# Enter Zig src dir
cd /path/to/zig-src
                                                                                                                                        
cmake . -DCMAKE_BUILD_TYPE=Release -DZIG_NO_LIB=ON -GNinja
                                                                                                                                        
## Build Zig. option 1: bootstrap (slow)
ninja install
                                                                                                                                        
## Build Zig, option 2: use prebuilt Zig (fast)
ninja zigcpp
# Grab a Zig build that includes #17917 (852e7e2)
version=0.12.0-dev.2236+32e88251e
url=https://ziglang.org/builds/zig-linux-x86_64-$version.tar.xz
# Extract Zig binary to ./zig
curl -fL "$url" | tar xJ --strip-components=1 --wildcards --no-wildcards-match-slash '*/zig'
./zig build -Denable-llvm -Dno-lib --prefix stage3
                                                                                                                                        
./stage3/bin/zig
# => error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
                                                                                                                                        
ldd ./stage3/bin/zig
readelf -d ./stage3/bin/zig

cc @Jan200101, @kubkon, @andrewrk

@erikarvstedt erikarvstedt changed the title Broken rpath output on NixOS Broken rpath output when building Zig with Nix Jan 18, 2024
@andrewrk andrewrk added bug Observed behavior contradicts documented or intended behavior os-linux regression It worked in a previous version of Zig, but stopped working. labels Jan 19, 2024
@andrewrk andrewrk added this to the 0.12.0 milestone Jan 19, 2024
@andrewrk
Copy link
Member

why are you saying those lib directories are include paths? What files are in there?

@erikarvstedt
Copy link
Contributor Author

erikarvstedt commented Jan 19, 2024

Ah, sorry, these *-dev paths are not only present in NIX_CFLAGS_COMPILE, but also in other env vars.

Let's take /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev as an example.
It's included in these env vars:

Env var Env var entry
CMAKE_INCLUDE_PATH /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev/include
CMAKE_PREFIX_PATH /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev
NIX_CFLAGS_COMPILE -isystem /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev/include
PATH /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev/bin

Contents:

/nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev
├── bin
│   └── xml2-config
├── include
│   └── libxml2
│       └── libxml
│           ├── c14n.h
│           ├── ...
├── lib
│   ├── cmake
│   │   └── libxml2
│   │       └── libxml2-config.cmake
│   └── pkgconfig
│       └── libxml-2.0.pc
├── nix-support
│   └── propagated-build-inputs
└── share
    └── aclocal
        └── libxml.m4

The same goes for all other *-dev paths. They are dev pkg outputs that contain build-related tooling and source files but no binary objects.

@andrewrk
Copy link
Member

Hmm. When I do the following on my system:

$ nix-shell -p libxml2
$ env | grep NIX_LDFLAGS
NIX_LDFLAGS=-rpath /nix/store/2swpy93b6y5bsvmb7jawlmwwipwxmy2m-shell/lib64 -rpath /nix/store/2swpy93b6y5bsvmb7jawlmwwipwxmy2m-shell/lib  -L/nix/store/8mw6ssjspf8k1ija88cfldmxlbarl1bb-zlib-1.2.13/lib -L/nix/store/awj9x4rwndilh9hcwf121yz3xr9j64w6-libxml2-2.10.4/lib -L/nix/store/8mw6ssjspf8k1ija88cfldmxlbarl1bb-zlib-1.2.13/lib -L/nix/store/awj9x4rwndilh9hcwf121yz3xr9j64w6-libxml2-2.10.4/lib
$ ls /nix/store/awj9x4rwndilh9hcwf121yz3xr9j64w6-libxml2-2.10.4/lib
libxml2.la  libxml2.so  libxml2.so.2  libxml2.so.2.10.4

It looks to me like adding an rpath for that -L directory was the right move. I think the only confirmed regression in this issue is the missing directory that you identified above - the gcc one. I'm not convinced these other differences are problematic.

@erikarvstedt
Copy link
Contributor Author

Yes, these are lib outputs in NIX_LDFLAGS from pkg libxml2.lib. They should be added to the rpath. #17917 didn't change that.
What changed is that libxml2.dev outputs, which are not included in NIX_LDFLAGS (as shown in the env var table above), are also added to the rpath.

@erikarvstedt
Copy link
Contributor Author

NIX_LDFLAGS:                     -L/nix/store/8g3myidcxw02mv9pzyvwq9cv0y9nayi7-libxml2-2.11.5/lib  (should be added to rpath)
NIX_CFLAGS_COMPILE (and others):   /nix/store/nhv7xmxzi63lp3x1j7zrwb7f2248sgl2-libxml2-2.11.5-dev  (should not be added to rpath)

@andrewrk
Copy link
Member

andrewrk commented Jan 19, 2024

Hmm, I see. The new implementation of -feach-lib-rpath naively adds each library search directory to the rpath list regardless of whether a dynamic library was used from inside that directory. That should be adjusted.

Alternately, we could proceed with removing that feature entirely, as I mentioned in that PR, since the original motivation for -feach-lib-rpath was NixOS anyway. On the other hand, -feach-lib-rpath as opposed to adding an rpath for each -L from NIX_LDFLAGS creates a binary with a slightly more efficient runtime startup, because it prevents the dynamic linker from searching unnecessary directories to find dynamically linked libraries. With the current strategy of adding an RPath for each -L argument in NIX_LDFLAGS it could potentially add unnecessary RPaths if those are in the nix environment but not ultimately used by the executable.

What remains to be diagnosed is

/nix/store/dghjv6hfz0s0z4kffa5ahyw2mhp79215-gcc-12.3.0-lib/lib     (Missing after #17917)

@erikarvstedt
Copy link
Contributor Author

erikarvstedt commented Jan 19, 2024

Only adding required rpath entries would be perfect.
nixpkgs has a stdlib feature (patchelf, autoPatchelfHook) that prunes unneeded rpaths, but this is inconvenient when using Zig as a standalone build tool, outside of Nix derivations.

@oldendick
Copy link

The libstdc++.so missing from rpath issue is likely related to #18742

@erikarvstedt
Copy link
Contributor Author

Zig somehow auto-detects libstdc++ via cmake.

Ideally, Zig should remove this heuristic or correctly setup the rpath on Nix, so that a successful build guarantees that the binary can load its libs correctly.

@Jan200101
Copy link
Contributor

Zig somehow auto-detects libstdc++ via cmake.

I believe it does this in build.zig

zig/build.zig

Line 715 in d0c06ca

addCxxKnownPath(b, cfg, exe, b.fmt("lib{s}.{s}", .{ cfg.system_libcxx, lib_suffix }), "", need_cpp_includes) catch |err| switch (err) {

(There are also other non linux parts that directly link libstdc++)

Solutions include:

  • abandoning all hope for anything rpath related and giving in to the dark lord
  • checking if the found stdc++ library is on a NativePath, if not add it to the rpath
    • something along those lines: d4328e4
    • technically the same issue also exists for llvm, but the Nix flags deal with this for us.
  • setting use-zig-libcxx to use the included libc++

@Cloudef
Copy link
Contributor

Cloudef commented Mar 13, 2024

FYI I complained about this in a other issue, but IMO zig should not use the nixpkgs specific env vars at all
#18998 (comment)

@andrewrk andrewrk modified the milestones: 0.12.0, 0.13.0 Apr 6, 2024
@igaryhe
Copy link
Contributor

igaryhe commented May 23, 2024

is it possible to also add the path to libstdc++.so to rpath?

zig/build.zig

Line 819 in fb88cfd

exe.addObjectFile(.{ .cwd_relative = path_unpadded });

it's a bit hacky, but maybe something like

exe.addRPath(.{ .cwd_relative = path_unpadded[0..path_unpadded.len - 1 - objname.len] });

so that we can ensure the path to libstdc++.so would ended up in rpath

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior os-linux regression It worked in a previous version of Zig, but stopped working.
Projects
None yet
Development

No branches or pull requests

6 participants