Using cglm

I am trying to use the cglm library, in header only mode:
build.zig:

exe_test.addIncludePath(b.path("lib/cglm/" ++ cglm_version ++ "/include"));

main.zig:

const cglm = @cImport({
    @cInclude("cglm/cglm.h");
    @cInclude("cglm/call.h");
    @cInclude("cglm/simd/sse2/mat4.h");
});

var vec: [4]f32 = [_]f32{1.0, 0.0, 0.0, 1.0};
    var trans: [4][4]f32 = undefined;
    cglm.glm_mat4_identity(&trans);
    var translation = [_]f32{1.0, 1.0, 0.0};
    cglm.glm_translate(&trans, &translation);
    var result_vec: [4]f32 = undefined;
    cglm.glm_mat4_mulv(&trans, &vec, &result_vec);
    std.log.info("Transformed Vector: x={:.2}, y={:.2}, z={:.2}\n", .{
        result_vec[0],
        result_vec[1],
        result_vec[2],
    });

I get some undefined symbols from… lld?

   └─ zig build-exe test Debug native 2 errors
error: ld.lld: undefined symbol: glm_mat4_mulv_sse2
    note: referenced by cimport.zig:33545 (/home/./Projects/Programming/ziggl/.zig-cache/o/a490b41046868bba0df2c1d9ecc31f48/cimport.zig:33545)
    note:               /home/./Projects/Programming/ziggl/.zig-cache/o/66c67dd1ade95ed7df7c4ce66291dcf1/test.o:(main.main)
error: ld.lld: undefined symbol: _mm_fmadd_ps
    note: referenced by cimport.zig:29542 (/home/./Projects/Programming/ziggl/.zig-cache/o/a490b41046868bba0df2c1d9ecc31f48/cimport.zig:29542)
    note:               /home/./Projects/Programming/ziggl/.zig-cache/o/66c67dd1ade95ed7df7c4ce66291dcf1/test.o:(cimport.glmm_fmadd)

Those functions do exist:

grep --recursive glm_mat4_mulv_sse2 .
./0.9.4/include/cglm/simd/sse2/mat4.h:glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) {
./0.9.4/include/cglm/mat4.h:  glm_mat4_mulv_sse2(m, v, dest);
grep --recursive _mm_fmadd_ps .
./0.9.4/include/cglm/simd/x86.h:  return _mm_fmadd_ps(a, b, c);

I don’t know what I’m missing.

/usr/include/cglm/simd/sse2/mat4.h:91:1: warning: unable to translate function, demoted to extern

Zig fails to translate this function (and some others) and demotes it to extern, hence the link issue. If you get this on master I believe you should report this issue. Meanwhile, as a workaround, you can wrap this function in C and export it, but this would hurt performance since it would not be inlined

How did you get this warning? Also, I just installed 0.14.0-dev.2571+01081cc8e and face the same issue.

The translate-c and @cImport features can only translate a subset of C designed to primarily handle constants, typedefs, and function declarations. The SIMD parts of CGLM rely on architecture specific compiler builtins for gcc, clang, etc, which won’t translate. The current way to use header only libraries is to not use them as header only, and to compile and link the implementation separately.

2 Likes

Is this still something that can be achieved with zig cc though? Obviously I can cmake the lib and use the .a, for now I’m just toying with stuff for myself. But if I had to distribute the project, I wouldn’t want people to have to install cmake.

>The current way to use header only libraries is to not use them as header only
exe.addIncludePath(b.path("lib/stb_image/" ++ stb_image_version)); is all I do for stb_image and it works.

I tried building cglm in the buildscript, similarly to how I build glfw:

const cglm_lib = try build_cglm(b, target, optimize, cglm_version);
exe.linkLibrary(cglm_lib);


pub fn build_cglm(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode,
    comptime version: []const u8) !*std.Build.Step.Compile {

    var src_files = std.ArrayList([]const u8).init(b.allocator);
    defer src_files.deinit();
    var src_dir = try std.fs.cwd().openDir("lib/cglm/" ++ version ++ "/src", .{ .iterate = true });
        defer src_dir.close();
    var src_walker = try src_dir.walk(b.allocator);
        defer src_walker.deinit();
    while (try src_walker.next()) |entry| {
            if (entry.kind != .file or !std.mem.eql(u8, std.fs.path.extension(entry.basename), ".c")) {
                continue;
            }
            try src_files.append(b.dupePath(try std.fs.path.join(b.allocator, &.{
                "lib/cglm/" ++ version ++ "/src",
                entry.path,
            })));
        }

    const lib = b.addStaticLibrary(.{
        .name = "cglm",
        .target = target,
        .optimize = optimize,
    });

    lib.installHeadersDirectory(b.path("lib/cglm/" ++ version ++ "/include/cglm"), "cglm", .{});

    const flags = [_][]const u8{
        "-std=c99",
    };

    const owned_slice = try src_files.toOwnedSlice();
    defer src_files.allocator.free(owned_slice);

    lib.addCSourceFiles(.{
        .files = owned_slice,
        .flags = &flags,
    });

    lib.linkLibC();

    b.installArtifact(lib);
    return (lib);
}

This doesn’t solve the issue.