Something went wrong. Try again.
A pure Zig PipeWire client library that speaks the native wire protocol to play audio and manage the graph, with no libpipewire and no libc.
Something went wrong. Try again.
zig-pipewire build.zig
5.0 kB · 121 lines
Zig
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
const std = @import("std");
pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
const mod = b.addModule("pipewire", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, });
const examples = [_]struct { name: []const u8, path: []const u8, desc: []const u8 }{ .{ .name = "tone", .path = "examples/tone.zig", .desc = "Play a test tone (push API)" }, .{ .name = "chord", .path = "examples/callback.zig", .desc = "Play a chord (pull API)" }, .{ .name = "session", .path = "examples/session.zig", .desc = "List and change the graph" }, .{ .name = "pause", .path = "examples/pause.zig", .desc = "Pause and unpause a stream, playing silence" }, .{ .name = "latency", .path = "examples/latency.zig", .desc = "Say how far away the sink is, playing silence" }, };
for (examples) |example| { const exe = b.addExecutable(.{ .name = b.fmt("pw-{s}", .{example.name}), .root_module = b.createModule(.{ .root_source_file = b.path(example.path), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "pipewire", .module = mod }, }, }), }); b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); run_cmd.addPassthruArgs(); const run_step = b.step(b.fmt("run-{s}", .{example.name}), example.desc); run_step.dependOn(&run_cmd.step); }
const test_step = b.step("test", "Run tests");
const mod_tests = b.addTest(.{ .root_module = mod, .use_llvm = true }); test_step.dependOn(&b.addRunArtifact(mod_tests).step);
// The fuzz targets, which are properties rather than examples: what the // library must do with bytes nobody wrote. They are ordinary tests as well // as fuzz tests — without `--fuzz` each one runs the corpus checked in // beside it, so `zig build test` exercises them every time. const fuzz_mod = b.createModule(.{ .root_source_file = b.path("tests/fuzz.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "pipewire", .module = mod }, }, });
// Zig's fuzzer takes one test at a time, so a run that is chasing a // particular target wants to build only that one: // `zig build fuzz --fuzz -Dfuzz-filter=pod`. const fuzz_filter = b.option( []const u8, "fuzz-filter", "Run only the fuzz target whose name matches", ); const fuzz_tests = b.addTest(.{ .root_module = fuzz_mod, .filters = if (fuzz_filter) |f| &.{f} else &.{}, // Coverage feedback needs LLVM: the self-hosted backend emits no // instrumentation, and the fuzzer then reports nothing. .use_llvm = true, }); test_step.dependOn(&b.addRunArtifact(fuzz_tests).step);
// And a step of their own, for `zig build fuzz --fuzz`, which needs a run // step holding nothing else: the fuzzer takes over the terminal. const fuzz_step = b.step("fuzz", "The fuzz targets: add --fuzz to fuzz them"); fuzz_step.dependOn(&b.addRunArtifact(fuzz_tests).step);
// The loop that drives those same targets without Zig's fuzzer, from a // corpus rather than from coverage; `tools/fuzz.zig` says why. Optimised, because a fuzzer's whole job is how // many inputs it gets through. const fuzz_run = b.addExecutable(.{ .name = "pw-fuzz", .root_module = b.createModule(.{ .root_source_file = b.path("tools/fuzz.zig"), .target = target, .optimize = .ReleaseSafe, .imports = &.{ .{ .name = "fuzz_targets", .module = fuzz_mod }, }, }), }); const fuzz_run_cmd = b.addRunArtifact(fuzz_run); fuzz_run_cmd.addPassthruArgs(); const fuzz_run_step = b.step("fuzz-run", "Drive the fuzz targets without Zig's fuzzer"); fuzz_run_step.dependOn(&fuzz_run_cmd.step);
// Benchmarks, always optimised: timing a Debug build measures the safety // checks rather than the code. const bench = b.addExecutable(.{ .name = "pw-bench", .root_module = b.createModule(.{ .root_source_file = b.path("tools/bench.zig"), .target = target, .optimize = .ReleaseFast, .imports = &.{ .{ .name = "pipewire", .module = mod }, }, }), }); const bench_cmd = b.addRunArtifact(bench); bench_cmd.addPassthruArgs(); const bench_step = b.step("bench", "Measure the hot paths and the graph cycle"); bench_step.dependOn(&bench_cmd.step);}