Comptime system calls

Why does this fail?

const timestamp = comptime std.time.timestamp();

Here’s the message it gives me:

$ zig build run
run
└─ run comptime_cross_compile
   └─ install
      └─ install comptime_cross_compile
         └─ zig build-exe comptime_cross_compile Debug native-native 1 errors
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/os/linux.zig:1507:21: error: unable to evaluate comptime expression
        const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/os/linux.zig:1507:52: note: operation is runtime due to this operand
        const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
                                                   ^~~~~~~~~~~~~~~~~~~
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/posix.zig:5721:39: note: called at comptime from here
    switch (errno(system.clock_gettime(clock_id, &tp))) {
                  ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/time.zig:68:43: note: called at comptime from here
            const ts = posix.clock_gettime(.REALTIME) catch |err| switch (err) {
                       ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/time.zig:29:53: note: called at comptime from here
    return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_ms)));
                                       ~~~~~~~~~~~~~^~
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/std/time.zig:20:36: note: called at comptime from here
    return @divFloor(milliTimestamp(), ms_per_s);
                     ~~~~~~~~~~~~~~^~
src/main.zig:18:43: note: called at comptime from here
 const timestamp = comptime std.time.timestamp();
                        ~~~~~~~~~~~~~~~~~~^~
src/main.zig:18:16: note: 'comptime' keyword forces comptime evaluation
 const timestamp = comptime std.time.timestamp();
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the following command failed with 1 compilation errors:
/gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/bin/zig build-exe -ODebug -target native-native -mcpu baseline --dep comptime_cross_compile_lib -Mroot=/mnt/store/Projects/Zig language/comptime-cross-compile/src/main.zig -ODebug -target native-native -mcpu baseline -Mcomptime_cross_compile_lib=/mnt/store/Projects/Zig language/comptime-cross-compile/src/root.zig --cache-dir /mnt/store/Projects/Zig language/comptime-cross-compile/.zig-cache --global-cache-dir /home/dan/.cache/zig --name comptime_cross_compile --zig-lib-dir /gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig/ --listen=- 
Build Summary: 2/7 steps succeeded; 1 failed
run transitive failure
└─ run comptime_cross_compile transitive failure
   ├─ zig build-exe comptime_cross_compile Debug native-native 1 errors
   └─ install transitive failure
      └─ install comptime_cross_compile transitive failure
         └─ zig build-exe comptime_cross_compile Debug native-native (reused)
error: the following build command failed with exit code 1:
/mnt/store/Projects/Zig language/comptime-cross-compile/.zig-cache/o/4b7643883ee70484ee4b79392b35c6d9/build /gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/bin/zig /gnu/store/76f996h4854np3g8i0n97hhi5nl1dp67-zig-0.14.0/lib/zig /mnt/store/Projects/Zig language/comptime-cross-compile /mnt/store/Projects/Zig language/comptime-cross-compile/.zig-cache /home/dan/.cache/zig --seed 0x894cdc02 -Z5e045d9c41cd3489 run

in the documentation it says:

It doesn’t make sense that a program could call exit() (or any other external function) at compile-time, …

But why not? Why not allow the call to an OS agnostic library call like std.time.timestamp()?

For context, I ran into this issue because I wanted to add a debug log message that included the time and date of the last compilation. in C++ I would use the __DATE__ and __TIME__ predefined macros

this should be doable via build.zig.

3 Likes
6 Likes

More specifically, with something like this:

const options = b.addOptions();
options.addOption(i64, "timestamp", std.time.timestamp());

And then

const exe_mod = b.createModule(.{...});
exe_mod.addOptions("buildenv", options);

Then in Zig source code you can @import("buildenv") and access it’s timestamp-field.

4 Likes

Won’t this break caching?

You now have a constant that always differs between builds being injected into your codebase.

1 Like

Yeah, it probably does. I did not think of that. But making the build process depend on system time is also bad from the perspective of build reproducibility.

Thanks for the details @andrewrk . Makes sense!

Thanks for the workaround @gustafla . This works great for my use-case.

I can confirm @tsdtas that this does break caching, but this is acceptable in my use-case: it is used to add a timestamp to the startup logs of my program during short bursts of active development. Specifically to the startup of a microcontroller, where it’s easy to have multiple of them being tested at the same time, it’s useful to know when it was programmed with a specific version of the code in terms of a timeframe (was it programmed 1 hour ago? 2 days ago?). Not planning on having this on in the long term though: after development stabilises I’ll switch to using some git tag derived semver string (which should lead to cacheable builds?)

6 Likes