fetch_ml/cli/build.zig
Jeremie Fraeys d225ea1f00 feat: implement Zig CLI with comprehensive ML experiment management
- Add modern CLI interface built with Zig for performance
- Include TUI (Terminal User Interface) with bubbletea-like features
- Implement ML experiment commands (run, status, manage)
- Add configuration management and validation
- Include shell completion scripts for bash and zsh
- Add comprehensive CLI testing framework
- Support for multiple ML frameworks and project types

CLI provides fast, efficient interface for ML experiment management
with modern terminal UI and comprehensive feature set.
2025-12-04 16:53:58 -05:00

175 lines
6.6 KiB
Zig

// Targets:
// - default: ml (ReleaseSmall)
// - dev: ml-dev (Debug)
// - prod: ml (ReleaseSmall) -> zig-out/prod
// - release: ml-release (ReleaseFast) -> zig-out/release
// - cross: ml-* per platform -> zig-out/cross
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseSmall });
// Common executable configuration
// Default build optimizes for small binary size (~200KB after strip)
const exe = b.addExecutable(.{
.name = "ml",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// Embed rsync binary if available
const embed_rsync = b.option(bool, "embed-rsync", "Embed rsync binary in CLI") orelse false;
if (embed_rsync) {
// This would embed the actual rsync binary
// For now, we'll use the wrapper approach
exe.root_module.addCMacro("EMBED_RSYNC", "1");
}
b.installArtifact(exe);
// Default run command
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);
// === Development Build ===
// Fast build with debug info for development
const dev_exe = b.addExecutable(.{
.name = "ml-dev",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = b.resolveTargetQuery(.{}), // Use host target
.optimize = .Debug,
}),
});
const dev_install = b.addInstallArtifact(dev_exe, .{
.dest_dir = .{ .override = .{ .custom = "dev" } },
});
const dev_step = b.step("dev", "Build development version (fast compilation, debug info)");
dev_step.dependOn(&dev_install.step);
// === Production Build ===
// Optimized for size and speed
const prod_exe = b.addExecutable(.{
.name = "ml",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = .ReleaseSmall, // Optimize for small binary size
}),
});
const prod_install = b.addInstallArtifact(prod_exe, .{
.dest_dir = .{ .override = .{ .custom = "prod" } },
});
const prod_step = b.step("prod", "Build production version (optimized for size and speed)");
prod_step.dependOn(&prod_install.step);
// === Release Build ===
// Fully optimized for performance
const release_exe = b.addExecutable(.{
.name = "ml-release",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = .ReleaseFast, // Optimize for speed
}),
});
const release_install = b.addInstallArtifact(release_exe, .{
.dest_dir = .{ .override = .{ .custom = "release" } },
});
const release_step = b.step("release", "Build release version (optimized for performance)");
release_step.dependOn(&release_install.step);
// === Cross-Platform Builds ===
// Build for common platforms with descriptive binary names
const cross_targets = [_]struct {
query: std.Target.Query,
name: []const u8,
}{
.{ .query = .{ .cpu_arch = .x86_64, .os_tag = .linux }, .name = "ml-linux-x86_64" },
.{ .query = .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, .name = "ml-linux-musl-x86_64" },
.{ .query = .{ .cpu_arch = .x86_64, .os_tag = .macos }, .name = "ml-macos-x86_64" },
.{ .query = .{ .cpu_arch = .aarch64, .os_tag = .macos }, .name = "ml-macos-aarch64" },
};
const cross_step = b.step("cross", "Build cross-platform binaries");
for (cross_targets) |ct| {
const cross_target = b.resolveTargetQuery(ct.query);
const cross_exe = b.addExecutable(.{
.name = ct.name,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = cross_target,
.optimize = .ReleaseSmall,
}),
});
const cross_install = b.addInstallArtifact(cross_exe, .{
.dest_dir = .{ .override = .{ .custom = "cross" } },
});
cross_step.dependOn(&cross_install.step);
}
// === Clean Step ===
const clean_step = b.step("clean", "Clean build artifacts");
const clean_cmd = b.addSystemCommand(&[_][]const u8{
"rm", "-rf",
"zig-out", ".zig-cache",
});
clean_step.dependOn(&clean_cmd.step);
// === Install Step ===
// Install binary to system PATH
const install_step = b.step("install-system", "Install binary to /usr/local/bin");
const install_cmd = b.addSystemCommand(&[_][]const u8{
"sudo", "cp", "zig-out/bin/ml", "/usr/local/bin/",
});
install_step.dependOn(&install_cmd.step);
// === Size Check ===
// Show binary sizes for different builds
const size_step = b.step("size", "Show binary sizes");
const size_cmd = b.addSystemCommand(&[_][]const u8{
"sh", "-c",
"if [ -d zig-out/bin ]; then echo 'zig-out/bin contents:'; ls -lh zig-out/bin/; fi; " ++
"if [ -d zig-out/prod ]; then echo '\nzig-out/prod contents:'; ls -lh zig-out/prod/; fi; " ++
"if [ -d zig-out/release ]; then echo '\nzig-out/release contents:'; ls -lh zig-out/release/; fi; " ++
"if [ -d zig-out/cross ]; then echo '\nzig-out/cross contents:'; ls -lh zig-out/cross/; fi; " ++
"if [ ! -d zig-out/bin ] && [ ! -d zig-out/prod ] && [ ! -d zig-out/release ] && [ ! -d zig-out/cross ]; then " ++
"echo 'No CLI binaries found. Run zig build (default), zig build dev, zig build prod, or zig build release first.'; fi",
});
size_step.dependOn(&size_cmd.step);
// Test step
const source_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const test_module = b.createModule(.{
.root_source_file = b.path("tests/main_test.zig"),
.target = target,
.optimize = optimize,
});
test_module.addImport("src", source_module);
const exe_tests = b.addTest(.{
.root_module = test_module,
});
const run_exe_tests = b.addRunArtifact(exe_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_tests.step);
}