How to prevent module duplication?

I’ve got a test project, which depends on two C libraries, FreeType and Harfbuzz.

.{
    .name = "font-test",
    .version = "0.0.0",
    .paths = .{""},
    .dependencies = .{
        .freetype = .{
            .path = "dependencies/freetype",
        },
        .harfbuzz = .{
            .path = "dependencies/harfbuzz",
        },
    },
}

The two C libraries are thinly wrapped so they can use Zig build files. Harfbuzz also depends on the same FreeType library:

.{
    .name = "harfbuzz",
    .version = "10.4.0",
    .minimum_zig_version = "0.13.0",
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "lib.h",
        "lib.zig",
    },
    .dependencies = .{
        .freetype = .{
            .path = "../freetype",
        },
        .harfbuzz = .{
            .url = "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/10.4.0.tar.gz",
            .hash = "12209daa63ce40e1cd0d4dfa96435e6ac0cda5be37b8f11f6b73c29a89122df3e387",
        },
    },
}

Within my test program, if I try to pass FreeType variables to Harfbuzz, I get weird errors, as if Harfbuzz is using a separate copy of FreeType:

src/example.zig:70:47: error: expected type '[*c]cimport.struct_FT_FaceRec_', found '[*c]cimport.struct_FT_FaceRec_'
    const font = harfbuzz.c.hb_ft_font_create(ftFace, 0);
                                              ^~~~~~
src/example.zig:70:47: note: pointer type child 'cimport.struct_FT_FaceRec_' cannot cast into pointer type child 'cimport.struct_FT_FaceRec_'
/home/nairou/.persist/dev/projects/browser/platform/example/.zig-cache/o/59f6d172c702b17c5ef6008ef192299c/cimport.zig:1127:39: note: struct declared here
pub const struct_FT_FaceRec_ = extern struct {
                               ~~~~~~~^~~~~~
/home/nairou/.persist/dev/projects/browser/platform/example/.zig-cache/o/1997fa3a7d3dc5e84ca374b794520140/cimport.zig:2111:39: note: struct declared here
pub const struct_FT_FaceRec_ = extern struct {
                               ~~~~~~~^~~~~~
/home/nairou/.persist/dev/projects/browser/platform/example/.zig-cache/o/1997fa3a7d3dc5e84ca374b794520140/cimport.zig:2246:42: note: parameter type declared here
pub extern fn hb_ft_font_create(ft_face: FT_Face, destroy: hb_destroy_func_t) ?*hb_font_t;
                                         ^~~~~~~

Given that both build.zig files point to the same path, why are they building separate copies of the FreeType library? More importantly, how do I force them to use the same one?

See how ghostty reuses freetype from harfbuzz:

I’ve actually been going through ghostty’s build files for exactly that, but haven’t been able to determine how it reuses freetype. There’s a lot there, and a lot that matches my attempts, but I’m not seeing the piece that makes reuse work…

In your main build.zig.zon include both packages:

In your harfbuzz, include freetype as dependency in your build.zig.zon

In the build.zig for both main and harfbuzz:

Declare the freetype dependency and add it as import in your modules.