Hello! Thought I'd let you know that I've started work on a repository which shows more practical examples of how to accomplish higher-level compiler tasks with Cranelift.
So far I've created one which defines and links a binary file, and one which lowers structs.
https://github.com/simvux/cranelift-examples
I find that a lot of the current Cranelift documentation assumes pre-existing understanding of what a compiler needs to do to use Cranelift, and instead focuses on being a reference for the specifics. My goal with this project is to be the "missing" documentation in-between which explains the higher-level concepts you'd need to understand to use Cranelift.
I'd also want to continuously adapt the examples to address any questions I find people having when trying to pick up Cranelift with or without my examples.
Some other examples I've got planned are:
This is fantastic -- thank you for putting it together!
If (and only if!) you'd be interested in upstreaming your examples, I think we'd be happy to have them. I don't mean to preempt your ownership of this at all though if you'd rather it be a separate resource.
I'd rather keep it separate, at least for now. But would of course still love if Cranelift's README mentioned it, similarly to the JIT example.
Sure, happy to review a PR to add a link!
@Floppy Couple of comment on your examples:
Function you are building, so when compiling for Windows or arm64 macOS it will panic due to a calling convention mismatch.main instead of _start and link with gcc or clang instead? That is more portable across OSes. Some OSes for example mandate a special note being present to even allow running an executable, which plain ld will not add for you AFAIK. And once you actually start doing useful things, you will want to use libc. It will also allow you to just return 0 (or the result of the iadd) from the main function rather than emitting a trap at the end.Hello! Reviews and suggestions are much appreciated.
I do switch to using main after the output-a-binary example. But; It was probably a mistake to vary between the two and I should consistently stick to one so that more broad instructions of how to build and test it can be followed. Although since that first example is explicitly about producing native binaries, I could add more documentation on which things differ between different platforms and the various ways you may want to link the binary.
Instructing to link with clangseems like a good idea, since that should behave similarly between MacOS and Linux at least. Windows is a whole different beast that I've been ignoring for now.
Being able to inspect the result with echo $? by returning int as you say is also great as that allows people to mess with the code and see the result change without having to use a debugger.
I'll add MIT license, thanks for the reminder.
I'm trying to write fairly idiomatic code but one thing I've always done that's always felt a bit of is that;
Whenever I declare a function in a module, i create a function signature, which allocates two vectors.
Then when I define that function, I have to clone that function signature for the temporary function builder.
Solving this is a bit of an microoptimization. However; so much else of Cranelift is focused around arena allocation and ids/refs. So is there some way I'm missing to not have to allocate the signature twice?
I don't think there is a way to avoid allocating the signature twice.
Last updated: Dec 06 2025 at 07:03 UTC