From 79b430da24a5f2214aa00f1b893f0191a5ad623c 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 efaca2e5ea..cf07455d03 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 9160d526ad..673a34447e 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 4d303dbced..628912d4a4 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 cadfe0ce6b..0000000000 --- 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 4f71e6f41a..dc85e02ced 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 7e9717627b..0000000000 --- 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 759ed184d0..5d5e46dc06 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 5fdad3648f..0000000000 --- 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 293ff105ea..89b8183620 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 80614a1fe7..0000000000 --- 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 214853d11f..470ebfeca6 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 e489a20016..0000000000 --- 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 1ff6746d7e..f44f3aab06 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 e489a20016..0000000000 --- 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 d5876a8c0e..91994f10a2 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 5fdad3648f..0000000000 --- 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 62d6d32311..89753b59be 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 420f89fe82..0000000000 --- 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 cadfe0ce6b..6a9646463e 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);