7.3 KiB
7.3 KiB
zargs - Zero-overhead Argument Parser for Zig
A type-safe, compile-time command-line argument parser for Zig that uses struct introspection to automatically generate parsers.
Features
- ✅ Type-safe: Arguments are defined as struct fields with compile-time type checking
- ✅ Zero runtime overhead: All metadata extraction happens at compile time
- ✅ Flexible syntax: Supports
--flag,--flag=value,-f,-f value, and multi-flags (-abc) - ✅ Rich types: Bool, integers, strings, enums, lists, and optional types
- ✅ Automatic help: Generates professional help text from struct metadata
- ✅ Multi-module: Multiple modules can register arguments with collision detection
- ✅ Memory safe: No leaks, proper cleanup with
defer - ✅ Zero dependencies: Pure Zig, no external dependencies
Quick Start
const std = @import("std");
const zargs = @import("zargs");
const Config = struct {
verbose: bool = false,
output: []const u8 = "output.txt",
count: u32 = 10,
pub const meta = .{
.verbose = .{ .short = 'v', .help = "Enable verbose output" },
.output = .{ .short = 'o', .help = "Output file path" },
.count = .{ .short = 'c', .help = "Number of items" },
};
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const config = zargs.parse(Config, allocator, args) catch |err| {
if (err == error.HelpRequested) return;
return err;
};
std.debug.print("Output: {s}\n", .{config.output});
}
Usage
Define Your Configuration
const Config = struct {
// Boolean flag (default: false)
verbose: bool = false,
// String argument (default: "output.txt")
output: []const u8 = "output.txt",
// Integer argument (default: 10)
count: u32 = 10,
// Enum argument (default: .balanced)
mode: enum { fast, slow, balanced } = .balanced,
// Optional argument (default: null)
name: ?[]const u8 = null,
// String list (can be repeated or comma-separated)
files: []const []const u8 = &[_][]const u8{},
// Add metadata for help text and short flags
pub const meta = .{
.verbose = .{
.short = 'v',
.help = "Enable verbose output",
},
.output = .{
.short = 'o',
.help = "Output file path",
},
.count = .{
.short = 'c',
.help = "Number of items to process",
},
.mode = .{
.short = 'm',
.help = "Processing mode",
},
.name = .{
.help = "Optional name parameter",
},
.files = .{
.short = 'f',
.help = "Input files (can be repeated)",
},
};
};
Parse Arguments
// Simple parsing (shows help automatically)
const config = try zargs.parse(Config, allocator, args);
// Advanced: manual registry for multi-module apps
var registry = zargs.ArgumentRegistry.init(allocator);
defer registry.deinit();
try registry.registerMetadata(Module1Config, "Module1");
try registry.registerMetadata(Module2Config, "Module2");
try zargs.parseArgv(®istry, args);
const mod1 = try zargs.populateStruct(Module1Config, ®istry, allocator);
const mod2 = try zargs.populateStruct(Module2Config, ®istry, allocator);
Command-Line Syntax
Boolean Flags
./program --verbose # Sets verbose = true
./program -v # Short form
./program -vdq # Multi-flag (sets verbose, debug, quiet)
String Arguments
./program --output=file.txt # With equals
./program --output file.txt # Space-separated
./program -o file.txt # Short form
Integer Arguments
./program --count=42
./program --count 0xFF # Hex supported
./program --count 0b1010 # Binary supported
Enum Arguments
./program --mode=fast
./program --mode slow
List Arguments
./program --files=a.txt,b.txt,c.txt # Comma-separated
./program --files=a.txt --files=b.txt # Repeated (both work!)
Help
./program --help
./program -h
Supported Types
- Booleans:
bool - Integers:
u8,u16,u32,u64,i8,i16,i32,i64 - Strings:
[]const u8 - Enums: Any Zig enum type
- Lists:
[]const []const u8(string lists) - Optionals:
?Tfor any supported typeT
Help Text Generation
zargs automatically generates professional help text:
Usage: program [OPTIONS]
Options:
-h, --help Show this help message
-c, --count <NUM> Number of items to process
-m, --mode <CHOICE> Processing mode
-o, --output <VALUE> Output file path [default: output.txt]
-v, --verbose Enable verbose output [default: false]
Advanced Features
Collision Detection
When multiple modules register the same argument name:
- Compatible (same type): Allowed, warns
- Incompatible (different types): Compile error
// Both modules can register --verbose (bool)
try registry.registerMetadata(Module1, "Module1"); // has verbose: bool
try registry.registerMetadata(Module2, "Module2"); // has verbose: bool - OK!
// This would error at compile time:
// Module1 has verbose: bool
// Module2 has verbose: u32 - COMPILE ERROR!
Custom Metadata
pub const meta = .{
.field_name = .{
.short = 'x', // Short flag (optional)
.help = "Description", // Help text (optional)
.required = true, // Override default requirement (optional)
},
};
Examples
See the examples/ directory for complete examples:
simple.zig- Basic single-struct usagemulti_module.zig- Multiple modules with shared registry
Building
Requires Zig 0.14 or later (tested with Zig 0.15.2).
zig build
zig build test
API Reference
Main Functions
parse(T, allocator, argv)- Parse arguments into struct TparseWithRegistry(T, registry, allocator, argv)- Parse with existing registry
Core Types
ArgumentRegistry- Central registry for argument metadataArgumentType- Enum of supported argument typesParsedValue- Tagged union of parsed valuesArgumentMetadata- Complete metadata for an argument
Utilities
generateHelpText(registry, allocator, program_name)- Generate help textparseArgv(registry, argv)- Parse argv into registrypopulateStruct(T, registry, allocator)- Populate struct from parsed values
Design Philosophy
zargs is designed for game engines and plugin architectures where:
- Arguments are scattered across many modules
- Not all modules may load in every run
- Comprehensive documentation is still needed
- Type safety is non-negotiable
Version
Current version: 0.1.0-dev
License
[Add your license here]
Contributing
Contributions welcome! Please ensure:
- All tests pass (
zig build test) - No memory leaks (tests check with
std.testing.allocator) - Code follows existing style
- New features have tests and documentation
Acknowledgments
Built with ❤️ in Zig, following best practices from the Zig standard library.