Backlog/lib/sdl3/parser/docs/usage.md

5.4 KiB

Usage Guide

Installation

cd lib/sdl3/parser
zig build

Basic Usage

Parse a Header File

# Output to stdout
zig build run -- ../SDL/include/SDL3/SDL_gpu.h

# Save to file with --output
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig

# Generate with C mocks
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig --mocks=gpu_mock.c

# Test mock generation (uses test_small.h)
zig build test-mocks
# Output: zig-out/test_small.zig and zig-out/test_small_mock.c

Command Line Options

  • <header-file> - Path to C header file to parse (required)
  • --output=<path> - Write Zig bindings to specified file (optional, defaults to stdout)
  • --mocks=<path> - Generate C mock implementations at specified path (optional)

Run Tests

# All unit tests
zig build test

# Test mock generation
zig build test-mocks

Output Format

The parser outputs Zig code with this structure:

pub const c = @import("c.zig").c;

// 1. Opaque types
pub const GPUDevice = opaque {};

// 2. Enums
pub const GPUPrimitiveType = enum(c_int) { ... };

// 3. Flags (packed structs)
pub const GPUTextureUsageFlags = packed struct(u32) { ... };

// 4. Structs
pub const GPUViewport = extern struct { ... };

// 5. Functions (inline wrappers)
pub inline fn createGPUDevice(...) ... { ... }

Integration

Using Generated Bindings

// Your project
const gpu = @import("gpu.zig");

pub fn main() !void {
    // Use opaque types
    const device = gpu.createGPUDevice(false, false, null);
    defer if (device) |d| gpu.destroyGPUDevice(d);
    
    // Use enums
    const prim_type = gpu.GPUPrimitiveType.primitivetypeTrianglelist;
    
    // Use flags
    var usage: gpu.GPUTextureUsageFlags = .{};
    usage.textureusageSampler = true;
    usage.textureusageColorTarget = true;
    
    // Use structs
    const viewport = gpu.GPUViewport{
        .x = 0.0,
        .y = 0.0,
        .w = 800.0,
        .h = 600.0,
        .min_depth = 0.0,
        .max_depth = 1.0,
    };
}

Required c.zig

The generated bindings expect a c.zig file that exports C declarations:

// c.zig
pub const c = @cImport({
    @cInclude("SDL3/SDL.h");
    @cInclude("SDL3/SDL_gpu.h");
});

Or link with SDL3 directly in your build.zig:

const exe = b.addExecutable(.{
    .name = "my_app",
    .root_source_file = b.path("src/main.zig"),
    // ...
});

exe.linkSystemLibrary("SDL3");
exe.linkLibC();

Common Patterns

Handling Opaque Pointers

// Functions return optional pointers
const device: ?*gpu.GPUDevice = gpu.createGPUDevice(...);

// Check before use
if (device) |d| {
    // Use d safely
    gpu.destroyGPUDevice(d);
}

Working with Flags

// Initialize empty
var flags: gpu.GPUTextureUsageFlags = .{};

// Set individual bits
flags.textureusageSampler = true;
flags.textureusageColorTarget = true;

// Pass to functions
const texture = gpu.createGPUTexture(device, &.{
    .usage = flags,
    // ... other fields
});

Enum Comparisons

const prim_type = gpu.GPUPrimitiveType.primitivetypeTrianglelist;

if (prim_type == .primitivetypeTrianglelist) {
    // Handle triangle list
}

Troubleshooting

Issue: "error: use of undeclared identifier 'c'"

Solution: Create a c.zig file that imports SDL3 headers:

pub const c = @cImport({
    @cInclude("SDL3/SDL.h");
});

Issue: Parser crashes on header file

Cause: Unsupported C pattern

Solution: Check parser output for errors, file an issue with the problematic pattern

Issue: Generated names don't match expectations

Cause: Naming convention mismatch

Solution: See Naming Conventions for the conversion rules

Issue: Memory leak warnings

Cause: Parser bug (should not happen in current version)

Solution: Run with GPA to identify leak, file an issue

zig build run -- header.h 2>&1 | grep -i leak

Performance Tips

For Large Headers

  • Parser is O(n) in source size, typically <500ms
  • Memory usage is O(declarations), typically <10MB
  • No performance tuning needed for typical SDL3 headers

Batch Processing

# Parse multiple headers
for header in ../SDL/include/SDL3/*.h; do
    basename="${header##*/}"
    zig build run -- "$header" > "output/${basename%.h}.zig"
done

Advanced Usage

Custom Naming

Edit naming.zig to customize conversion rules:

pub fn typeNameToZig(c_name: []const u8) []const u8 {
    // Custom logic here
}

Adding New Patterns

See Architecture for how to add support for new C patterns.

Debugging

# Run with debug info
zig build -Doptimize=Debug
zig-out/bin/sdl-parser header.h

# Check what's being parsed
zig build run -- header.h 2>&1 | head -20

FAQ

Q: Does the parser support C++? A: No, only C headers. C++ requires a full C++ parser.

Q: Can I use this for non-SDL libraries? A: Yes, but it's optimized for SDL3 naming conventions. You may need to adjust naming.zig.

Q: Does it handle macros? A: Only #define for flag values. Complex macros are not supported.

Q: What about function pointers? A: Basic support exists but may need refinement for complex signatures.

Q: Can it generate C code? A: Not yet, but mock generation is planned (see TEST_HARNESS_PLAN_V2.md).

Q: Is it production ready? A: Yes for SDL3. It's tested with SDL_gpu.h and generates valid, working bindings.