Zig 0.16 cross-compiling with external uClibc toolchain: sysroot/libc linking and ELF interpreter issues

Hello,

zig 0.16

I want to build an app that uses a library which links against the libc provided by the arm-buildroot-linux-uclibcgnueabihf-4.9.4 toolchain. I can compile my code with Zig, but I’m having trouble linking to that library because it depends on the toolchain libc.

When I build, either it links against my system libc or it fails to link against the toolchain libc. I tried using setLibCFile() but ldd reports:

error: ld.lld: cannot open /lib/libc.so.1: No such file or directory
error: 1 compilation errors

The linker is searching my system lib instead of the toolchain sysroot. I tried setting the sysroot with b.sysroot =, but the toolchain is downloaded and extracted by build.zig, so b.sysroot would need to be a lazy path to work. If I extract the toolchain outside of build.zig and set b.sysroot, the linker then cannot find Zig’s libraries. (like undefined getauxval)

I thought it might be a bug, so I tried Zig 0.17.0-dev.958+c5d6277ac, but b.sysroot no longer exists there and I still have the same libc problem.

I considered the hack ln -s /mytoolchain/sysroot/lib/libc.so.1 /lib/libc.so.1, but that didn’t work either. (and it’s awful…)

If I didn’t have to use this librairie, everything would be fine, but I need it for DTLS.
I’ve been working on this for three days and have tried many approaches, but I’m stuck. Any ideas how to fix this?


Another issue: for code that links against shared libraries with no dependencies, I must manually set the interpreter using patchelf. The dynamic-linker field does not work with shared libraries (and I don’t really understand what it does :eyes:), so I have to do this:

const patchelf = b.addSystemCommand(&.{
    "patchelf",
    "--set-interpreter",
    "/lib/ld-uClibc.so.0",
});
patchelf.addArg("--output");
const output = patchelf.addOutputFileArg("patched.elf");
patchelf.addFileArg(exe.getEmittedBin());
patchelf.step.dependOn(&exe.step);
b.getInstallStep().dependOn(&b.addInstallFileWithDir(output, .bin, "patched").step);

Now I can’t build on Windows and my team uses Windows. I’m the only one on Linux.
Is there a way to set the interpreter for the executable without using patchelf?

1 Like