ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.79k stars 2.54k forks source link

cannot link against shared system libraries -AND- ZIG task is bad #14939

Open gshanemiller opened 1 year ago

gshanemiller commented 1 year ago

Zig Version

0.11.0-dev.1987+a2c6ecd6d Ubuntu 22.04LTS

Steps to Reproduce and Observed Behavior

This bug might be related to https://github.com/ziglang/zig/issues/14963

As with vanilla C development, Zig should be able to link against standard shared libraries (e.g. pthread.so, mlx5.so, ibverbs.so). I cannot make this happen. I've played over several hours with CompileStep's options to no avail.

Although static link is generally preferred, in this case I want these libraries linked dynamically. No matter what I do, all successful builds give:

$ zig build

$ ldd ./zig-out/bin/zig-perftest 
linux-vdso.so.1 (0x00007ffdd21da000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa1b901f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa1b9249000)

$ file ./zig-out/bin/zig-perftest
zig-out/bin/zig-perftest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped

ldd does not show libibverbs, for example. I'm pretty sure Zig linked statically; regardless the behavior of the program is wrong. See below.

To reproduce:

  1. git clone https://github.com/gshanemiller/zig-perftest/tree/zigbuildbug
  2. cd zigbuildbug
  3. ./scripts/setup_build_env. # adjust apt install packages as needed
  4. zig build
  5. ./scripts/setup_run_env
  6. ./zig-out/bin/zig-perftest

stdout reports:

got 0 devices expect (2) devices

It should report (2) devices not 0.

Expected Behavior

Since the ZIG build does not work and does not produce the correct output, I'll give the expected output by showing what a C build of the same two .c files gives when built by gcc:

  1. cd zigbuildbug/c
  2. ./build
$ ldd ./ib
linux-vdso.so.1 (0x00007ffc8c331000)
libibverbs.so.1 => /lib/x86_64-linux-gnu/libibverbs.so.1 (0x00007f1ae727f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1ae7057000)
libnl-route-3.so.200 => /lib/x86_64-linux-gnu/libnl-route-3.so.200 (0x00007f1ae6fd4000)
libnl-3.so.200 => /lib/x86_64-linux-gnu/libnl-3.so.200 (0x00007f1ae6fb1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1ae72a9000)

$ file ./ib
./ib: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=757f7521f5e67e14125ea5f66e66fff61f1bd47a, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ./ib
got 2 devices expect (2) devices

The zig code is a cannon shooting a fly. All it does is call a single C function ibv_get_device_list. A relevant difference between the correct behavior and Zig is how this symbol is linked:

# bad: how'd zig get the code for this anyway? it's probably from the static libibverbs.a
$ nm ./zig-out/bin/zig-perftest | grep ibv_get_device_list
000000000021d320 T ibv_get_device_list

# good: ibv_get_device_list is supposed to be undefined since it's extern in a linked shared library!
$ nm ./c/ib | grep ibv_get_device_list
U ibv_get_device_list@IBVERBS_1.1
wainejr commented 3 months ago

Workaround is to use LD_PRELOAD to run the executable and link only when running it, as in

LD_PRELOAD="/usr/lib64/libpthread.so.0 /usr/lib64/libdl.so.2 /usr/lib64/libc.so.6" zig-out/bin/<program-name>

You can check the linkage with

LD_PRELOAD="/usr/lib64/libpthread.so.0 /usr/lib64/libdl.so.2"  ldd zig-out/bin/zLBM
        linux-vdso.so.1 (0x00007f9e96424000)
        /usr/lib64/libpthread.so.0 (0x00007f9e96419000)
        /usr/lib64/libdl.so.2 (0x00007f9e96414000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f9e96214000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9e96426000)
polarathene commented 1 month ago

You may want to try reproducing again with a newer Zig release. For example a glibc build failure with zig in releases earlier than 0.12.0 was the cause of this one: https://github.com/rust-cross/cargo-zigbuild/issues/255#issuecomment-2339632373

That said zig cc still fails with building a static binary, even when .a files are provided it still has an interpreter configured for some reason 🤷‍♂️ (resulting in a segfault) https://github.com/ziglang/zig/issues/4986#issuecomment-1982362679