What would be the proper way of exposing OS-specific APIs in Roc platforms? Given a platform that supports muliple OS, what is the best way to allow namespace unsharing when spawning a child process? Only Linux has this feature.
Another use case is restricting a child process with a Roc API that uses Landlock + seccomp on Linux, Seatbelt on macOS, but Windows has no equivalent for this.
There is the platform API
and there is the underlying host implementation, for each target CpuArch-OS.
So the platform could export a Linux module, and the underlying host implementation does linux things on the linux host... And on a windows host, those could be no-ops or return an error etc.
And then the platform API could return something like: Try(LinuxResult, [CpuArchOSNotSupported]) etc.
Or you can supply a platform per os, with just the relevant API calls, and none of the other irrelevant calls. linux-platform-1.0.0/[hash].tar.zst, windows-platform-1.0.0/[hash].tar.zst etc...
Or you can supply a combined platform API, that supplies the host OS, as a tag union this_host : [Linux, Windows, MacOS] or something, and then app authors can conditionally call the platform APIs.
Just depends on the requirements of the app developers. "I want cross OS support", "I only care about A & B OS...", "I don't care what's under the hood" etc.
So you can either ship extra bloat, or trimmed to just the app developer's use-case.
The point is... that the platform is static, the host ABIs are static C-FFI etc. If you need something dynamic, then you need to dynamically generate a platform at compile time. Or supply a matrix of platforms...
This is not very ergonomic. It's requires handling the other platforms on any target. And also makes easy to write code that accidentally expects a result for a different OS, which would never happen, so it's effectively unreachable code. Would be nicer if there were some way to utilize comptime checking, like in Zig:
if (builtin.target.os.tag == .linux) {
...
} else {}
The library is usable for any OS, but it's returning void when compiling to other than Linux.
Or you can supply a platform per os, with just the relevant API calls, and none of the other irrelevant calls.
linux-platform-1.0.0/[hash].tar.zst,windows-platform-1.0.0/[hash].tar.zstetc...
There's no mechanism to conditionally include dependencies, this would only work with single OS apps.
If you need something dynamic, then you need to dynamically generate a platform at compile time.
This wouldn't be bad. Apart from requiring a Zig compiler alongside the Roc one, but if somebody is developing complex apps, it's a good compromise.
But this would require some built-in solution to expose this info in Roc code, without hacky workarounds.
I'm creating godot-roc platform...
And I have multiple versions of godot, godot forks, publish to web -> wasm32-emscripten
The API, will need to support 4.1, ..., 4.7...
And redot (godot-forks from v4.5 ->) 1, 2, 3... 26.
4.7 is backwards compatible with 4.1... but 4.1 is missing APIs that 4.7 has.
Calling 4.7 function on 4.1, could lead to memory corruption etc... these are just function pointers in a table... there is a version api call in 4.1 that i can check the version at runtime (& statically at platform compile time), so I can safely conditionally call the 4.7 apis, comptime & runtime.
I don't have one static platform, instead I'm generating a dynamic one from a pinned version of any given engine(s)...
And from here, I'll need to provide either a all-in-1 platform, or a matrix of platforms... or just the latest platform, with runtime conditionals etc.
So my final workflow looks like...
Godot engine version(s) -> generate platform -> roc glue ...roc abi -> generate matching host implementation
So the roc platform, know which static engine api versions are available, at platform compile time, and can double check at runtime.
And for game devs... they'll just have some-platform/[hash].tar.zst.
I'm still undecided what "some-platform" will be... but for now I'm targeting godot 4.7 API, with the possibility to generate any other combination as needed... so game devs can migrate versions & engines, multi-engine support via runtime conditionals or choose a trimmed down & optimised platform.
Engine : [Godot4_7, Redot26]
engine : Engine
engine = Redot26
Redot26.redot_exclusive(1234)
Godot4_7.godot_exclusive("foobar") # uh-oh !
Engine.atan2(123) # implemented in both engines.
const is_wasm_target = builtin.cpu.arch == .wasm32;
const is_native_target = !is_wasm_target;
// wasm doesn't have stdout print!
if (comptime is_native_target) {
std.debug.print("{s}\n", .{msg});
}
g_engine_interface.print_warning(msg.ptr, "printWarn", "host.zig", @src().line, 0);
// @since 4.1
g_engine_interface.get_godot_version(&g_engine_runtime_version);
if (g_engine_runtime_version.major != 4 and g_engine_runtime_version.major != 1 and g_engine_runtime_version.major != 0) {
var ver_buf: [256]u8 = undefined;
const ver_slice = cStrToSlice(g_engine_runtime_version.string, 128);
const ver_msg = bufPrintC(
&ver_buf,
"This version of godot-roc was compiled for godot 4.7.2, but got: {s}.",
.{ver_slice},
) catch "godot-roc: version mismatch (string truncated).";
g_engine_interface.print_error(ver_msg.ptr, "godot_roc_init", "host.zig", @src().line, 1);
}
Last updated: Oct 15 2026 at 17:56 UTC