How to write compat shim for builtin function changes (e.g. `@abs` vs `@fabs`)?

I want code that temporarily supports both Zig 0.11.x and the upcoming 0.12.0. Normally, I can write compatibility shims that use comptime:

if (@hasDecl(foo, "newThing"))
    foo.newThing()
else
    foo.oldThing();

I have not been able to get this pattern to work with the @fabs to @abs change though. Zig 0.11.0 complains that @abs does not exist, and 0.12.0-dev does the same for @fabs. Am I missing something?

test "abs compat shim" {
    const x: f32 = 1.0;
    if (@import("builtin").zig_version.major > 11) {
        _ = @abs(x);
    } else {
        _ = @fabs(x);
    }
}
1 Like

Interesting problem, it seems that the builtin calls are name checked during the AstGen step and so it complains before evaluating the comptime if.

I was able to get the following to work using a conditional module in the build.zig:

// build.zig

pub fn build(b: *std.Built) void {
    //...
    const abs = if (@import("builtin").zig_version.minor > 11)
        b.addModule("abs", .{ .source_file = .{ .path = "src/abs.zig" } })
    else
        b.addModule("abs", .{ .source_file = .{ .path = "src/fabs.zig" } });
    exe.addModule("abs", abs);
    //...
}
// src/abs.zig
pub inline fn abs(a: anytype) @TypeOf(@abs(a)) {
    return @abs(a);
}
// src/fabs.zig
pub inline fn abs(a: anytype) @TypeOf(@fabs(a)) {
    return @fabs(a);
}
5 Likes