hi I am a bit stuck in my current project but for the next one, I will be definitely in need to create my own platform. I want to start gather information ahead to have relatively smooth start. Could you point me to simplest possible example of Roc platform done in "C" or "C++" ( I don't want to learn Rust or Zig just for that )
host.c - Put this file into ./platform
#include <stdlib.h>
#include <stdio.h>
void *roc_alloc(size_t size)
{
return malloc(size);
}
void *roc_realloc(void *ptr, size_t new_size, size_t old_size, unsigned int alignment)
{
return realloc(ptr, new_size);
}
void roc_dealloc(void *ptr, unsigned int alignment)
{
free(ptr);
}
void *roc_memset(void *str, int c, size_t n)
{
return memset(str, c, n);
}
struct RocStr { char *bytes; size_t len; size_t capacity; };
int main()
{
struct RocStr str1;
//roc__mainForHost_1_exposed_generic(&str1);
roc__mainForHost_1_exposed(&str1); // identical!
for (int i=0; i<str1.len && i<30; ++i)
putchar(str1.bytes[i]);
printf("\n");
}
main.roc - Also put this file into ./platform
platform "simple-c-test"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main
Finally: app.roc - put this file into ./
app "app"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
zahl = 234
main : Str
main = "simple c example (this string must be long cuz we dont have sso!) \(Num.toStr zahl)"
1) Compile host.c: gcc -c platform/host.c
2) Compile app: ./roc build --no-link --optimize app.roc
3) Link all: gcc -o app app.o host.o
Edit:
4) Run: ./app
this statement , I don't get it
main = "simple c example (this string must be long cuz we dont have sso!) \(Num.toStr zahl)"
is this possible to expose more then just one object from Roc platform to "C" , let say provides [a1,a2,a3,a4] ??
Currently not: https://github.com/roc-lang/roc/issues/6115
You can only expose one function currently, but it can return anything, even a record of functions (though this does add some complexity for platform development)
if I want to expose some interface from "C" to roc, let say there is some array with data on C side and I want to give Roc API to access those data how to do that ?
Let say I have char [1000] buffer on "C" side and I want to read write to it
I also want to expose to Roc normal C functions like for side effects how to do that
There are a few options here:
@Brendan Hansknecht all great but what are exact syntax to pass anything from "C" to Roc
in context of example provided by Shaiden Spreitzer
If you are fine with just passing everything and then getting a result back (as opposed to using an effect). It would mean changing main
/mainForHost
to be a function in Roc. Then roc__mainForHost_1_exposed_generic
would be passed args in the order (&output, in1, in2, in3, ...)
. So the location to write the output then each of the inputs.
ok but how exactly syntax in "C" and .roc platform file looks like , what I should type there ?
So I would personally advise using rust or zig, or maybe c++. Rust and zig have a well tested roc library for the types like RocStr. C++ has a newer library in a PR that isn't really tested, but may work. Zig would probably give you the simplest experience close to C with significantly more support and examples.
If you use C++ and the new library, I think that you can just import a fully working RocStr
. Not 100% sure this code is correct, but something like this:
#include "roc_std.h"
// Other roc_alloc and such functions from above
int main()
{
// Fill this as normal.
char [1000] buffer;
Roc::Str in(buffer);
Roc::Str out;
roc__mainForHost_1_exposed_generic(&out, &in);
// out.content() should give you a `char *` if the output data. With out.length() as the length.
}
This assumes a Str -> Str
main function.
So mainForHost : Str -> Str
and
main : Str -> Str
main = \input ->
...
hi I will consider switching later one but when I do "C" for now I can't link for some reason
#include <stdlib.h>
#include <stdio.h>
void *roc_alloc(size_t size)
{
return malloc(size);
}
void *roc_realloc(void *ptr, size_t new_size, size_t old_size, unsigned int alignment)
{
return realloc(ptr, new_size);
}
void roc_dealloc(void *ptr, unsigned int alignment)
{
free(ptr);
}
void *roc_memset(void *str, int c, size_t n)
{
return memset(str, c, n);
}
struct RocStr { char *bytes; size_t len; size_t capacity; };
int main()
{
struct RocStr str1;
struct RocStr str2;
roc__mainForHost_1_exposed(&str1, &str2);
for (int i=0; i<str1.len && i<300; ++i)
putchar(str1.bytes[i]);
printf("\n");
}
platform "simple-c-test"
requires {} { main : Str -> Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str -> Str
mainForHost = main
app "app"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
main : Str -> Str
main = \ lst ->
"simple c example (this string must be long cuz we dont have sso!)"
regardless if "C" struct is correct here or not , at least I expect it to link, btw. I want to pass list of floats as input not Str, but I want to make that work first
Can't you expand on can't link?
sorry I messed up my cmake and warnings in custom roc command were treated as errors
so it works , what is the syntax when I want to pass list of floats , can I just pass
the code I provided is malfunctioning I am not able to pass return value from function. For some reason I am getting garbage in str1, but when I pass it as in example provided by Shaiden Spreitzer it works
maybe I will check this C++ library
Sure, this should be what is required to pass a seamless slice of floats to roc. This avoids an extra allocation and copy of the list of floats.
This is not tested, I just typed it out and hopefully it is correct. Then on the roc side, just change the input to List F32
.
struct RocList { float *data; size_t len; size_t capacity; };
const size_t SLICE_BIT = ((size_t)1) << (8 * sizeof(size_t) - 1);
const size_t REFCOUNT_MAX = 0;
int main()
{
// Initialize this however you want with whatever length.
float inputs[100];
struct RocStr out;
struct RocList in;
in.data = inputs;
in.len = 100;
// This is not actually the capacity but something special for seamless slices.
size_t rc = REFCOUNT_MAX;
size_t slice_bits = (((size_t)&rc) >> 1) | SLICE_BIT;
in.capacity = slice_bits;
roc__mainForHost_1_exposed(&out, &in);
// Everything else
}
Is your planned output still a string?
I don't know yet it may be list of float
I am still working on my example and although I initialized input with something
#include <stdlib.h>
#include <stdio.h>
void *roc_alloc(size_t size)
{
return malloc(size);
}
void *roc_realloc(void *ptr, size_t new_size, size_t old_size, unsigned int alignment)
{
return realloc(ptr, new_size);
}
void roc_dealloc(void *ptr, unsigned int alignment)
{
free(ptr);
}
void *roc_memset(void *str, int c, size_t n)
{
return memset(str, c, n);
}
struct RocStr { char *bytes; size_t len; size_t capacity; };
int main()
{
struct RocStr str1;
char *zink ="ankeanank";
struct RocStr str2 = { zink, 10, 10 };
roc__mainForHost_1_exposed(&str1, &str2);
for (int i=0; i<str1.len && i<300; ++i)
putchar(str1.bytes[i]);
printf("\n");
}
platform "simple-c-test"
requires {} { main : Str -> Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str -> Str
mainForHost = main
app "app"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
main : Str -> Str
main = \ lst ->
"simple c example (this string must be long cuz we dont have sso!)"
after running I am getting garbage in str1
basically function is not returning anything
this is influence of str2 because as I mentioned if I create function which is just returning everything works just fine
This is not a valid initialization of a RocStr:
char *zink ="ankeanank";
struct RocStr str2 = { zink, 10, 10 };
You could copy what I did above for a seamless slice, otherwise, RocStr is a more complex type. To initialize a big string, roc expects that the value is allocated on the heap and has the refcount stored on the heap before it. There is also an inline small string that is possible. This is why I don't really advise just hacking on things without a standard library.
With this current form, I am pretty sure that roc is attempting to modify the refcount of str2
. This would live before *zink
. As such, it is probably mutating and messing up str1
on the stack because that is what comes right before *zink
. That is at least my guess as to why you get garbage.
in your example you are using stack this is ok for list ?? float inputs[100];
In my example I make it a seamless slice with this:
size_t rc = REFCOUNT_MAX;
size_t slice_bits = (((size_t)&rc) >> 1) | SLICE_BIT;
in.capacity = slice_bits;
If you do the same to your string, it should work.
in your example I don't see crash but I am not getting result in out is empty
Hmm. I guess I'll need to take a deeper look.
it does not work either
char *zink = (char*)malloc(10);
size_t rc = REFCOUNT_MAX;
size_t slice_bits = (((size_t)&rc) >> 1) | SLICE_BIT;
struct RocStr str2 = { zink, 10, slice_bits };
Oh, this is a different bug. No idea what actually causes this. In the platform main, try this:
mainForHost : Str -> Str
mainForHost = \x -> main x
memory violation on both my and your example
I will try c++ library
Oh, minor typo:
roc__mainForHost_1_exposed
should be roc__mainForHost_1_exposed_generic
. I think that gets it working
still crashing , I tried c++ version in meantime and there is problem with name mangling for example it can't find "roc__mainForHost_1_exposed_generic" , could you point out zig example but zig is unfortunate because I have to use C anyway for other reasons so there will be mess
Hmm....I ran it just fine
could you copy paste your entire thing maybe I messed up something
and linking command would be nice to have too maybe I messed up something there
This works for me letting roc handle the linking: https://gist.github.com/bhansconnect/f5445239cd0e614514c9f49333e24e10
Note, github doesn't let me put /
in the names so have to put platform-main.roc
as platform/main.roc
Then just roc build app.roc
It also works to build manually by doing:
roc build --no-link app.roc
gcc -o app platform/host.c app.o
thx I will look
ok I had short Str and for some reason it was crashing entire thing thx for help
now I looked at your example and everything works fine short and long
Awesome
Last updated: Jul 06 2025 at 12:14 UTC