This juicy merge answers, what if you could receive a bunch of goodies in main simply by asking for them? As a result, there are now 3 ways to define the main function.
pub fn main() !void { ... }
pub fn main(init: std.process.Init) !void { ... }
pub fn main(init: std.process.Init.Minimal) !void { ... }
The structure to understand is Init. This struct is now the only way to access environment variables and cli arguments, os.environ and os.argv have been deleted.
First, Let’s talk about Minimal Init #
The new method of getting command line arguments.
pub fn main(init: std.process.Init.Minimal) void {
// Use an allocator of your choice.
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
defer _ = debug_allocator.deinit();
const gpa = debug_allocator.allocator();
var i: u32 = 0;
var args = try init.args.iterateAllocator(gpa);
args.deinit();
while (args.next()) |arg| : (i += 1) {
std.debug.print("arg[{d}]={s}\n", .{i, arg});
}
}
You can also use toSlice() but an arena allocator must be used.
pub fn main(init: std.process.Init.Minimal) void {
var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const args = try init.args.toSlice(arena);
for (args) |arg| {
std.debug.print("arg: {s}\n", .{arg});
}
}
How do we access environment fields? #
The difference between the constant and non-constant versions of environ is that the non-constant versions create an environ map std.process.Environ.Map.
pub fn main(init: std.process.Init.Minimal) !void {
var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const contains_home = try init.environ.contains(arena, "HOME");
const home_is_unempty = try init.environ.containsUnempty(arena, "HOME");
const contains_editor = init.environ.containsConstant("EDITOR");
const editor_is_unempty = init.environ.containsUnemptyConstant("EDITOR");
std.debug.print("{} {} {} {}", .{contains_home, home_is_unempty, contains_editor, editor_is_unempty});
// Get a specific environ value.
std.debug.print("EDITOR: {s}\n", .{try init.environ.getAlloc(arena, "EDITOR")});
if (builtin.os.tag == .windows) {
std.debug.print("HOME: {?s}\n", .{init.environ.getWindows("HOME")});
} else if (builtin.os.tag != .wasi or builtin.link_libc) {
std.debug.print("HOME: {?s}\n", .{init.environ.getPosix("HOME")});
}
// Iterate/Find specific environ values as key/value pairs of a map.
const environ_map = try init.environ.createMap(arena);
for (environ_map.keys(), environ_map.values()) |key, value| {
std.debug.print("env: {s}={s}\n", .{key, value});
}
}
Let’s talk about Init (non-Minimal) … #
The non-Minimal Init is a superset of Minimal
pub const Init = struct {
/// Init is a superset of Minimal.
minimal: Minimal,
/// Permanent storage for the entire process, cleaned automatically on exit.
arena: *std.heap.ArenaAllocator,
/// A default-selected general purpose allocator for temporary heap allocations.
/// Debug mode will set up leak checking.
gpa: std.mem.Allocator,
/// An appropriate default Io implementation based on the target configuration.
/// Debug mode will set up leak checking.
io: std.Io,
/// Environment variables, initialized with gpa. Not threadsafe.
environ_map: *Environ.Map,
/// Named files that have been provded by the parent process. This is mainly useful on WASI, but can be used on other systems to mimic the behavior with respect to stdio.
propens: Propens,
};
Notes about Init:
We can use all our previous code but instead of calling
init.environ.containswe’d callinit.minimal.environ.contains.
Init comes with an
environ_mapso we don’t need to create one, we can use the existing one.
pub fn main(init: std.process.Init) !void {
for (init.environ_map.keys(), init.environ_map.values()) |key, value| {
std.log.info("env: {s}={s}", .{ key, value });
}
}
It comes with an Arena and Debug allocator. You can plug them into your application, no need to call
deinit().
I’ve captured a summary above, for more in-depth information check out this video by ComputerBread.