ourc Node: 1 Using ourc Next: 2 Reference Prev: Top Up: Top

1 Using ourc

ourc is a Rust compiler written in Rust that compiles itself. It reads a single Rust source file and emits LLVM IR. With -o it then runs llc and the system C compiler to produce a native executable.

The promise of v0.1: ourc compiles a subset of Rust correctly, and refuses the rest.

1.1 Install

The release tarballunpack it; put ourc on your PATHtrust the published binary, or check it against SHA256SUMS
With cargo$ cargo install ourctrust rustc; about a minute
From the hand-written hex$ cargo install ourc-bootstrap
$ ourc-bootstrap OUT
trust only the hex; LLVM for machine code. About 20 minutes

All three give the same compiler: ourc built by rustc and ourc built from the hex emit byte-identical LLVM IR for ourc’s own source. ourc needs x86-64 Linux, llc from LLVM 16 or newer (on PATH, or named by $LLC), and a C compiler to link: cc on PATH, or named by $CC.

1.2 Usage

$ ourc prog.rs -o prog        # compile and link an executable
$ ourc prog.rs --emit-ir      # LLVM IR on stdout; status and errors on stderr

A rejected program prints ourc[O0] prog.rs -> error[lo..hi]: … on stderr and exits 1, and no file is written. A compile that hits a limit, or an internal crash, also exits 1 with a one-line message saying which.

1.3 Options

-o PATHBuild an executable at PATH: runs ${LLC:-llc} -O2, then ${CC:-cc}.
--emit-irPrint the LLVM IR module on stdout instead of linking.
-OAccepted for compatibility; executables are always built with llc -O2.
--time-limit NRefuse a compile that runs longer than N seconds. Default 25; 0 means no limit.
--mem-limit GBRefuse a compile that needs more than GB GiB of memory. Default 8; 0 means no limit.

1.4 An example

hello.rs ×
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// hello.rs
struct Point { x: i32, y: i32 }

fn dist2(p: &Point) -> i32 {
    p.x * p.x + p.y * p.y
}

fn main() {
    let pts = vec![Point { x: 3, y: 4 }, Point { x: 1, y: 1 }];
    let mut total = 0;
    for p in pts.iter() {
        total += dist2(p);
    }
    println!("sum of squared distances: {}", total);
}
$ ourc hello.rs -o hello
ourc[O0] hello.rs -> ok int = <runtime> [hir=2 mir=3] ir_lines=10
$ ./hello
sum of squared distances: 27
accepted · hello.rsRust

1.5 Self-hosting

ourc compiles its own source, about 50,000 lines, and reaches a fixed point. ourc′ is ourc built by ourc, and ourc″ is ourc′ built by ourc′.

ourc

built by SEM0, from the hex

ourc′

ourc built by ourc

ourc″

ourc′ built by ourc′

The SEM0-built ourc, ourc′ and ourc″ all emit byte-identical IR for ourc’s own source, and ourc′ and ourc″ are byte-identical executables. A self-build needs --mem-limit 0 --time-limit 0: it takes about 14 s and peaks near 20 GB.

1.6 Reporting a wrong answer

A program that ourc accepts and that then behaves differently from rustc’s build is a bug in the promise, the most important kind of bug ourc can have. Please report it with the program, both outputs, and the first stderr line of ourc --emit-ir.