zig icon indicating copy to clipboard operation
zig copied to clipboard

Incorrect linker command when linking some system libs on FreeBSD

Open nfisher1226 opened this issue 3 years ago • 9 comments

Zig Version

0.10.0-dev.3027+0e26c6149

Steps to Reproduce

Here is a minimal build.zig which triggers the issue:

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{});
    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("ztest", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.linkLibC();
    exe.linkSystemLibrary("gtk+-3.0");
    exe.install();

    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

}

Expected Behavior

The linker should run and link to the dynamic versions of Gtk+ and it's dependent libraries, as it does on Linux.

Actual Behavior

The linker attempts to link to several static versions of various Gtk+ dependencies, resulting in missing symbols. The actual linker command as given by zig build --verbose-link is as follows:

ld.lld -error-limit=0 -O0 -z stack-size=16777216 --gc-sections -znow -m elf_x86_64_fbsd -o /usr/home/nathan/src/ztest/zig-cache/o/6933f02c3c246b91d9337d486672806c/ztest /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -rpath /usr/local/lib -L /usr/local/lib -L /usr/local/lib64 -L /usr/local/lib -L /usr/lib/x86_64-freebsd-gnu -L /lib64 -L /lib -L /usr/lib64 -L /usr/lib -L /lib/x86_64-freebsd-gnu -L /usr/lib -dynamic-linker /libexec/ld-elf.so.1 /usr/local/lib/libcairo-gobject.a /usr/local/lib/libcairo.a /usr/local/lib/libgio-2.0.a /usr/local/lib/libgobject-2.0.a /usr/local/lib/libglib-2.0.a /usr/local/lib/libintl.a /usr/home/nathan/src/ztest/zig-cache/o/6933f02c3c246b91d9337d486672806c/ztest.o /home/nathan/.cache/zig/o/02b2f69ae7238eb4aa3a7ea27fcbcfff/libcompiler_rt.a --as-needed -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpthread -lc -ldl -lrt -lutil /usr/lib/crtend.o /usr/lib/crtn.o

This results in numerous missing symbol errors:

ld.lld: error: undefined symbol: libiconv_open
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_iconv_open) in archive /usr/local/lib/libglib-2.0.a
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_iconv_open) in archive /usr/local/lib/libglib-2.0.a
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_iconv_open) in archive /usr/local/lib/libglib-2.0.a
>>> referenced 1 more times

ld.lld: error: undefined symbol: libiconv
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_iconv) in archive /usr/local/lib/libglib-2.0.a
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_convert_with_iconv) in archive /usr/local/lib/libglib-2.0.a
>>> referenced by gconvert.c
>>>               gconvert.c.o:(g_convert_with_iconv) in archive /usr/local/lib/libglib-2.0.a
>>> referenced 1 more times
... omitted for brevity ...

nfisher1226 avatar Jul 19 '22 13:07 nfisher1226

I am seeing what I believe is the same issue reported here. First, I have to explicitly name, with -lfoo, all the libraries that gtk+ depends upon, which used to be unnecessary. When I do and successfully build an executable, running it produces (on FreeBSD 13.1)

dca@pangloss:/tmp/zig/zig_newcash$ make
clang -g `pkg-config --cflags gtk+-3.0` -D_XOPEN_SOURCE -c -o interface.o interface.c
zig build-exe -O Debug -cflags -g -pg -- --main-pkg-path .. -fsingle-threaded  -L/usr/local/lib -L/usr/lib64 -lffi -liconv -lpcre -lgmodule-2.0 -lz -lpixman-1 -lfontconfig -lfreetype -lxml2 -lexpat -lpng  -lXrender -lX11 -lxcb -lXau -lXdmcp -lXext `pkg-config --libs gtk+-3.0` -lsqlite3 -lc newcash.zig interface.o
dca@pangloss:/tmp/zig/zig_newcash$ ./newcash

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_lookup: assertion 'hash_table != NULL' failed

(process:51957): GLib-CRITICAL **: 13:02:14.667: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed
**
GLib-GObject:ERROR:../gobject/gtype.c:2808:g_type_register_static: assertion failed: (static_quark_type_flags)
Bail out! GLib-GObject:ERROR:../gobject/gtype.c:2808:g_type_register_static: assertion failed: (static_quark_type_flags)
zsh: abort (core dumped)  ./newcash

The first thing this application does is check the number of command line arguments and print a usage statement if incorrect. That is what should have happened here, since I invoked it without arguments.

I have tested the same code on an Arch Linux system and the executable runs correctly (without args, prints the usage message and exits; with args the application comes up normally and works as far as I've gotten in the coding).

Both the FreeBSD and Linux copies of zig were downloaded today (8/4) from the nightly buiilds.

donaldcallen avatar Aug 04 '22 17:08 donaldcallen

Out of curiosity, what happens if you don't name all of the dependent libraries explicitly? For me, the link succeeds on Linux but fails on FreeBSD.

nfisher1226 avatar Aug 04 '22 19:08 nfisher1226

On Thu, 4 Aug 2022 at 15:34, Nathan Fisher @.***> wrote:

Out of curiosity, what happens if you don't name all of the dependent libraries explicitly? For me, the link succeeds on Linux but fails on FreeBSD.

I use FreeBSD primarily and I don't think I tested that on Linux. If I have a chance to do so, I will, and report the result.

— Reply to this email directly, view it on GitHub https://github.com/ziglang/zig/issues/12170#issuecomment-1205688353, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABGOGJ4WDPJG7B4FVC4GGC3VXQLNTANCNFSM53772H6A . You are receiving this because you commented.Message ID: @.***>

donaldcallen avatar Aug 04 '22 21:08 donaldcallen

I assume this is because zig is linking against the static libraries rather than the dynamic library.

Questions to answer:

  • Why is zig preferring static over dynamic?
  • Why doesn't zig use pkgconfig data to fill in all dependent libraries for a static library?
    • Or perhaps is FreeBSD is missing pkgconfig data?

daurnimator avatar Aug 15 '22 01:08 daurnimator

stryder% pkg-config --libs gtk+-3.0     
-L/usr/local/lib -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl
stryder% ls /usr/local/libdata/pkgconfig/gtk+-3.0.pc 
/usr/local/libdata/pkgconfig/gtk+-3.0.pc

Could be the location of .pc file on FreeBSD I suppose? Linux would have them under /usr/lib/pkgconfig or /usr/share/pkgconfig. But at least I can confirm they exist.

nfisher1226 avatar Aug 15 '22 16:08 nfisher1226

I'm thinking now that this is a path issue. I have a minimal Linux installation that uses NetBSD pkgsrc for packages, installed under /usr/pkg. It's triggering this bug. So the os-freebsd label is likely too specific.

nfisher1226 avatar Sep 30 '22 16:09 nfisher1226

Can this be worked around without removing *.a static libraries? I'm trying to find a fix for mepo package that got regressed by zig 0.9.1 -> 0.10.0 update.

EDIT: found a workaround.

jbeich avatar Jan 12 '23 10:01 jbeich

this looks related to #14111

short story: not an issue specific to freebsd; it's probably happening on all *unix platforms

My memory is a bit fuzzy, but I think I did find where zig searched .a first but it was rather a can-o-worms to tackle due to how very different each platform (linux, *bsd) vs openbsd vs macos, so I shelved it for the moment.

mikdusan avatar Jan 13 '23 02:01 mikdusan

Agreed. My further experiments showed that paths were not the issue, the existence of static libraries causes zig to attempt to link to them over shared libraries.

nfisher1226 avatar Jan 13 '23 15:01 nfisher1226