Write Zig code in the style of Loris Cro, VP Community at Zig Software Foundation. Emphasizes practical patterns, build system mastery, and teaching Zig effectively...
Loris Cro is the VP of Community at the Zig Software Foundation, known for explaining Zig concepts clearly and demonstrating practical applications. His focus is on making Zig accessible and showing how to build real software.
"Zig's build system is one of its killer features."
"Start simple, add complexity only when needed."
Cro emphasizes practical applicationβbuilding real things, understanding the build system, and using Zig's unique features to solve actual problems.
Build System First: Understand build.zig deeply.
Practical Patterns: Focus on what works in production.
C Interop: Leverage existing C libraries seamlessly.
Incremental Adoption: Use Zig where it helps most.
build.zig for all project configurationstd.log for structured loggingbuild.zig over external build tools// build.zig - the heart of a Zig project
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Main executable
const exe = b.addExecutable(.{
.name = "myapp",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// Link C library
exe.linkLibC();
exe.linkSystemLibrary("sqlite3");
// Add include paths
exe.addIncludePath(.{ .path = "vendor/include" });
b.installArtifact(exe);
// Run step
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the application");
run_step.dependOn(&run_cmd.step);
// Test step
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
// Import C headers directly
const c = @cImport({
@cInclude("stdio.h");
@cInclude("sqlite3.h");
});
pub fn main() void {
// Call C functions directly
_ = c.printf("Hello from C!\n");
}
// Wrap C libraries idiomatically
const Database = struct {
handle: *c.sqlite3,
pub fn open(path: [*:0]const u8) !Database {
var db: ?*c.sqlite3 = null;
const result = c.sqlite3_open(path, &db);
if (result != c.SQLITE_OK) {
return error.DatabaseOpenFailed;
}
return .{ .handle = db.? };
}
pub fn close(self: *Database) void {
_ = c.sqlite3_close(self.handle);
}
pub fn exec(self: *Database, sql: [*:0]const u8) !void {
var err_msg: ?[*:0]u8 = null;
const result = c.sqlite3_exec(
self.handle,
sql,
null,
null,
&err_msg,
);
if (result != c.SQLITE_OK) {
if (err_msg) |msg| {
std.log.err("SQL error: {s}", .{msg});
c.sqlite3_free(msg);
}
return error.SqlExecutionFailed;
}
}
};
const std = @import("std");
// Scoped logging
const log = std.log.scoped(.myapp);
pub fn processRequest(request_id: u64) !void {
log.info("Processing request {d}", .{request_id});
const result = doWork() catch |err| {
log.err("Request {d} failed: {}", .{ request_id, err });
return err;
};
log.debug("Request {d} result: {any}", .{ request_id, result });
}
// Configure log level at build time
pub const std_options = struct {
pub const log_level: std.log.Level = .debug;
// Custom log function
pub fn logFn(
comptime level: std.log.Level,
comptime scope: @TypeOf(.enum_literal),
comptime format: []const u8,
args: anytype,
) void {
const scope_prefix = if (scope != .default)
"[" ++ @tagName(scope) ++ "] "
else
"";
const prefix = "[" ++ level.asText() ++ "] " ++ scope_prefix;
std.debug.print(prefix ++ format ++ "\n", args);
}
};
const std = @import("std");
const testing = std.testing;
fn add(a: i32, b: i32) i32 {
return a + b;
}
test "add basic" {
try testing.expectEqual(@as(i32, 5), add(2, 3));
}
test "add negative" {
try testing.expectEqual(@as(i32, -1), add(2, -3));
}
// Test with allocator
test "dynamic allocation" {
const allocator = testing.allocator; // Detects leaks!
var list = std.ArrayList(u8).init(allocator);
defer list.deinit();
try list.append(42);
try testing.expectEqual(@as(usize, 1), list.items.len);
}
// Fuzz testing
test "fuzz example" {
const input = std.testing.fuzzInput(.{});
// Process fuzz input...
}
const std = @import("std");
// ArrayList - dynamic arrays
fn arrayListExample(allocator: std.mem.Allocator) !void {
var list = std.ArrayList(u32).init(allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.appendSlice(&[_]u32{ 3, 4, 5 });
for (list.items) |item| {
std.debug.print("{d} ", .{item});
}
}
// HashMap
fn hashMapExample(allocator: std.mem.Allocator) !void {
var map = std.StringHashMap(u32).init(allocator);
defer map.deinit();
try map.put("one", 1);
try map.put("two", 2);
if (map.get("one")) |value| {
std.debug.print("one = {d}\n", .{value});
}
}
// File I/O
fn fileExample() !void {
const file = try std.fs.cwd().openFile("data.txt", .{});
defer file.close();
var buf_reader = std.io.bufferedReader(file.reader());
var reader = buf_reader.reader();
var line_buf: [1024]u8 = undefined;
while (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) |line| {
std.debug.print("{s}\n", .{line});
}
}
// JSON parsing
fn jsonExample(allocator: std.mem.Allocator) !void {
const json_str =
\\{"name": "Alice", "age": 30}
;
const User = struct {
name: []const u8,
age: u32,
};
const parsed = try std.json.parseFromSlice(
User,
allocator,
json_str,
.{},
);
defer parsed.deinit();
std.debug.print("Name: {s}, Age: {d}\n", .{
parsed.value.name,
parsed.value.age,
});
}
// build.zig - cross-compile easily
pub fn build(b: *std.Build) void {
// Default to native
const target = b.standardTargetOptions(.{});
// Or target specific platforms:
// zig build -Dtarget=x86_64-linux-gnu
// zig build -Dtarget=aarch64-macos
// zig build -Dtarget=x86_64-windows-gnu
const exe = b.addExecutable(.{
.name = "myapp",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = b.standardOptimizeOption(.{}),
});
b.installArtifact(exe);
}
// Target-specific code
const builtin = @import("builtin");
fn platformSpecific() void {
switch (builtin.os.tag) {
.linux => linuxImpl(),
.macos => macosImpl(),
.windows => windowsImpl(),
else => @compileError("Unsupported platform"),
}
}
Cro approaches Zig projects by asking:
build.zigbuild.zig before deep language features