Currently, Roc generates builtin functions for things thare are not provided as an LLVM intrensic. The way this is done is by writing the functions in Rust, the compiling with rustc and emiting LLVM bitcode. Then, the compiler uses that file as a base and adds to it as part of the code gen process. So far this is working great, but there seems to be a limitation to this approach. To compile Rust to LLVM bitcode, you can't use external crates. This effects the builtins we write in two major ways:
- You can't use any code from crates.io
- Relatedly, you can only use rust primitives (no
core
orstd
)
When adding the Num.atan
function, which doesn't have an LLVM intrensic, we tried to use the libm crate. After running into the problem mentioned above, we ended up copying just the atan
function from the crate into the Roc module. While this works in a one-off case, it's not an ideal solution long term. This came up again shortly after, when trying to implement the countGraphemes
method from the unicode-segmentation crate. After trying to figure out ways to use more external crates in the bitcode generation, I think there are a couple possible solutions:
- Clone all external crates into a
vendor
folder, then compile each one to bitcode, the link them all into 1 big bitcode file.
I have solution patrially working. We can compile each library into it's own bitcode file and join them using llvm-link. The cons for this approach are that we need to clone any external library, including core
and compile them separately. This isnt' too bad, especially since we can do some optimization with LLVM to drop any dead code, etc, etc to remove any parts of the external crates that we don't use.
- Clone each function we need from external crates into the
builints/bitcode
crate directly.
This makes the compliation eaiser, but