mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 07:49:17 +03:00
Compile bitcode as part of build script
This commit is contained in:
parent
586b899e73
commit
48f8aad180
2
compiler/builtins/bitcode/.gitignore
vendored
2
compiler/builtins/bitcode/.gitignore
vendored
@ -1 +1 @@
|
||||
out
|
||||
lib.ll
|
||||
|
@ -1,7 +0,0 @@
|
||||
.PHONY: build clean
|
||||
|
||||
build:
|
||||
./generate.sh ../../gen/src/llvm/builtins.bc
|
||||
|
||||
clean:
|
||||
rm -rf ./out
|
@ -5,52 +5,24 @@ When their implementations are simple enough (e.g. addition), they
|
||||
can be implemented directly in Inkwell.
|
||||
|
||||
When their implementations are complex enough, it's nicer to
|
||||
implement them in a higher-level language like Rust, compile the
|
||||
result to LLVM bitcode, and import that bitcode into the compiler.
|
||||
implement them in a higher-level language like C (or eventually Zig),
|
||||
compile the result to LLVM bitcode, and import that bitcode into the compiler.
|
||||
|
||||
Here is the process for doing that.
|
||||
Compiling the bitcode happens automatically in a Rust build script at `compiler/gen/build.rs`.
|
||||
You can find the compiled bitcode in `target/debug/build/roc_gen-[some random characters]/out/builtins.bc`.
|
||||
|
||||
## Building the bitcode
|
||||
|
||||
The source we'll use to generate the bitcode is in `src/lib.rs` in this directory.
|
||||
|
||||
To generate the bitcode, `cd` into `compiler/builtins/bitcode/` and run:
|
||||
|
||||
```bash
|
||||
$ ./regenerate.sh
|
||||
```
|
||||
|
||||
> If you want to take a look at the human-readable LLVM IR rather than the
|
||||
> bitcode, run this instead and look for a `.ll` file instead of a `.bc` file:
|
||||
> If you want to take a look at the human-readable LLVM IR, cd into `compiler/builtins/bitcode` and
|
||||
> run the following command. It should create `compiler/builtins/bitcode/lib.ll`
|
||||
>
|
||||
> ```bash
|
||||
> $ cargo rustc --release --lib -- --emit=llvm-ir
|
||||
> clang -S -emit-llvm src/lib.c
|
||||
> ```
|
||||
>
|
||||
> Then look in the root `roc` source directory under `target/release/deps/` for a file
|
||||
> with a name like `roc_builtins_bitcode-8da0901c58a73ebf.bc` - except
|
||||
> probably with a different hash before the `.bc`. If there's more than one
|
||||
> `*.bc` file in that directory, delete the whole `deps/` directory and re-run
|
||||
> the `cargo rustc` command above to regenerate it.
|
||||
|
||||
**Note**: In order to be able to address the bitcode functions by name, they need to be defined with the `#[no_mangle]` attribute.
|
||||
|
||||
The bitcode is a bunch of bytes that aren't particularly human-readable.
|
||||
Since Roc is designed to be distributed as a single binary, these bytes
|
||||
need to be included in the raw source somewhere.
|
||||
|
||||
The `llvm/src/build.rs` file statically imports these raw bytes
|
||||
using the [`include_bytes!` macro](https://doc.rust-lang.org/std/macro.include_bytes.html).
|
||||
The current `.bc` file is located at:
|
||||
|
||||
```
|
||||
compiler/gen/src/llvm/builtins.bc
|
||||
```
|
||||
|
||||
The script will automatically replace this `.bc` file with the new one.
|
||||
|
||||
Once that's done, `git status` should show that the `builtins.bc` file
|
||||
has been changed. Commit that change and you're done!
|
||||
The `llvm/src/build.rs` file statically imports these raw bytes.
|
||||
|
||||
## Calling bitcode functions
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
# Clear out any existing output files
|
||||
rm -rf ./out
|
||||
mkdir ./out
|
||||
|
||||
# Regenerate the .bc file
|
||||
clang -emit-llvm -o out/lib.bc -c src/lib.c
|
||||
|
||||
# Copy bc file for it to be used
|
||||
cp ./out/lib.bc "$1"
|
23
compiler/gen/build.rs
Normal file
23
compiler/gen/build.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let src_path = fs::canonicalize("./../builtins/bitcode/src/lib.c")
|
||||
.expect("Failed to resolve bitcode source");
|
||||
let src = src_path.to_str().expect("Invalid src path");
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("builtins.bc");
|
||||
let dest = dest_path.to_str().expect("Invalid dest path");
|
||||
|
||||
Command::new("clang")
|
||||
.args(&["-emit-llvm", "-o", dest, "-c", src])
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed={}", src);
|
||||
println!("cargo:rustc-env=BUILTINS_BC={}", dest);
|
||||
}
|
@ -34,6 +34,8 @@ use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::{JoinPointId, Wrapped};
|
||||
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
||||
use std::fs::File;
|
||||
use std::io::prelude::Read;
|
||||
use target_lexicon::CallingConvention;
|
||||
|
||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||
@ -181,8 +183,19 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
}
|
||||
|
||||
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
||||
let memory_buffer =
|
||||
MemoryBuffer::create_from_memory_range(include_bytes!("builtins.bc"), module_name);
|
||||
// In the build script for the gen module, we compile the builtins bitcode and set
|
||||
// BUILTINS_BC to the path to the compiled output.
|
||||
let path: &'static str = env!(
|
||||
"BUILTINS_BC",
|
||||
"Env var BUILTINS_BC not found. Is there a problem with the build script?"
|
||||
);
|
||||
let mut builtins_bitcode = File::open(path).expect("Unable to find builtins bitcode source");
|
||||
let mut buffer = std::vec::Vec::new();
|
||||
builtins_bitcode
|
||||
.read_to_end(&mut buffer)
|
||||
.expect("Unable to read builtins bitcode");
|
||||
|
||||
let memory_buffer = MemoryBuffer::create_from_memory_range(&buffer, module_name);
|
||||
|
||||
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user