// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // Turning this off forces the scalar path even where the target could use // the vector kernels, which is useful for measuring what they buy and for // sidestepping them if a target ever miscompiles them. It cannot turn them // on where the CPU cannot support them: the target check in src/simd.zig // still has to agree. const simd = b.option( bool, "simd", "Use vectorised kernels where the target supports them (default: true)", ) orelse true; const options = b.addOptions(); options.addOption(bool, "simd", simd); // The library itself, exposed to consumers as `@import("zuucode")`. const mod = b.addModule("zuucode", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "build_options", .module = options.createModule() }, }, }); // A `uuencode`/`uudecode` command line tool built on top of the library. const exe = b.addExecutable(.{ .name = "zuucode", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "zuucode", .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("run", "Run the app"); run_step.dependOn(&run_cmd.step); // Test executables cover one module each, so the library and the command // line tool need one apiece. They are compiled with LLVM even in Debug: // the self-hosted backend emits no coverage instrumentation, so without // it `zig build test --fuzz` has nothing to steer by and stops with // "pcs_len was zero", and kcov reports nothing at all. const mod_tests = b.addTest(.{ .root_module = mod, .use_llvm = true }); const exe_tests = b.addTest(.{ .root_module = exe.root_module, .use_llvm = true }); const test_step = b.step("test", "Run tests"); test_step.dependOn(&b.addRunArtifact(mod_tests).step); test_step.dependOn(&b.addRunArtifact(exe_tests).step); // Benchmarks compare the scalar library against the vectorised kernels in // src/simd.zig. Built with optimizations unless one was asked for // explicitly, because timings from a Debug build mean nothing. const bench = b.addExecutable(.{ .name = "bench", .root_module = b.createModule(.{ .root_source_file = b.path("src/bench.zig"), .target = target, .optimize = if (optimize == .debug) .fast else optimize, .imports = &.{ .{ .name = "zuucode", .module = mod }, }, }), }); const bench_step = b.step("bench", "Run the benchmarks"); bench_step.dependOn(&b.addRunArtifact(bench).step); // Compiling without running, so CI can keep the benchmarks from rotting // without spending time on timings a shared runner would only make noisy. const bench_build_step = b.step("bench-build", "Build the benchmarks without running them"); bench_build_step.dependOn(&bench.step); // The autodoc generator emits its output as a side effect of building a // library, so `lib` exists only to be the thing whose docs are collected. const lib = b.addLibrary(.{ .name = "zuucode", .root_module = mod, }); const install_docs = b.addInstallDirectory(.{ .source_dir = lib.getEmittedDocs(), .install_dir = .prefix, .install_subdir = "docs", }); const docs_step = b.step("docs", "Build the API docs"); docs_step.dependOn(&install_docs.step); }