Troubleshooting for linking with pre-built static libraries

Missing a lot of std C++ symbols like:
ld.lld: undefined symbol: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::rfind(char const*, unsigned long, unsigned long) const

in build.zig I am linking the zig’s libc++ with linkLibCpp. I assume that zig’s bundled C++ standad library is different than the pre-built one, is there any suggestions what should I try in this case?

I’ve noticed issues with this depending on the platform/abi/etc, particularly on some Windows targets. What target are you trying to build and/or do you have code you can share?

1 Like

I am actually trying to link with pre-built llvm static libraries from here Index of /development_releases/prebuilt/libclang/qt
specifically the libclang-release_18.1.7-based-linux-Ubuntu22.04-gcc11.2-x86_64.7z

For someone in the future ever encounters something like this, it’s probably happening because the pre-built static library requires libstdc++, zig would be usually configured to link libc++ not libstdc++, not sure how to tell zig to link with libstdc++ probably you can’t without recompiling zig?

So tried to use std.zig.system.NativePaths

fn hasFileIn(dir_path: []const u8, file: []const u8) bool {
    var dir = std.fs.openDirAbsolute(dir_path, .{}) catch return false;
    defer dir.close();
    dir.access(file, .{}) catch return false;
    return true;
}

fn getObjSystemPath(
    native_path: std.zig.system.NativePaths,
    obj_full_file: []const u8,
) ![]const u8 {
    for (native_path.lib_dirs.items) |lib_dir| {
        const resolved_lib_dir = try std.fs.path.resolve(native_path.arena, &.{lib_dir});
        if (hasFileIn(resolved_lib_dir, obj_full_file)) {
            return try std.fs.path.join(native_path.arena, &.{ resolved_lib_dir, obj_full_file });
        }
    }
    return error.FileNotFound;
}

then can be used like this with combination of a build option(make sure you’ve not called linkLibCpp)

// b: *std.Build, target: std.Build.ResolvedTarget, exe: *std.Build.Step.Compile
const libstdcxx_names: []const []const u8 = &.{
    "libstdc++.so",
    "libstdc++.a",
};
const native_path = try std.zig.system.NativePaths.detect(b.allocator, target.result);
for (libstdcxx_names) |libstdcxx_name| {
    const libstdcxx_path = getObjSystemPath(native_path, libstdcxx_name) catch continue;
    exe.addObjectFile(.{ .cwd_relative = libstdcxx_path });
    break;
}

basically this will just search the system library paths for libstdc++, not sure how cross-compatible(for unix-like platforms) this solution is, but something if you really need also addObjectFile can be your friend.

4 Likes