mach-sysaudio moves back into the main repository

Helps hexops/mach#1165

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-03-04 18:45:52 -07:00 committed by Stephen Gutekanst
parent bca1543391
commit e77a5a2ca2
4 changed files with 196 additions and 52 deletions

View file

@ -37,12 +37,22 @@ jobs:
run: zig build -Dtarget=x86_64-windows-gnu
- name: launch xvfb
run: Xvfb :99 -screen 0 1680x720x24 > /dev/null 2>&1 &
- name: test
# TODO: do we actually need this?
- name: install Linux dependencies
run: |
sudo add-apt-repository -y ppa:kisak/kisak-mesa
sudo apt-get update
sudo apt-get install mesa-utils mesa-utils-extra mesa-va-drivers mesa-vdpau-drivers mesa-vulkan-drivers xvfb pulseaudio jackd
zig build test
- name: test
run: zig build test
- name: test (with core deps only)
run: zig build -Dcore test
- name: test (with sysaudio deps only)
run: zig build -Dsysaudio test
- name: test (with sysgpu deps only)
run: zig build -Dsysgpu test
- name: test (specific deps only)
run: zig build -Dcore -Dsysaudio -Dsysgpu test
x86_64-windows:
runs-on: windows-latest
# We want to run on external PRs, but not on our own internal PRs as they'll be run by the push

169
build.zig
View file

@ -1,20 +1,65 @@
const std = @import("std");
const builtin = @import("builtin");
const glfw = @import("mach_glfw");
const sysaudio = @import("mach_sysaudio");
const core = @import("mach_core");
var _module: ?*std.Build.Module = null;
/// Examples:
///
/// `zig build` -> builds all of Mach
/// `zig build test` -> runs all tests
///
/// ## (optional) minimal dependency fetching
///
/// By default, all Mach dependencies will be added to the build. If you only depend on a specific
/// part of Mach, then you can opt to have only the dependencies you need fetched as part of the
/// build:
///
/// ```
/// b.dependency("mach", .{
/// .target = target,
/// .optimize = optimize,
/// .core = true,
/// .sysaudio = true,
/// });
/// ```
///
/// The presense of `.core = true` and `.sysaudio = true` indicate Mach should add the dependencies
/// required by `@import("mach").core` and `@import("mach").sysaudio` to the build. You can use this
/// option with the following:
///
/// * core (also implies sysgpu)
/// * sysaudio
/// * sysgpu
///
/// Note that Zig's dead code elimination and, more importantly, lazy code evaluation means that
/// you really only pay for the parts of `@import("mach")` that you use/reference.
pub fn build(b: *std.Build) !void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const core_deps = b.option(bool, "core", "build core specifically");
const sysaudio_deps = b.option(bool, "sysaudio", "build sysaudio specifically");
const sysgpu_deps = b.option(bool, "sysgpu", "build sysgpu specifically");
const mach_core_dep = b.dependency("mach_core", .{
.target = target,
const want_mach = core_deps != null or sysaudio_deps != null or sysgpu_deps != null;
const want_core = want_mach or (core_deps orelse false);
const want_sysaudio = want_mach or (sysaudio_deps orelse false);
const want_sysgpu = want_mach or (sysgpu_deps orelse false);
const build_options = b.addOptions();
build_options.addOption(bool, "want_mach", want_mach);
build_options.addOption(bool, "want_core", want_core);
build_options.addOption(bool, "want_sysaudio", want_sysaudio);
build_options.addOption(bool, "want_sysgpu", want_sysgpu);
const module = b.addModule("mach", .{
.root_source_file = .{ .path = sdkPath("/src/main.zig") },
.optimize = optimize,
.target = target,
});
const mach_sysaudio_dep = b.dependency("mach_sysaudio", .{
module.addImport("build-options", build_options.createModule());
if (want_mach) {
// TODO(Zig 2024.03): use b.lazyDependency
const mach_core_dep = b.dependency("mach_core", .{
.target = target,
.optimize = optimize,
});
@ -32,18 +77,97 @@ pub fn build(b: *std.Build) !void {
});
const font_assets_dep = b.dependency("font_assets", .{});
const module = b.addModule("mach", .{
.root_source_file = .{ .path = sdkPath("/src/main.zig") },
.imports = &.{
.{ .name = "mach-core", .module = mach_core_dep.module("mach-core") },
.{ .name = "mach-sysaudio", .module = mach_sysaudio_dep.module("mach-sysaudio") },
.{ .name = "mach-basisu", .module = mach_basisu_dep.module("mach-basisu") },
.{ .name = "mach-freetype", .module = mach_freetype_dep.module("mach-freetype") },
.{ .name = "mach-harfbuzz", .module = mach_freetype_dep.module("mach-harfbuzz") },
.{ .name = "mach-sysjs", .module = mach_sysjs_dep.module("mach-sysjs") },
.{ .name = "font-assets", .module = font_assets_dep.module("font-assets") },
},
module.addImport("mach-core", mach_core_dep.module("mach-core"));
module.addImport("mach-basisu", mach_basisu_dep.module("mach-basisu"));
module.addImport("mach-freetype", mach_freetype_dep.module("mach-freetype"));
module.addImport("mach-harfbuzz", mach_freetype_dep.module("mach-harfbuzz"));
module.addImport("mach-sysjs", mach_sysjs_dep.module("mach-sysjs"));
module.addImport("font-assets", font_assets_dep.module("font-assets"));
}
if (want_sysaudio) {
// Can build sysaudio examples if desired, then.
inline for ([_][]const u8{
"sine",
"record",
}) |example| {
const example_exe = b.addExecutable(.{
.name = "sysaudio-" ++ example,
.root_source_file = .{ .path = "src/sysaudio/examples/" ++ example ++ ".zig" },
.target = target,
.optimize = optimize,
});
example_exe.root_module.addImport("mach", module);
addPaths(&example_exe.root_module);
b.installArtifact(example_exe);
const example_compile_step = b.step("sysaudio-" ++ example, "Compile 'sysaudio-" ++ example ++ "' example");
example_compile_step.dependOn(b.getInstallStep());
const example_run_cmd = b.addRunArtifact(example_exe);
example_run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| example_run_cmd.addArgs(args);
const example_run_step = b.step("run-sysaudio-" ++ example, "Run '" ++ example ++ "' example");
example_run_step.dependOn(&example_run_cmd.step);
}
// Add sysaudio dependencies to the module.
// TODO(Zig 2024.03): use b.lazyDependency
const mach_sysjs_dep = b.dependency("mach_sysjs", .{
.target = target,
.optimize = optimize,
});
const mach_objc_dep = b.dependency("mach_objc", .{
.target = target,
.optimize = optimize,
});
module.addImport("sysjs", mach_sysjs_dep.module("mach-sysjs"));
module.addImport("objc", mach_objc_dep.module("mach-objc"));
if (target.result.isDarwin()) {
// Transitive dependencies, explicit linkage of these works around
// ziglang/zig#17130
module.linkSystemLibrary("objc", .{});
// Direct dependencies
module.linkFramework("AudioToolbox", .{});
module.linkFramework("CoreFoundation", .{});
module.linkFramework("CoreAudio", .{});
}
if (target.result.os.tag == .linux) {
// TODO(Zig 2024.03): use b.lazyDependency
const linux_audio_headers_dep = b.dependency("linux_audio_headers", .{
.target = target,
.optimize = optimize,
});
module.link_libc = true;
module.linkLibrary(linux_audio_headers_dep.artifact("linux-audio-headers"));
// TODO: for some reason this is not functional, a Zig bug (only when using this Zig package
// externally):
//
// module.addCSourceFile(.{
// .file = .{ .path = "src/pipewire/sysaudio.c" },
// .flags = &.{"-std=gnu99"},
// });
//
// error: unable to check cache: stat file '/Volumes/data/hexops/mach-flac/zig-cache//Volumes/data/hexops/mach-flac/src/pipewire/sysaudio.c' failed: FileNotFound
//
// So instead we do this:
const lib = b.addStaticLibrary(.{
.name = "sysaudio-pipewire",
.target = target,
.optimize = optimize,
});
lib.linkLibC();
lib.addCSourceFile(.{
.file = .{ .path = "src/pipewire/sysaudio.c" },
.flags = &.{"-std=gnu99"},
});
lib.linkLibrary(linux_audio_headers_dep.artifact("linux-audio-headers"));
module.linkLibrary(lib);
}
}
if (target.result.cpu.arch != .wasm32) {
// Creates a step for unit testing. This only builds the test executable
@ -57,6 +181,7 @@ pub fn build(b: *std.Build) !void {
while (iter.next()) |e| {
unit_tests.root_module.addImport(e.key_ptr.*, e.value_ptr.*);
}
addPaths(&unit_tests.root_module);
// Exposes a `test` step to the `zig build --help` menu, providing a way for the user to
// request running the unit tests.
@ -114,11 +239,6 @@ pub const App = struct {
var deps = std.ArrayList(std.Build.Module.Import).init(app_builder.allocator);
if (options.deps) |v| try deps.appendSlice(v);
try deps.append(.{ .name = "mach", .module = mach_mod });
const mach_sysaudio_dep = mach_builder.dependency("mach_sysaudio", .{
.target = options.target,
.optimize = options.optimize,
});
try deps.append(.{ .name = "mach-sysaudio", .module = mach_sysaudio_dep.module("mach-sysaudio") });
const mach_core_dep = mach_builder.dependency("mach_core", .{
.target = options.target,
@ -154,10 +274,15 @@ pub const App = struct {
.target = app.compile.root_module.resolved_target.?,
.optimize = app.compile.root_module.optimize.?,
}).artifact("mach-basisu"));
addPaths(app.compile);
}
}
};
pub fn addPaths(mod: *std.Build.Module) void {
if (mod.resolved_target.?.result.isDarwin()) @import("xcode_frameworks").addPaths(mod);
}
fn sdkPath(comptime suffix: []const u8) []const u8 {
if (suffix[0] != '/') @compileError("suffix must be an absolute path");
return comptime blk: {

View file

@ -19,10 +19,6 @@
.url = "https://pkg.machengine.org/mach-basisu/5a68105a5e503c7183aab481b7ec6ae16b996943.tar.gz",
.hash = "12204098c8d8d15a687068a3c0b15fe95d20f8fe074531e34e78f9dfe518cf86a67c",
},
.mach_sysaudio = .{
.url = "https://pkg.machengine.org/mach-sysaudio/ce8ab30dd300b822224d14997c58c06520b642c9.tar.gz",
.hash = "12203f0d4afc83bae8571434ff48a459732c15c9542df13e0a97baedc73212d355a1",
},
.mach_freetype = .{
.url = "https://pkg.machengine.org/mach-freetype/dc4a5d8ce14f8678f35bdaf197303091e22b1f27.tar.gz",
.hash = "122070070dd2c402d94c279d64d4a4d154691ad49f46fa2c24ed7c6e4e4f5c531477",
@ -35,5 +31,17 @@
.url = "https://github.com/hexops/font-assets/archive/6b43c160451e8fa5c64620ffb614929feacf2f5d.tar.gz",
.hash = "12202039304f0603a9706105788e450fd4f901c3e20eca28a52a2173879b14c606c7",
},
.linux_audio_headers = .{
.url = "https://pkg.machengine.org/linux-audio-headers/302c41dc4ab5fa292c3062e9e0d26c7f62652740.tar.gz",
.hash = "1220dc84528a0e298467bec65ab158426306961f08e7555eab9eef684ef126893689",
},
.xcode_frameworks = .{
.url = "https://pkg.machengine.org/xcode-frameworks/e7c2abbe28efbb5ae7f04e6c1ac6578a6d75bb67.tar.gz",
.hash = "1220432df3c74dc28bd6cc299e5c8317bc65a95219e6ebf40450c157d8c7a3ac54c0",
},
.mach_objc = .{
.url = "https://pkg.machengine.org/mach-objc/2b2a698e7f019e1599edb3eda4a974fa1fb07483.tar.gz",
.hash = "1220d708af437c2076d1a0482ac745b3c4507f4f41cc9f248ee78a3c297c41ee7c33",
},
},
}

View file

@ -1,19 +1,20 @@
// Core re-exports
pub const core = @import("mach-core");
pub const Timer = core.Timer;
const build_options = @import("build-options");
// Mach packages
pub const gpu = core.gpu;
pub const sysjs = @import("mach-sysjs");
pub const sysaudio = @import("mach-sysaudio");
// Core re-exports
pub const core = if (build_options.want_core) @import("mach-core") else struct {};
pub const Timer = if (build_options.want_core) core.Timer else struct {};
pub const gpu = if (build_options.want_core) core.gpu else struct {};
pub const sysjs = if (build_options.want_core) @import("mach-sysjs") else struct {};
// Mach standard library
pub const ecs = @import("ecs/main.zig");
pub const gamemode = @import("gamemode.zig");
pub const gfx = @import("gfx/main.zig");
pub const gfx = if (build_options.want_mach) @import("gfx/main.zig") else struct {};
pub const math = @import("math/main.zig");
pub const testing = @import("testing.zig");
pub const sysaudio = if (build_options.want_sysaudio) @import("sysaudio/main.zig") else struct {};
// Engine exports
pub const App = @import("engine.zig").App;
pub const Engine = @import("engine.zig").Engine;