From b14f8e69ee8eb834695eb0d0582053e555d10156 Mon Sep 17 00:00:00 2001 From: Emi Date: Mon, 17 Feb 2025 20:51:42 -0700 Subject: [PATCH] build: add @import("mach").addExecutable helper This adds a helper that can be used people's `build.zig` code, called `@import("mach").addExecutable`, a direct replacement for `b.addExecutable`. The benefits of using this method are: 1. Your `build.zig` code does not need to be aware of platform-specifics that may be required to build an executable, for example setting a Windows manifest to ensure your app is DPI-aware. 2. You do not need to write `main.zig` entrypoint code, which although simple today is expected to become more complex over time as we add support for more platforms. For example, WASM and other platforms require different entrypoints and this can account for that without your `build.zig` containing that logic. Steps to use: 1. Delete your `main.zig` file. 2. Define your `Modules` as a public const in your `App.zig` file, e.g.: ```zig // The set of Mach modules our application may use. pub const Modules = mach.Modules(.{ mach.Core, App, }); ``` 3. Update your `build.zig` code to use `@import("mach").addExecutable` like so: ```zig const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const app_mod = b.createModule(.{ .root_source_file = b.path("src/App.zig"), .optimize = optimize, .target = target, }); // Add Mach to our library and executable const mach_dep = b.dependency("mach", .{ .target = target, .optimize = optimize, }); app_mod.addImport("mach", mach_dep.module("mach")); // Use the Mach entrypoint to write main for us const exe = @import("mach").addExecutable(mach_dep.builder, .{ .name = "hello-world", .app = app_mod, .target = target, .optimize = optimize, }); b.installArtifact(exe); 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); const app_unit_tests = b.addTest(.{ .root_module = app_mod, }); const run_app_unit_tests = b.addRunArtifact(app_unit_tests); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_app_unit_tests.step); } ``` Signed-off-by: Emi --- build.zig | 44 ++++++++++++++++--- examples/core-transparent-window/App.zig | 6 +++ examples/core-triangle/App.zig | 6 +++ examples/core-triangle/main.zig | 22 ---------- examples/custom-renderer/App.zig | 7 +++ examples/custom-renderer/main.zig | 23 ---------- examples/glyphs/App.zig | 7 +++ examples/glyphs/main.zig | 23 ---------- examples/hardware-check/App.zig | 9 ++++ examples/hardware-check/main.zig | 25 ----------- examples/piano/App.zig | 7 +++ examples/piano/main.zig | 23 ---------- examples/play-opus/App.zig | 7 +++ examples/play-opus/main.zig | 23 ---------- examples/sprite/App.zig | 7 +++ examples/sprite/main.zig | 23 ---------- examples/text/App.zig | 7 +++ examples/text/main.zig | 23 ---------- .../entrypoint}/main.zig | 10 +---- 19 files changed, 101 insertions(+), 201 deletions(-) delete mode 100644 examples/core-triangle/main.zig delete mode 100644 examples/custom-renderer/main.zig delete mode 100644 examples/glyphs/main.zig delete mode 100644 examples/hardware-check/main.zig delete mode 100644 examples/piano/main.zig delete mode 100644 examples/play-opus/main.zig delete mode 100644 examples/sprite/main.zig delete mode 100644 examples/text/main.zig rename {examples/core-transparent-window => src/entrypoint}/main.zig (54%) diff --git a/build.zig b/build.zig index efaca2e5..cf07455d 100644 --- a/build.zig +++ b/build.zig @@ -389,6 +389,34 @@ const Example = struct { run_step: *std.Build.Step = undefined, }; +pub fn addExecutable( + mach_builder: *std.Build, + options: struct { + name: []const u8, + app: *std.Build.Module, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + }, +) *std.Build.Step.Compile { + const entrypoint_mod = mach_builder.addModule( + mach_builder.fmt("{s}-entrypoint", .{options.name}), + .{ + .root_source_file = mach_builder.path("src/entrypoint/main.zig"), + .optimize = options.optimize, + .target = options.target, + }, + ); + entrypoint_mod.addImport("app", options.app); + + return mach_builder.addExecutable(.{ + .name = options.name, + .root_module = entrypoint_mod, + + // Win32 manifest file for DPI-awareness configuration + .win32_manifest = mach_builder.path("src/core/windows/win32.manifest"), + }); +} + fn buildExamples( b: *std.Build, optimize: std.builtin.OptimizeMode, @@ -397,14 +425,16 @@ fn buildExamples( examples: []Example, ) void { for (examples) |*example| { - const exe = b.addExecutable(.{ + const app_mod = b.addModule(example.name, .{ + .root_source_file = b.path(b.fmt("examples/{s}/App.zig", .{example.name})), + }); + app_mod.addImport("mach", mach_mod); + const exe = addExecutable(b, .{ .name = example.name, - .root_source_file = b.path(b.fmt("examples/{s}/main.zig", .{example.name})), + .app = app_mod, .target = target, .optimize = optimize, - .win32_manifest = b.path("src/core/windows/win32.manifest"), }); - exe.root_module.addImport("mach", mach_mod); for (example.deps) |d| { switch (d) { @@ -412,19 +442,19 @@ fn buildExamples( if (b.lazyDependency("mach_example_assets", .{ .target = target, .optimize = optimize, - })) |dep| exe.root_module.addImport("assets", dep.module("mach-example-assets")); + })) |dep| app_mod.addImport("assets", dep.module("mach-example-assets")); }, .freetype => { if (b.lazyDependency("mach_freetype", .{ .target = target, .optimize = optimize, - })) |dep| exe.root_module.addImport("freetype", dep.module("mach-freetype")); + })) |dep| app_mod.addImport("freetype", dep.module("mach-freetype")); }, .zigimg => { if (b.lazyDependency("zigimg", .{ .target = target, .optimize = optimize, - })) |dep| exe.root_module.addImport("zigimg", dep.module("zigimg")); + })) |dep| app_mod.addImport("zigimg", dep.module("zigimg")); }, } } diff --git a/examples/core-transparent-window/App.zig b/examples/core-transparent-window/App.zig index 9160d526..673a3444 100644 --- a/examples/core-transparent-window/App.zig +++ b/examples/core-transparent-window/App.zig @@ -4,6 +4,12 @@ const gpu = mach.gpu; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + @This(), +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit }; diff --git a/examples/core-triangle/App.zig b/examples/core-triangle/App.zig index 4d303dbc..628912d4 100644 --- a/examples/core-triangle/App.zig +++ b/examples/core-triangle/App.zig @@ -4,6 +4,12 @@ const gpu = mach.gpu; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit }; diff --git a/examples/core-triangle/main.zig b/examples/core-triangle/main.zig deleted file mode 100644 index cadfe0ce..00000000 --- a/examples/core-triangle/main.zig +++ /dev/null @@ -1,22 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/custom-renderer/App.zig b/examples/custom-renderer/App.zig index 4f71e6f4..dc85e02c 100644 --- a/examples/custom-renderer/App.zig +++ b/examples/custom-renderer/App.zig @@ -9,6 +9,13 @@ const Vec3 = math.Vec3; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + App, + @import("Renderer.zig"), +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .deinit, .tick }; diff --git a/examples/custom-renderer/main.zig b/examples/custom-renderer/main.zig deleted file mode 100644 index 7e971762..00000000 --- a/examples/custom-renderer/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - @import("App.zig"), - @import("Renderer.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/glyphs/App.zig b/examples/glyphs/App.zig index 759ed184..5d5e46dc 100644 --- a/examples/glyphs/App.zig +++ b/examples/glyphs/App.zig @@ -16,6 +16,13 @@ const Mat4x4 = math.Mat4x4; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.gfx.Sprite, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .deinit, .tick }; diff --git a/examples/glyphs/main.zig b/examples/glyphs/main.zig deleted file mode 100644 index 5fdad364..00000000 --- a/examples/glyphs/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.gfx.Sprite, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/hardware-check/App.zig b/examples/hardware-check/App.zig index 293ff105..89b81836 100644 --- a/examples/hardware-check/App.zig +++ b/examples/hardware-check/App.zig @@ -14,6 +14,15 @@ const Mat4x4 = math.Mat4x4; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.gfx.Sprite, + mach.gfx.Text, + mach.Audio, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit, .deinit2, .audioStateChange }; diff --git a/examples/hardware-check/main.zig b/examples/hardware-check/main.zig deleted file mode 100644 index 80614a1f..00000000 --- a/examples/hardware-check/main.zig +++ /dev/null @@ -1,25 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.gfx.Sprite, - mach.gfx.Text, - mach.Audio, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/piano/App.zig b/examples/piano/App.zig index 214853d1..470ebfec 100644 --- a/examples/piano/App.zig +++ b/examples/piano/App.zig @@ -18,6 +18,13 @@ const sysaudio = mach.sysaudio; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.Audio, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit, .audioStateChange }; diff --git a/examples/piano/main.zig b/examples/piano/main.zig deleted file mode 100644 index e489a200..00000000 --- a/examples/piano/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.Audio, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/play-opus/App.zig b/examples/play-opus/App.zig index 1ff6746d..f44f3aab 100644 --- a/examples/play-opus/App.zig +++ b/examples/play-opus/App.zig @@ -13,6 +13,13 @@ const sysaudio = mach.sysaudio; pub const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.Audio, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit, .audioStateChange }; diff --git a/examples/play-opus/main.zig b/examples/play-opus/main.zig deleted file mode 100644 index e489a200..00000000 --- a/examples/play-opus/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.Audio, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/sprite/App.zig b/examples/sprite/App.zig index d5876a8c..91994f10 100644 --- a/examples/sprite/App.zig +++ b/examples/sprite/App.zig @@ -15,6 +15,13 @@ const Mat4x4 = math.Mat4x4; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.gfx.Sprite, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit }; diff --git a/examples/sprite/main.zig b/examples/sprite/main.zig deleted file mode 100644 index 5fdad364..00000000 --- a/examples/sprite/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.gfx.Sprite, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/text/App.zig b/examples/text/App.zig index 62d6d323..89753b59 100644 --- a/examples/text/App.zig +++ b/examples/text/App.zig @@ -16,6 +16,13 @@ const Mat4x4 = math.Mat4x4; const App = @This(); +// The set of Mach modules our application may use. +pub const Modules = mach.Modules(.{ + mach.Core, + mach.gfx.Text, + App, +}); + pub const mach_module = .app; pub const mach_systems = .{ .main, .init, .tick, .deinit }; diff --git a/examples/text/main.zig b/examples/text/main.zig deleted file mode 100644 index 420f89fe..00000000 --- a/examples/text/main.zig +++ /dev/null @@ -1,23 +0,0 @@ -const std = @import("std"); -const mach = @import("mach"); - -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - mach.gfx.Text, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. -pub fn main() !void { - const allocator = std.heap.c_allocator; - - // The set of Mach modules our application may use. - var mods: Modules = undefined; - try mods.init(allocator); - // TODO: enable mods.deinit(allocator); for allocator leak detection - // defer mods.deinit(allocator); - - const app = mods.get(.app); - app.run(.main); -} diff --git a/examples/core-transparent-window/main.zig b/src/entrypoint/main.zig similarity index 54% rename from examples/core-transparent-window/main.zig rename to src/entrypoint/main.zig index cadfe0ce..6a964646 100644 --- a/examples/core-transparent-window/main.zig +++ b/src/entrypoint/main.zig @@ -1,18 +1,10 @@ const std = @import("std"); -const mach = @import("mach"); -// The set of Mach modules our application may use. -const Modules = mach.Modules(.{ - mach.Core, - @import("App.zig"), -}); - -// TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. pub fn main() !void { const allocator = std.heap.c_allocator; // The set of Mach modules our application may use. - var mods: Modules = undefined; + var mods: @import("app").Modules = undefined; try mods.init(allocator); // TODO: enable mods.deinit(allocator); for allocator leak detection // defer mods.deinit(allocator);