Skip to content

Unable to link libc when targeting wasm-freestanding-musl with C library #22481

@Rokannon

Description

@Rokannon

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

Suppose we have a zig project which compiles to wasm32 to be used in a browser. We can enable linking C library and use some function from it (e.g. strlen). But the issue I stumbled upon happens when we also try to link a C library that uses libc. I boiled down an example to reproduce the issue to just 4 files (all in a single directory).

main.zig

const c = @cImport({
  @cInclude("string.h");
  @cInclude("./my_lib.h");
});

// Just sends that value to `console.log(...)` from JS.
extern fn report_int(value: i32) void;
    
export fn init1() void {
  report_int(@as(i32, @intCast(c.strlen("hellohello"))));
}
    
export fn init2() void {
  report_int(c.get_strlen_value());
}

my_lib.h

#ifndef MY_LIB_H
#define MY_LIB_H

int get_strlen_value();

#endif

my_lib.c

#include <string.h>

int get_strlen_value() {
  return strlen("hello");
}

build.zig

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.resolveTargetQuery(.{
        .cpu_arch = .wasm32,
        .os_tag = .freestanding,
        .abi = .musl,
    });
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "micro",
        .target = target,
        .optimize = optimize,
        .link_libc = true,
        .root_source_file = b.path("main.zig"),
    });
    exe.entry = .disabled;
    exe.rdynamic = true;
    exe.addIncludePath(b.path("."));

    const lib = b.addStaticLibrary(.{
        .name = "my_lib",
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    lib.addCSourceFile(.{
        .file = b.path("my_lib.c"),
    });
    exe.linkLibrary(lib);

    b.installArtifact(exe);
}

Note that in main.zig we have a function init2 which calls c.get_strlen_value which is a simple function that just calls strlen. Linking fails with a following error:

$ zig build -Doptimize=ReleaseSmall
install
└─ install micro
   └─ zig build-exe micro ReleaseSmall wasm32-freestanding-musl 1 errors
error: wasm-ld: /home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache/o/ccc9861ab7882074d19f86c34d9f1c51/libmy_lib.a(/home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache/o/621b297b8b85baaa5f30542c19b9404e/my_lib.o): undefined symbol: strlen
error: the following command failed with 1 compilation errors:
/snap/zig/11625/zig build-exe -fno-entry /home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache/o/ccc9861ab7882074d19f86c34d9f1c51/libmy_lib.a -OReleaseSmall -target wasm32-freestanding-musl -mcpu baseline -I /home/rokannon/Repos/Zig-Toolchain/micro -I /home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache/o/544790c738d38eb183fa637997b2e9c3 -Mroot=/home/rokannon/Repos/Zig-Toolchain/micro/main.zig -lc --cache-dir /home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache --global-cache-dir /home/rokannon/.cache/zig --name micro -rdynamic --listen=-
Build Summary: 3/6 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install micro transitive failure
   └─ zig build-exe micro ReleaseSmall wasm32-freestanding-musl 1 errors
error: the following build command failed with exit code 1:
/home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache/o/71a38367b5c1abf4888b25312019f33a/build /snap/zig/11625/zig /home/rokannon/Repos/Zig-Toolchain/micro /home/rokannon/Repos/Zig-Toolchain/micro/.zig-cache /home/rokannon/.cache/zig --seed 0xeea5da53 -Z367dd54620a577b3 -Doptimize=ReleaseSmall

I also tried building C code as a static library using zig build-lib -target wasm32-freestanding-musl my_lb.c -rdynamic -lc. That succeeds, but then I would have b.addObjectfile(b.path("libmy_lib.a")); in my build.zig file. And when I zig build it, it fails with the same failure of not linking the strlen into the final wasm file.

Expected Behavior

That linking error seem to be quite unexpected especially given the following observation: If I disable that simple C library and use strlen function from within the main.zig file (see init1 function) then the complation suceeds. I can the final wasm file and strlen succesfully computes the correct value.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions