Help compiling and linking C headers and libraries in 0.16+

Hello, everyone!

I’ve been away from Zig for a long time, now trying to get back to working on my pet projects using Zig :slight_smile:

Basically, I’d like to be able to compile my pre-0.16 projects.

My little projects contain some C code, including headers. Also I link against system libraries (glfw, GL, X11, etc.).

In the old times, there was this function addIncludePath, I used it to add paths to where the C headers I use in my projects were. In build.zig, I was doing this:

const exe = b.addExecutable( … );
exe.addIncludePath(std.Build.LazyPath { .cwd_relative = “glad/include” });

How do achieve the same in Zig 0.16 or later?

Also, how do I link system libraries?

(from my pre-0.16 build.zig) :

const c_flags: []const []const u8 = &[_][]const u8{"-O2", "-ffunction-sections", "-fdata-sections"};

exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = "glad/src/glad.c" }, .flags = c_flags });

exe.linkSystemLibrary("glfw");
exe.linkSystemLibrary("GL");
. . .
exe.linkLibC();

Currently I’m struggling with addIncludePath part, I haven’t gotten to addCSourceFile, linkSystemLibrary, and linkLibC.

It looks like addCSourceFile is now in exe.root_module:exe.root_module.addCSourceFile , but I’m not sure about linkSystemLibrary and linkLibC.

All of those things are on Module now, they have been for a couple versions with the ones on compile just forwarding to the root module until they were removed.

These things are mentioned in release notes, you can also just look at the docs of the previous version, as things are usually documented to be deprecated and get a grace period of at least 1 major version, this case is no exception.

In a situation like this, I think starting fresh is a good idea. What if I never in my life created a single Zig project? I wouldn’t be reading release notes of all previous versions of Zig. Instead, I would look for documentation, examples, tutorials on the following -

If I start from zig init, how then would I modify the stock build.zig so that it

  1. adds include paths for (local) C headers;
  2. adds local C source file(s) to be build;
  3. links system libraries?

If there were any examples of a build.zig doing these things, that would be awesome.

Currently I’m confused by the two modules my simple project now has to have - the .root_module in b.addExecutable(.{ … .root_module = b.createModule( … ) … }); and the translate-c module I now must have and import in .imports = &.{}

const translate_c = b.addTranslateC( … );

. . .

const exe = b.addExecutable(.{ … , .root_module = b.createModule(.{ …, .imports = &.{ .{ .name = “c”, .module = translate_c.createModule() }, } …);

Which one of them should add the include path, link the system libraries and the C library now?

A working example would really be wonderful.

The include path is just for #including headers, so it needs to be on the translate-c step (not the module it creates), it also needs to be on modules compiling c code.

Linking the libraries can be done on any module, by the time linking happens modules don’t exist, but it is best to put it on the module(s) that actually use the linked library, such as the module created from a translate c step. The same logic for which module to add the c source to for compilation.

The module from the translate c step will contain generated zig code that matches the headers, not everything can be translated because comptime is not a direct equivalent to c macros, those things will cause a compile error, but only if you try to use them.

To summarise:

  • give translate c the include paths, otherwise it can’t translate relevant #includes
  • add relevant linked libraries/c source to the module you get from translate c
  • add the relevant include paths to module containing c source code
  • add the module imports you need.

a working example exists in the 0.16 release notes

3 Likes

I think I finally hatched a working version (without actually linking any system libraries, that’s going to be the next step). Created a repo, as a template / reference - https://codeberg.org/Durobot/zig_c_translate_template

Hm.. Strangely, it works for me if I just call addIncludePath on c_module, not on translate_c: c_module.addIncludePath(...);

where c_module = translate_c.createModule();

Maybe that’s because I’m testing on Zig 0.16.0. Perhaps 0.17.0-dev works differently, I should try it as well.

Got it.

Did that (see above).