If you aren’t developing a Zig package meant for consumption by others (i.e. you’re compiling an executable), it’s probably easiest to use different branches like @pachde suggests. (But it’s even easier to just pick one target and stick to that.)
If you are developing a package and you only want to maintain one branch that works with multiple Zig versions (e.g. the latest tagged release and master) instead of two that target different Zig versions, there are two main tools you can use:
Use reflection builtins like @hasDecl, @hasField, @FieldType@TypeOf, @typeInfo etc. to detect features added to/removed from/changed in master:
if (@hasDecl(std.Build.Step.ConfigHeader, "addIdent")) {
build_config_h.addIdent(name, value);
} else {
// TODO: Remove after 0.16.0
build_config_h.values.put(name, .{ .ident = value }) catch @panic("OOM");
}
Use @import("builtin").zig_version:
if (@import("builtin").zig_version.major <= 15) { // TODO: Remove after 0.16
// Fix "duplicate symbol" errors by redefining a problematic weak symbol definition in
// wchar.h which was introduced in Windows SDK version 10.0.26100.0 and which LLVM 20
// doesn't understand how to handle.
sdl_mod.addCMacro("_Avx2WmemEnabledWeakValue", "_Avx2WmemEnabled");
}
Both of these examples are from an older revision of my SDL3 Zig package, which has always supported the latest tagged release and master for as long as it has existed.
Feature detection using reflection I usually find easier to write and maintain because then you won’t need to look up the exact revision of Zig master a particular breaking change was introduced in. But zig_version is useful if there’s some feature within the Zig toolchain itself (as opposed to the std API) that doesn’t work the same in both versions, such as a miscompilation or a change in translate-c.
You mean like keep 2 versions of your project? One version of your project for Zig main on one branch and another branch for another version of Zig? Seems dicey trying to manage different versions like that…
The other answers are good, but I also want to point out that for this particular case, you can just keep using std.fmt.allocPrint. It shouldn’t be deleted until sometime between 0.17.0 and 0.18.0 (and by that time Allocator.print will work on both 0.17.0 and latest main, so switch to it then)