zig icon indicating copy to clipboard operation
zig copied to clipboard

Zig 0.12.0 fails to link against dynamic library on MacOS

Open aherrmann opened this issue 1 year ago • 1 comments

Zig Version

0.12.0

Steps to Reproduce and Observed Behavior

Zig fails to link against a dynamic library when it is passed by filename on the command-line, i.e. a command like

$ zig build-lib some-dir/libadd.dylib main.zig

fails with an error of the form

error: unknown file type for an object file
    note: while parsing some-dir/libadd.dylib

However, it succeeds when instead using -L and -l flags as follows

$ zig build-lib -Lsome-dir -ladd main.zig

See https://github.com/aherrmann/rules_zig/issues/274 for further details.

Note, this used to work with Zig 0.11.0. So, this is a regression.

Expected Behavior

The linking should succeed with both types of commands. For reference zig build-lib --help states:

Supported file types:
                    .zig    Zig source code
...
                  .dylib    Mach-O (macOS) dynamic library
...

aherrmann avatar Apr 23 '24 20:04 aherrmann

You need to specify -dynamic to generate dynamic library files.

Although in 0.11.0 you can generate libmain.a by zig build-lib libadd.dylib main.zig, it is an incorrect archive file. If you check its contents by ar t libmain.a, you will find that libadd.dylib is packaged together, and this file cannot be compiled into an executable file by clang.

$ zig version
0.11.0

$ cat add.c
int add(int a, int b) {
  return a + b;
}

$ cat main.zig
const std = @import("std");
const print = std.debug.print;

export fn greet() void {
    const sum = add(1, 2);
    print("{}\n", .{sum});
}

extern fn add(a: c_int, b: c_int) callconv(.C) c_int;

$ clang add.c -shared -o libadd.dylib
$ zig build-lib libadd.dylib main.zig

$ ar t libmain.a
__.SYMDEF
libadd.dylib
./libmain.a.o

$ cat entry.c
void greet();

int main() {
    greet();
}

$ clang libmain.a entry.c
ld: warning: archive member is not an object file
ld: warning: object file (libmain.a[3](./libmain.a.o)) was built for newer 'macOS' version (14.4.1) than being linked (14.0)
Undefined symbols for architecture arm64:
  "_add", referenced from:
      _greet in libmain.a.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I can't decide whether to set the output mode to dynamic library when compiling with dynamic library files in Zig to avoid generating invalid files.

zhylmzr avatar Apr 26 '24 06:04 zhylmzr

Thanks for clarifying! I misunderstood what Zig's behavior should be in this case. In the dynamic library case

zig build-lib -dynamic libadd.dylib main.zig

will generate libmain.dylib such that it links dynamically against libadd.dylib.

$ otool -l libmain.dylib | grep libadd
         name libadd.dylib (offset 24)

I assumed that in the static case it would also not attempt to include libadd.dylib into the archive. But, it seems it does.

It looks like if the intent is to maintain libadd.dylib as a dynamic dependency then the correct build-lib command omits libadd.dylib altogether.

zig build-lib main.zig

aherrmann avatar Apr 30 '24 06:04 aherrmann