all: build: organize build files and reduce unreachables (#567)

This commit is contained in:
Ali Chraghi 2022-09-25 20:32:51 +03:30 committed by GitHub
parent 3bb1357299
commit 56b6222b2f
2 changed files with 55 additions and 53 deletions

View file

@ -20,20 +20,20 @@ There are 130+ tests, and CI tests on all major platforms as well as cross-compi
Why create a ziggified GLFW wrapper, instead of just using `@cImport` and interfacing with GLFW directly? You get: Why create a ziggified GLFW wrapper, instead of just using `@cImport` and interfacing with GLFW directly? You get:
* Errors as [zig errors](https://ziglang.org/documentation/master/#Errors) instead of via a callback function. - Errors as [zig errors](https://ziglang.org/documentation/master/#Errors) instead of via a callback function.
* `true` and `false` instead of `c.GLFW_TRUE` and `c.GLFW_FALSE` constants. - `true` and `false` instead of `c.GLFW_TRUE` and `c.GLFW_FALSE` constants.
* Generics, so you can just use `window.hint` instead of `glfwWindowHint`, `glfwWindowHintString`, etc. - Generics, so you can just use `window.hint` instead of `glfwWindowHint`, `glfwWindowHintString`, etc.
* **Enums**, always know what value a GLFW function can accept as everything is strictly typed. And use the nice Zig syntax to access enums, like `window.getKey(.escape)` instead of `c.glfwGetKey(window, c.GLFW_KEY_ESCAPE)` - **Enums**, always know what value a GLFW function can accept as everything is strictly typed. And use the nice Zig syntax to access enums, like `window.getKey(.escape)` instead of `c.glfwGetKey(window, c.GLFW_KEY_ESCAPE)`
* Slices instead of C pointers and lengths. - Slices instead of C pointers and lengths.
* [packed structs](https://ziglang.org/documentation/master/#packed-struct) represent bit masks, so you can use `if (joystick.down and joystick.right)` instead of `if (joystick & c.GLFW_HAT_DOWN and joystick & c.GLFW_HAT_RIGHT)`, etc. - [packed structs](https://ziglang.org/documentation/master/#packed-struct) represent bit masks, so you can use `if (joystick.down and joystick.right)` instead of `if (joystick & c.GLFW_HAT_DOWN and joystick & c.GLFW_HAT_RIGHT)`, etc.
* Methods, e.g. `my_window.hint(...)` instead of `glfwWindowHint(my_window, ...)` - Methods, e.g. `my_window.hint(...)` instead of `glfwWindowHint(my_window, ...)`
## How do I use OpenGL, Vulkan, WebGPU, etc. with this? ## How do I use OpenGL, Vulkan, WebGPU, etc. with this?
You'll need to bring your own library for this. Some are: You'll need to bring your own library for this. Some are:
* (Vulkan) https://github.com/Snektron/vulkan-zig (also see https://github.com/Avokadoen/zig_vulkan) - (Vulkan) https://github.com/Snektron/vulkan-zig (also see https://github.com/Avokadoen/zig_vulkan)
* (OpenGL) https://github.com/ziglibs/zgl - (OpenGL) https://github.com/ziglibs/zgl
## Examples ## Examples
@ -57,10 +57,10 @@ Then in your `build.zig` add:
... ...
const glfw = @import("libs/mach-glfw/build.zig"); const glfw = @import("libs/mach-glfw/build.zig");
pub fn build(b: *Builder) void { pub fn build(b: *Builder) !void {
... ...
exe.addPackage(glfw.pkg); exe.addPackage(glfw.pkg);
glfw.link(b, exe, .{}); try glfw.link(b, exe, .{});
} }
``` ```
@ -83,11 +83,11 @@ Then in your `build.zig` add:
const pkgs = @import("deps.zig").pkgs; const pkgs = @import("deps.zig").pkgs;
const glfw = @import("build-glfw"); const glfw = @import("build-glfw");
pub fn build(b: *Builder) void { pub fn build(b: *Builder) !void {
... ...
exe.addPackage(pkgs.glfw); exe.addPackage(pkgs.glfw);
glfw.link(b, exe, .{}); try glfw.link(b, exe, .{});
} }
``` ```
@ -134,11 +134,11 @@ const pos = window.getPos() catch |err| {
Here is a rough list of functionality Wayland does not support: Here is a rough list of functionality Wayland does not support:
* `Window.setIcon` - `Window.setIcon`
* `Window.setPos`, `Window.getPos` - `Window.setPos`, `Window.getPos`
* `Window.iconify`, `Window.focus` - `Window.iconify`, `Window.focus`
* `Monitor.setGamma` - `Monitor.setGamma`
* `Monitor.getGammaRamp`, `Monitor.setGammaRamp` - `Monitor.getGammaRamp`, `Monitor.setGammaRamp`
## Join the community ## Join the community

View file

@ -13,20 +13,20 @@ pub fn build(b: *Builder) void {
test_step.dependOn(&testStepShared(b, mode, target).step); test_step.dependOn(&testStepShared(b, mode, target).step);
} }
pub fn testStep(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *std.build.RunStep { pub fn testStep(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) !*std.build.RunStep {
const main_tests = b.addTestExe("glfw-tests", thisDir() ++ "/src/main.zig"); const main_tests = b.addTestExe("glfw-tests", thisDir() ++ "/src/main.zig");
main_tests.setBuildMode(mode); main_tests.setBuildMode(mode);
main_tests.setTarget(target); main_tests.setTarget(target);
link(b, main_tests, .{}); try link(b, main_tests, .{});
main_tests.install(); main_tests.install();
return main_tests.run(); return main_tests.run();
} }
fn testStepShared(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *std.build.RunStep { fn testStepShared(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) !*std.build.RunStep {
const main_tests = b.addTestExe("glfw-tests-shared", thisDir() ++ "/src/main.zig"); const main_tests = b.addTestExe("glfw-tests-shared", thisDir() ++ "/src/main.zig");
main_tests.setBuildMode(mode); main_tests.setBuildMode(mode);
main_tests.setTarget(target); main_tests.setTarget(target);
link(b, main_tests, .{ .shared = true }); try link(b, main_tests, .{ .shared = true });
main_tests.install(); main_tests.install();
return main_tests.run(); return main_tests.run();
} }
@ -79,10 +79,11 @@ fn cimportWorkaround() void {
std.fs.cwd().copyFile(cn_path, dest_dir, thisDir() ++ "/src/c_native.zig", .{}) catch unreachable; std.fs.cwd().copyFile(cn_path, dest_dir, thisDir() ++ "/src/c_native.zig", .{}) catch unreachable;
} }
pub fn link(b: *Builder, step: *std.build.LibExeObjStep, options: Options) void { pub const LinkError = error{FailedToLinkGPU} || BuildError;
pub fn link(b: *Builder, step: *std.build.LibExeObjStep, options: Options) LinkError!void {
cimportWorkaround(); cimportWorkaround();
const lib = buildLibrary(b, step.build_mode, step.target, options); const lib = try buildLibrary(b, step.build_mode, step.target, options);
step.linkLibrary(lib); step.linkLibrary(lib);
addGLFWIncludes(step); addGLFWIncludes(step);
if (options.shared) { if (options.shared) {
@ -93,9 +94,10 @@ pub fn link(b: *Builder, step: *std.build.LibExeObjStep, options: Options) void
} }
} }
fn buildLibrary(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget, options: Options) *std.build.LibExeObjStep { pub const BuildError = error{CannotEnsureDependency} || std.mem.Allocator.Error;
fn buildLibrary(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget, options: Options) BuildError!*std.build.LibExeObjStep {
// TODO(build-system): https://github.com/hexops/mach/issues/229#issuecomment-1100958939 // TODO(build-system): https://github.com/hexops/mach/issues/229#issuecomment-1100958939
ensureDependencySubmodule(b.allocator, "upstream") catch unreachable; ensureDependencySubmodule(b.allocator, "upstream") catch return error.CannotEnsureDependency;
const lib = if (options.shared) const lib = if (options.shared)
b.addSharedLibrary("glfw", null, .unversioned) b.addSharedLibrary("glfw", null, .unversioned)
@ -108,7 +110,7 @@ fn buildLibrary(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget
lib.defineCMacro("_GLFW_BUILD_DLL", null); lib.defineCMacro("_GLFW_BUILD_DLL", null);
addGLFWIncludes(lib); addGLFWIncludes(lib);
addGLFWSources(b, lib, options); try addGLFWSources(b, lib, options);
linkGLFWDependencies(b, lib, options); linkGLFWDependencies(b, lib, options);
if (options.install_libs) if (options.install_libs)
@ -122,7 +124,7 @@ fn addGLFWIncludes(step: *std.build.LibExeObjStep) void {
step.addIncludePath(thisDir() ++ "/upstream/vulkan_headers/include"); step.addIncludePath(thisDir() ++ "/upstream/vulkan_headers/include");
} }
fn addGLFWSources(b: *Builder, lib: *std.build.LibExeObjStep, options: Options) void { fn addGLFWSources(b: *Builder, lib: *std.build.LibExeObjStep, options: Options) std.mem.Allocator.Error!void {
const include_glfw_src = "-I" ++ thisDir() ++ "/upstream/glfw/src"; const include_glfw_src = "-I" ++ thisDir() ++ "/upstream/glfw/src";
switch (lib.target_info.target.os.tag) { switch (lib.target_info.target.os.tag) {
.windows => lib.addCSourceFiles(&.{ .windows => lib.addCSourceFiles(&.{
@ -143,42 +145,25 @@ fn addGLFWSources(b: *Builder, lib: *std.build.LibExeObjStep, options: Options)
// ``` // ```
var sources = std.ArrayList([]const u8).init(b.allocator); var sources = std.ArrayList([]const u8).init(b.allocator);
var flags = std.ArrayList([]const u8).init(b.allocator); var flags = std.ArrayList([]const u8).init(b.allocator);
sources.append(thisDir() ++ "/src/sources_all.c") catch unreachable; try sources.append(thisDir() ++ "/src/sources_all.c");
sources.append(thisDir() ++ "/src/sources_linux.c") catch unreachable; try sources.append(thisDir() ++ "/src/sources_linux.c");
if (options.x11) { if (options.x11) {
sources.append(thisDir() ++ "/src/sources_linux_x11.c") catch unreachable; try sources.append(thisDir() ++ "/src/sources_linux_x11.c");
flags.append("-D_GLFW_X11") catch unreachable; try flags.append("-D_GLFW_X11");
} }
if (options.wayland) { if (options.wayland) {
sources.append(thisDir() ++ "/src/sources_linux_wayland.c") catch unreachable; try sources.append(thisDir() ++ "/src/sources_linux_wayland.c");
flags.append("-D_GLFW_WAYLAND") catch unreachable; try flags.append("-D_GLFW_WAYLAND");
} }
flags.append("-I" ++ thisDir() ++ "/upstream/glfw/src") catch unreachable; try flags.append("-I" ++ thisDir() ++ "/upstream/glfw/src");
// TODO(upstream): glfw can't compile on clang15 without this flag // TODO(upstream): glfw can't compile on clang15 without this flag
flags.append("-Wno-implicit-function-declaration") catch unreachable; try flags.append("-Wno-implicit-function-declaration");
lib.addCSourceFiles(sources.items, flags.items); lib.addCSourceFiles(sources.items, flags.items);
}, },
} }
} }
fn ensureDependencySubmodule(allocator: std.mem.Allocator, path: []const u8) !void {
if (std.process.getEnvVarOwned(allocator, "NO_ENSURE_SUBMODULES")) |no_ensure_submodules| {
defer allocator.free(no_ensure_submodules);
if (std.mem.eql(u8, no_ensure_submodules, "true")) return;
} else |_| {}
var child = std.ChildProcess.init(&.{ "git", "submodule", "update", "--init", path }, allocator);
child.cwd = thisDir();
child.stderr = std.io.getStdErr();
child.stdout = std.io.getStdOut();
_ = try child.spawnAndWait();
}
inline fn thisDir() []const u8 {
return comptime std.fs.path.dirname(@src().file) orelse ".";
}
fn linkGLFWDependencies(b: *Builder, step: *std.build.LibExeObjStep, options: Options) void { fn linkGLFWDependencies(b: *Builder, step: *std.build.LibExeObjStep, options: Options) void {
step.linkLibC(); step.linkLibC();
system_sdk.include(b, step, options.system_sdk); system_sdk.include(b, step, options.system_sdk);
@ -217,3 +202,20 @@ fn linkGLFWDependencies(b: *Builder, step: *std.build.LibExeObjStep, options: Op
}, },
} }
} }
fn ensureDependencySubmodule(allocator: std.mem.Allocator, path: []const u8) !void {
if (std.process.getEnvVarOwned(allocator, "NO_ENSURE_SUBMODULES")) |no_ensure_submodules| {
defer allocator.free(no_ensure_submodules);
if (std.mem.eql(u8, no_ensure_submodules, "true")) return;
} else |_| {}
var child = std.ChildProcess.init(&.{ "git", "submodule", "update", "--init", path }, allocator);
child.cwd = thisDir();
child.stderr = std.io.getStdErr();
child.stdout = std.io.getStdOut();
_ = try child.spawnAndWait();
}
inline fn thisDir() []const u8 {
return comptime std.fs.path.dirname(@src().file) orelse ".";
}