Incorrect linker command when linking some system libs on FreeBSD
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 ...
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.
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.
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: @.***>
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?
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.
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.
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.
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.
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.