Attempting to build with c header zpl-c/enet leads to an error: use of undeclared identifier 'CLOCK_MONOTONIC'

Main.zig:

const std = @import("std");
const print = std.debug.print;

const net = @cImport({
    @cDefine("ENET_IMPLEMENTATION", "");
    @cInclude("enet.h");
});

pub fn main() !void {
    print("{}", .{net.enet_initialize()});
    defer net.enet_deinitialize();
}

Build.zig:

const Builder = @import("std").build.Builder;

pub fn build(b: *Builder) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "init-exe",
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibC();
    exe.addIncludePath(.{ .path = "libs" });

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

Library I’m attempting to use: GitHub - zpl-c/enet: ⚡️ ENet reliable UDP networking library
Any help would be appreciated, I’ve been trying to get this to work for hours and it has me stumped

It’s generally not recommended to include the implementation of a library in a @cImport.
@cImport, which internally translates the C code to Zig code, is not working in many cases yet.
See Using a single-header C library from Zig - #2 by IntegratedQuantum for an explanation on how to deal with header-only libraries in zig.

Created a enet_impl.c with these two lines:

#define ENET_IMPLEMENTATION
#include <enet.h>

Removed the @cdefine line from main.
Added this line to build.zig below addIncludePath:

    exe.addCSourceFiles(&[_][]const u8{"src/enet_impl.c"}, &[_][]const u8{ "-g", "-O3" });

Still getting the same error, just moved to the C file:

zig build-exe init-exe Debug native: error: error(compilation): clang failed with stderr: In file included from (root)\src\enet_impl.c:2:
(root)\libs/enet.h:4978:23: error: use of undeclared identifier 'CLOCK_MONOTONIC'

the error seems to hint at a problem that you haven’t solved yet: it expects a CLOCK_MONOTONIC to be defined, while it’s not. you probably are missing an expected import.

Are you linking libc when building Zig? When building against the C standard library you need to add the -lc flag to calls to zig build-exe or add something along the lines of exe.linkLibC() to your build.zig.

The CLOCK_MONOTONIC definition should be included from time.h so I expect that the undeclared identifier comes from cInclude not knowing how to find time.h.

OP is indeed linking to libc, you can see that line in the build script. That said, if that symbol is defined in time.h, then it might simply be a matter of cInclude-ing it before enet.h.

Oh, of course. Hmm, but as it it is included inside enet.h shouldn’t an extra include not be needed? The library seems to build and work fine for me with just a single cInclude("enet.h"). I am on x86_64-linux though.

Maybe you need a #define to enable that symbol? For example:

#define _POSIX_C_SOURCE 199309L

the error seems to hint at a problem that you haven’t solved yet: it expects a CLOCK_MONOTONIC to be defined, while it’s not. you probably are missing an expected import.

Certainly, but that doesn’t help if I can’t figure out what import that is. I should have mentioned in the OP I’ve tried stdio.h, time.h, and windows.h .None have helped

The library seems to build and work fine for me

That’s interesting to note. Don’t have a linux enviornment to test on myself

Maybe you need a #define to enable that symbol? For example:

Attempted, did not work

Found an instance of someone else attempting to link this same library, after including

 exe.addCSourceFiles(&[_][]const u8{"src/enet_impl.c"}, &[_][]const u8{ "-DCLOCK_MONOTONIC=0", "-DHAS_FCNTL=1", "-DHAS_POLL=1", "-DHAS_GETNAMEINFO=1", "-DHAS_GETADDRINFO=1", "-DHAS_GETHOSTBYNAME_R=1", "-DHAS_GETHOSTBYADDR_R=1", "-DHAS_INET_PTON=1", "-DHAS_INET_NTOP=1", "-DHAS_MSGHDR_FLAGS=1", "-DHAS_SOCKLEN_T=1", "-fno-sanitize=undefined", "-D_WIN32" });

The monotonic error is solved, now replaced by the error

error: lld-link: undefined symbol: IN6_IS_ADDR_V4MAPPED

According to zig cc mingw libraries missing libws2_32.a · Issue #9364 · ziglang/zig · GitHub
This is an issue with the language itself. I have wasted a lot of time.

1 Like

Good to see that you found a solution. A lot of C/C++ projects have these kinds of quirks to them. Tiny inconsistencies between different platforms, things getting occasionally out of sync, etc.

The only solution is just to learn how to deal with them systematically… or to wait for somebody else to create a build.zig file and package the library for you.

Welcome to the bleeding edge of systems programming!

Although this is not exactly a flaw with the language, but a missing piece in the toolchain. Without Zig you would have had to procure the entirety of the required headers and libs on your own, and in this case you got most of them, just not all.

If you look at the thread on GH there’s a PR that aims to solve this problem, so a kind contributor has already done some work to solve your problem, it just hasn’t been merged yet.

So my suggestion is to subscribe to that PR and wait for it to be merged.

As an optional step, you could also check out that branch, build Zig from it, and use the PR even without it being merged, the problem in this case is that it seems to have incurred in some regressions (CI is red on most hosts), so you probably won’t get a working source tree right away, but it might also be that those are easy fixes, so it might prove a viable path afterall.

3 Likes