Hey welcome to ziggit, there are multiple ways to achieve that, within your code you can do something like this 
const std = @import("std");
const builtin = @import("builtin");
fn windowsImpl() void {}
fn linuxImpl() void {}
fn macosImpl() void {}
pub fn myFunction() void {
switch (builtin.os.tag) {
.windows => windowsImpl(),
.linux => linuxImpl(),
.macos => macosImpl(),
}
}
pub fn main() !void {}
Basically the builtin module is given to you by the build system everything in there is comptime known variable that you can leverage in your code, things, like abi, os, etc that this code was compiled with.
Than you can also do some more of this kind of stuff in the build system
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "foobar",
.root_module = b.createModule(.{
.root_source_file = null,
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
const c_source_files: []const []const u8 = &.{
"src/foo.c",
"src/bar.c",
};
const linux_files: []const []const u8 = &.{
"src/linux.c",
};
const macos_files: []const []const u8 = &.{
"src/macos.c",
};
const windows_files: []const []const u8 = &.{
"src/windows.c",
};
switch (target.result.os.tag) {
.windows => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ windows_files,
.flags = &.{},
.language = .c,
});
},
.linux => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ linux_files,
.flags = &.{},
.language = .c,
});
},
.macos => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ macos_files,
.flags = &.{},
.language = .c,
});
},
else => unreachable,
}
b.installArtifact(exe);
}
This is probably not the best way to do, it but for the sake of simplicity here are an example.
You can also do it with CLI arguments if you fancy :
const Backend = enum {
opengl,
sld2,
vulkan,
};
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "foobar",
.root_module = b.createModule(.{
.root_source_file = null,
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
const backend_choice = b.option(Backend, "Backend", "Select a Backend") orelse .opengl;
const c_source_files: []const []const u8 = &.{
"src/foo.c",
"src/bar.c",
};
const vulkan_backend: []const []const u8 = &.{
"src/vulkan.c",
};
const sdl2_backend: []const []const u8 = &.{
"src/sdl2.c",
};
const opengl_backend: []const []const u8 = &.{
"src/opengl.c",
};
switch (backend_choice) {
.opengl => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ opengl_backend,
.flags = &.{},
.language = .c,
});
},
.sld2 => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ vulkan_backend,
.flags = &.{},
.language = .c,
});
},
.vulkan => {
exe.root_module.addCSourceFiles(.{
.files = c_source_files ++ sdl2_backend,
.flags = &.{},
.language = .c,
});
},
}
b.installArtifact(exe);
}
and if you look at the ouput of zig build --help :
you will see
-DBackend=[enum] Select a Backend
Supported Values:
opengl
sld2
vulkan