How to import a c lib

Hey,
I’m very new to zig so I’m a bit lost on how to actually include any c header into my code. The documentation that I’ve found is also quite sparse.

Right now I have a c header file in a seperate directory called “external”.
To my understanding to include the file in my main.zig file I have to do the following:

const c = @cImport(@cInclude("external/stb_image.h"))

but I’m getting an “error: 'external/stb_image.h' file not found”. Do I have to include that directory and file somehow in the build.zig file?

You need to add an include path so Zig knows where to find that header. exe.addIncludePath() is what you’re looking for if you’re using build.zig.

Also, if you want to use an external dependency, instead of managing it yourself, you can have zig automatically download it/cache it by putting it in your build.zig.zon file, i.e.

.stb = .{
    .url = "git+https://github.com/nothings/stb#5c205738c191bcb0abc65c4febfa9bd25ff35234",
    .hash = "122082911aadaef3c836d3833f7c60386ee1ee46feffb6c54785f784801c32212aaa",
},

I fetched and resolved the hash for you as well. Then access that inside your build.zig with b.dependency("stb"), i.e.

const stb_dep = b.dependency("stb", .{});
exe.addIncludePath(stb_dep.path("."));
3 Likes

Welcome to the Forum!

assuming you used zig init your main.zig file will be in src/main.zig, so I would guess that external is a sibling directory to src, if that is the case you would need this:

const c = @cImport(@cInclude("../external/stb_image.h"));

Alternatively you could use:

exe.addIncludePath(b.path("external"))

within your build.zig and then use:

const c = @cImport(@cInclude("stb_image.h"));

in your code or even better do what @marler8997 suggested to add the dependency to your project.


However stb_image needs a define set, otherwise you won’t have the implementation part of the library in your build.

I think you could add the implementation part separately from the cImport/cTranslate to get the best compatibility (only put the header part through translate and the implementation part through addCSourceFile), I think you can do that by adding this to your build.zig (may need testing/some small changes):

var image_impl_step = b.addWriteFiles();
const image_c_path = gen_step.add("image.c", "#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n");
exe.addCSourceFile(.{ .file = image_c_path });

this is roughly based on what raylib does for its raygui.h raylib/build.zig at d46ba9a67176f49c3badc031a8f0445b142b5880 · raysan5/raylib · GitHub

4 Likes

Thanks guys for the swift answer, sorry for the late reply tho. Just wanted to let you know that the solution worked thank you!

Just so that I understand it better the addWriteFiles() allows me to add a file to the build which references the stb_image.h header correct?
Which it can find since we’ve added the include path “external”.

Did I get that right?

yes that is right

1 Like

I’ve read that @cImport might be removed in future versions of Zig so you might have to import the C header file as a module in your build file and then @import the module in your source file normally. For instance:

// suppose raylib_dep is the dependency object
const raylib_translate_c = b.addTranslateC(.{
    .root_source_file = raylib_dep.path("src/raylib.h"),
    .target = target,
    .optimize = optimize,
});
const raylib_mod = raylib_translate_c.createModule();
exe.root_module.addImport("raylib", raylib_mod);

and in main.zig:

const rl = @import("raylib");
3 Likes