// Majora's Screensaver (expects zig v0.15.x) // @author: Abner Coimbre // @description: Sample C app for Windows, Mac & Linux. Adapted from floooh's sokol examples. // The goal is to demonstrate how to write a cross-platform native app/game in vanilla C, using only Zig to compile. // Single-Header Libraries: // - Sokol (https://github.com/floooh/sokol): Windowing, input, and/or graphics // - STB (https://github.com/nothings/stb): Loading images/assets // Instructions // --- // 1. Ensure Zig is on your PATH: download from https://ziglang.org/download // 2. Navigate to this project's folder // 3. Run the `zig build` command // 4. For a macOS App Bundle try `zig build bundle` instead // --- // You may now run the executable under zig-out/ // The command `zig build` executes build() below. Learn more at https://zig.guide/ const std = @import("std"); pub fn build(b: *std.Build) void { // Initial exe const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "screensaver", .root_module = b.createModule(.{ .optimize = optimize, .target = target, }), }); // Compiler flags: update as needed const win_flags = &[_][]const u8{ "-DSOKOL_D3D11", "-O0", "-ggdb3", "-std=c99", "-Werror", // Without this we can't emit warnings. This is a Zig bug: https://github.com/ziglang/zig/issues/15912 }; const macos_flags = &[_][]const u8{ "-ObjC", "-DSOKOL_METAL", "-O0", "-ggdb3", "-std=c99", "-Werror", }; const linux_flags = &[_][]const u8{ "-DSOKOL_GLCORE", "-O0", "-ggdb3", "-std=c99", "-Werror", }; // Add include folder(s) exe.addIncludePath(b.path("inc")); exe.addIncludePath(b.path("data/shaders")); // Which OS are we in? const tag = target.result.os.tag; // Select appropriate compiler flags const target_flags = switch (tag) { .windows => win_flags, .macos => macos_flags, .linux => linux_flags, else => { std.debug.print("Error: Unsupported OS! Contact abner@terminal.click\n", .{}); std.process.exit(1); }, }; // Add our source code exe.addCSourceFile(.{ .file = b.path("main.c"), .flags = target_flags }); // Link against C's standard library exe.linkLibC(); // Link against appropriate system libraries switch (tag) { .windows => { exe.linkSystemLibrary("kernel32"); exe.linkSystemLibrary("gdi32"); exe.linkSystemLibrary("d3d11"); }, .macos => { exe.linkFramework("MetalKit"); exe.linkFramework("Metal"); exe.linkFramework("Cocoa"); exe.linkFramework("QuartzCore"); }, .linux => { exe.linkSystemLibrary("GL"); exe.linkSystemLibrary("X11"); exe.linkSystemLibrary("Xi"); exe.linkSystemLibrary("Xcursor"); }, else => unreachable, } b.installArtifact(exe); // // macOS App Bundle - prepares one if user called `zig build bundle` // // --- if (tag == .macos) { const app_name = "Screensaver"; const bundle_path = b.fmt("zig-out/{s}.app/Contents", .{app_name}); const mkdir = b.addSystemCommand(&.{ "mkdir", "-p", b.fmt("{s}/MacOS", .{bundle_path}), }); const mkdir_res = b.addSystemCommand(&.{ "mkdir", "-p", b.fmt("{s}/Resources", .{bundle_path}), }); const copy_exe = b.addSystemCommand(&.{ "cp", b.getInstallPath(.bin, "screensaver"), b.fmt("{s}/MacOS/screensaver", .{bundle_path}), }); copy_exe.step.dependOn(&mkdir.step); copy_exe.step.dependOn(b.getInstallStep()); const plist_content = \\ \\ \\ \\ \\ CFBundleExecutable \\ screensaver \\ CFBundleIdentifier \\ click.terminal.screensaver \\ CFBundleName \\ Screensaver \\ CFBundlePackageType \\ APPL \\ CFBundleVersion \\ 1.0 \\ \\ ; const write_files = b.addWriteFiles(); const plist_file = write_files.add("Info.plist", plist_content); const copy_plist = b.addInstallFile(plist_file, b.fmt("{s}.app/Contents/Info.plist", .{app_name})); const copy_data = b.addSystemCommand(&.{ "cp", "-R", "data", b.fmt("{s}/Resources/", .{bundle_path}), }); copy_data.step.dependOn(&mkdir_res.step); const bundle_step = b.step("bundle", "Create macOS app bundle"); bundle_step.dependOn(©_exe.step); bundle_step.dependOn(©_plist.step); bundle_step.dependOn(&mkdir_res.step); bundle_step.dependOn(©_data.step); bundle_step.dependOn(©_plist.step); } // --- // // We're done! Complete Zig's build graph // //--- const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); } const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); //--- }