I'm new to roc, I've seen quite a bit of the language and its documentation but not about the tooling and the platforms, so I have some questions:
If I extract the files (main.roc
, platform/main.roc
, platform/platform.zig
) from examples/platform-switching/zig-platform
and run roc run main.roc
I get a compiler bug that wasn't there before (panicked at 'called \
Result::unwrap()\` on an \`Err\` value: Any { .. }', crates/cli/src/build.rs:288:46`)
How would I build a roc file from a build script? and how does it compile the zig code? can I compile the zig code myself and then statically link them later?
Is there a way of not generating the dynhost
, libapp.so
, metadata
, preprocessedhost
, zig-cache
, and executable in the src
directory?
In the platform.zig
file it imports builtin
and str
, where from? can I import them into my code from build.zig
myself to compile separately without the roc (build|run)
doing everything?
I guess the main thing is that I want control over and knowledge of the build process.
I'd also like to know what a platform needs and how expensive transferring data between the platform and roc is.
I know these are lots of questions for a new language but I'm very excited and have been waiting and thinking about this for a while. I'd be happy to look through some examples or source code if that's all there is.
Thanks for the hard work!
Yeah, Roc linking can definitely do a bit of magic. This is to generally make life simpler for people. That being said, I have link Roc for running on an embedded device and had to do it manually. It isn't that bad, but if you can avoid it, I would advise allowing for Roc to just deal with it.
Anyway, let me try and answer the individual questions
If I extract the files (main.roc, platform/main.roc, platform/platform.zig) from examples/platform-switching/zig-platform and run roc run main.roc I get a compiler bug that wasn't there before (panicked at 'called \Result::unwrap()\` on an \`Err\` value: Any { .. }', crates/cli/src/build.rs:288:46`)
There was a failure to rebuild the zig host, only looking at this error message, it is quite hard to tell why. Based on what you said here, I think it should work, but it is hard to tell what is the issue. Would be useful if you can post and issue to the repo with more details.
How would I build a roc file from a build script? and how does it compile the zig code? can I compile the zig code myself and then statically link them later?
roc build --no-link
will output a .o
file. That can then be consumed by zig as any other .o
would be. So you could use ar rcs roc_app.a roc_app.o
to convert it into a static library. Then zig can use it like any other static library.
Is there a way of not generating the dynhost, libapp.so, metadata, preprocessedhost, zig-cache, and executable in the src directory?
There is no config for this to my knowledge. We need to add that, or at least put most of them in a hidden folder or something.
In the platform.zig file it imports builtin and str, where from? can I import them into my code from build.zig myself to compile separately without the roc (build|run) doing everything?
This is a convenience that long term should probably go away. Since our builtin functions are written in zig, we have just directly reused them when building zig hosts. A stripped down version of those files tailored for host use need eventually be built into a zig library/package that would get imported by the zig hosts. We have a proper package for the Rust platforms, but the zig platforms reuse our builtins directly. The files live in crates/compiler/builtins/bitcode/src/. If you were building a zig host a different way, you probably would just copy those files over.
I guess the main thing is that I want control over and knowledge of the build process.
You can get it, but Roc is made to hide that away (at least to some extent). Though a lot of the setup today is at least partially hacked together. Long term, we definitely want platform authors to have more control over how their platform gets built.
I'd also like to know what a platform needs
The platform story currently is not the cleanest. Decent parts of it plan to change long term (mostly around giving platforms more ability to control building/linking, and automatically generating a lot of the API the platform must fulfill). I thought we wrote a doc on the basics of platform dev, but I can't find it at this moment. I would advise building off of existing platforms currently because it leaves less to figure out. The general story is that the platform needs to provide roc with a few special functions roc_alloc
, roc_realloc
, roc_dealloc
, roc_memcpy
, roc_memset
, and roc_panic
. It also needs to provide roc with a function for every effect it can call (roc_fx_*
). Lastly, it has to actually call into roc functions when it needs to use them (with some extra complications around closures). All of this is doable manually, but some parts can get painful. Hopefully our bindgen commands will eventually generate most of this for you (at least the function headers/apis).
how expensive transferring data between the platform and roc is.
As expensive as a non-inlined function call (basically free) with the caveat that Roc expects certain types. So if you have a zig string and want to pass it to Roc, you have to convert it into a Roc Str.
please feel free to reach out with more questions or for follow up. We are glad to help people build platforms. I think Rust is probably the easiest language to build complex platforms in currently (first bindgen target so more stuff is automatic), but for testing Roc out, any language should work.
Brendan Hansknecht said:
Yeah, Roc linking can definitely do a bit of magic. This is to generally make life simpler for people. That being said, I have link Roc for running on an embedded device and had to do it manually. It isn't that bad, but if you can avoid it, I would advise allowing for Roc to just deal with it.
I think having simple defaults is great, but as long as it's possible to change things if you need to.
Brendan Hansknecht said:
roc build --no-link
will output a.o
file. That can then be consumed by zig as any other.o
would be. So you could usear rcs roc_app.a roc_app.o
to convert it into a static library. Then zig can use it like any other static library.
That's exactly what I needed! Thank you.
There is no config for this to my knowledge. We need to add that, or at least put most of them in a hidden folder or something.
Well it looks like if I do --no-link
it doesn't make those files so it's a lot more manageable.
Otherwise the rest is perfect! Thanks.
With that I've made a rudimentary zig buildStep
that means I have
// ...
exe.addObjectFile("zig-cache/roc/rocLovesZig.o");
// and
const roc = RocBuildStep.create(b, "rocLovesZig");
roc.setBuildMode(mode);
roc.install();
Which currently copies all of the files into a cache directory, compiles it into a .o
, then links it. It's slightly hardcoded right now but I'd love to get it out to a build library so that anyone can just add a roc file in a build.zig
and have it "just work" (including caching etc...).
I also just copied over the builtin zig definitions but I'd like to make that a package too.
Anyway, I got it to do:
$ zig build run
rebuilding host...
// ...
Roc <3 Zig!
runtime: 0.000ms
Arya Elfren has marked this topic as resolved.
Last updated: Jul 06 2025 at 12:14 UTC