Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig build-lib does not allow linking to a C program #14416

Open
1 of 3 tasks
perillo opened this issue Jan 22, 2023 · 6 comments
Open
1 of 3 tasks

zig build-lib does not allow linking to a C program #14416

perillo opened this issue Jan 22, 2023 · 6 comments
Milestone

Comments

@perillo
Copy link
Contributor

perillo commented Jan 22, 2023

In the Zig Language Reference there are two example of linking a Zig library to a C program in the "Exporting a C Library" and "Mixing Object Files" sections. Both examples fail.

These are the issues I found:

  • Static linking using a C compiler fails

    Using the mathtest.zig example

    zig build-lib -femit-h mathtest.zig
    
    gcc -o test -static -I $(zig env | jq -r .lib_dir) test.c -L . -lmathtest
    ./test
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.readElfDebugInfo':
    /home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:939: undefined reference to `__zig_probe_stack'
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `fs.Dir.openFile':
    /home/manlio/.local/share/sdk/zig/master/lib/std/fs.zig:1099: undefined reference to `__zig_probe_stack'
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.printLineFromFileAnyOs__anon_5459':
    /home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:1164: undefined reference to `__zig_probe_stack'
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `dwarf.DwarfInfo.getLineNumberInfo':
    /home/manlio/.local/share/sdk/zig/master/lib/std/dwarf.zig:1090: undefined reference to `__zig_probe_stack'
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.panicExtra__anon_5748':
    /home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:297: undefined reference to `__zig_probe_stack'
    /usr/bin/ld: ./libmathtest.a(./libmathtest.a.o):/home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:297: more undefined references to `__zig_probe_stack' follow
    collect2: error: ld returned 1 exit status
    

    I'm not sure if this works as expected. When using zig build the generated executable is dynamically linked.

    See -fcompiler-rt broken with object file builds #14099.

  • Setting LibExeObjStep.emit_h to true, does not emit the header file a second time when the header file is removed

    const Builder = @import("std").build.Builder;
    
    pub fn build(b: *Builder) void {
        const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
        lib.emit_h = true;
    
        const exe = b.addExecutable("test", null);
        exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"});
        exe.linkLibrary(lib);
        exe.linkSystemLibrary("c");
    
        b.default_step.dependOn(&exe.step);
    
        const run_cmd = exe.run();
    
        const test_step = b.step("test", "Test the program");
        test_step.dependOn(&run_cmd.step);
    }

    When mathtest.h does not exists, zig build will create it, but if I remove the file, zig build will not create it again.

    The reason is that the build system always enables caching, but the generated header file is not cached in the artifact directory.

    See compiler: enable caching for -femit-h #14606.

  • zig build should automatically include zig.h header when emit_h is set to true.

    When an executable links a library with emit_h set to true, the build system should automatically append the path to zig_dir to exe.include_dirs.

    See build: include zig.h when CompileStep.emit_h is true #14576.

Thanks.

@andrewrk andrewrk added this to the 0.11.0 milestone Jan 23, 2023
@kassane
Copy link
Contributor

kassane commented Feb 5, 2023

In the Zig Language Reference there are two example of linking a Zig library to a C program in the "Exporting a C Library" and "Mixing Object Files" sections. Both examples fail.

These are the issues I found:

Static linking using a C compiler fails

Using the mathtest.zig example

zig build-lib -femit-h mathtest.zig

gcc -o test -static -I $(zig env | jq -r .lib_dir) test.c -L . -lmathtest
./test
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.readElfDebugInfo':
/home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:939: undefined reference to `__zig_probe_stack'
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `fs.Dir.openFile':
/home/manlio/.local/share/sdk/zig/master/lib/std/fs.zig:1099: undefined reference to `__zig_probe_stack'
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.printLineFromFileAnyOs__anon_5459':
/home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:1164: undefined reference to `__zig_probe_stack'
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `dwarf.DwarfInfo.getLineNumberInfo':
/home/manlio/.local/share/sdk/zig/master/lib/std/dwarf.zig:1090: undefined reference to `__zig_probe_stack'
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o): in function `debug.panicExtra__anon_5748':
/home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:297: undefined reference to `__zig_probe_stack'
/usr/bin/ld: ./libmathtest.a(./libmathtest.a.o):/home/manlio/.local/share/sdk/zig/master/lib/std/debug.zig:297: more undefined references to `__zig_probe_stack' follow
collect2: error: ld returned 1 exit status

You have built the library in debug mode. If you build in releaseFast or small mode the error will not occur, or add -fcompiler-rt in build-lib. #6817 (comment)

@perillo
Copy link
Contributor Author

perillo commented Feb 5, 2023

You have built the library in debug mode. If you build in releaseFast or small mode the error will not occur, or add -fcompiler-rt in build-lib. #6817 (comment)

Thanks.

perillo added a commit to perillo/zig that referenced this issue Feb 9, 2023
As documented in ziglang#14416, when using `zig build-lib -femit-h` with
caching enabled, if the generated header file is removed, it will not
be generated again, unless the library source code is modified.

For consistent builds with `zig build`, assume that the file generated
by -femit using the default path is an artificact, and update
src/main.zig to enable caching.

Update the flushEmitH function in src/link/C.zig to use the
zig_cache_artifact_directory instead of the incorrect
local_cache_directory.

Updates ziglang#14416
perillo added a commit to perillo/zig that referenced this issue Feb 9, 2023
As documented in ziglang#14416, when using `zig build-lib -femit-h` with
caching enabled, if the generated header file is removed, it will not
be generated again, unless the library source code is modified.

For consistent builds with `zig build`, assume that the file generated
by -femit using the default path is an artificact, and update
src/main.zig to enable caching.

Update the flushEmitH function in src/link/C.zig to use the
zig_cache_artifact_directory instead of the incorrect
local_cache_directory.

Updates ziglang#14416
@kubkon
Copy link
Member

kubkon commented Feb 14, 2023

Fixed in #14644

@kubkon kubkon closed this as completed Feb 14, 2023
@kubkon kubkon reopened this Feb 14, 2023
@kubkon
Copy link
Member

kubkon commented Feb 14, 2023

Scratch my last comment. This issue goes away if you explicitly pass -fcompiler-rt. Whether this should be automatic I'll leave to @andrewrk, so reopening.

@perillo
Copy link
Contributor Author

perillo commented Feb 14, 2023

Scratch my last comment. This issue goes away if you explicitly pass -fcompiler-rt. Whether this should be automatic I'll leave to @andrewrk, so reopening.

I converted the 3 different issues into separate tasks.

I'm not sure about the last task, since the (currently disabled) test-gen-h test suite expects clean C code: https://github.com/ziglang/zig/blob/master/test/gen_h.zig.
A problem with this approach is name collision.

@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Jul 20, 2023
@owend
Copy link

owend commented Sep 8, 2023

Hello! With the latest versions of zig on MacOS (I tried version 0.10 and 0.11 and 0.12 and compiled from main/HEAD) this example now segfaults. Instead of opening a new bug I thought I would just add it here.

zig build-lib -femit-h mathtest.zig

➞  zig build-lib -femit-h  mathtest.zig
AST Lowering [519] target/aarch64.zig... thread 604505 panic: reached unreachable code
/Projects/zig/lib/std/debug.zig:342:14: 0x109fa4c7c in assert (zig)
    if (!ok) unreachable; // assertion failure
/Projects/zig/src/Module.zig:5343:19: 0x10a08705c in allocateNewDecl (zig)
            assert(@intFromEnum(decl_index) == mod_emit_h.allocated_emit_h.len);
/Projects/zig/src/Module.zig:3912:51: 0x10a22b0fc in semaFile (zig)
    const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0, null);
/Projects/zig/src/Module.zig:3888:24: 0x10a22ae81 in semaPkg (zig)
    return mod.semaFile(file);
/Projects/zig/src/Compilation.zig:3323:27: 0x10a25b19d in processOneJob (zig)
            module.semaPkg(pkg) catch |err| switch (err) {
/Projects/zig/src/Compilation.zig:3151:30: 0x10a0cddfe in performAllTheWork (zig)
            try processOneJob(comp, work_item, main_progress_node);
/Projects/zig/src/Compilation.zig:2058:31: 0x10a0c9929 in update (zig)
    try comp.performAllTheWork(main_progress_node);
/Projects/zig/src/main.zig:4098:24: 0x10a0fa161 in updateModule (zig)
        try comp.update(main_progress_node);

I added a debug print statement right before this block where the assertion is shown in Module.zig

        if (@intFromEnum(decl_index) >= mod_emit_h.allocated_emit_h.len) {
            try mod_emit_h.allocated_emit_h.append(gpa, .{});
            assert(@intFromEnum(decl_index) == mod_emit_h.allocated_emit_h.len);
        }

allocated_emit_h = segmented_list.SegmentedList(Module.EmitH,0)
decl_index = Module.Decl.Index(0)
allocated_emit_h.len = 0

It looks like the situation is (pseudo-code)

if 0 >= 0
    list.append
    assert 0 == 1

If the append succeeds, the assert always fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants