Compiling and running
How a .nu source file becomes a native binary.
A NURL source file goes through two stages to become a program you can run:
hello.nu → (nurlc) → hello.ll (LLVM IR — a text format, human-readable)
hello.ll → (clang) → hello (native binary for your machine)nurlc (the NURL compiler) never touches your CPU's instruction set
directly. It emits LLVM IR and hands that to
clang, which turns it into a real binary. This is the
same backend Rust and Swift use.
Script compiling
If you built NURL from source, ./nurl.sh (or nurl.bat) drives
both stages for you:
./nurl.sh hello.nu # → ./hello
./nurl.sh hello.nu myprogram # → ./myprogramUseful flags (put them before the source file):
| Flag | Effect |
|---|---|
-O0 … -O3 | Optimization level passed to clang (default -O2) |
-g, --debug | Include debug info |
--emit-ir | Stop after stage 1 — just produce the .ll file, do not link |
--emit-asm | Emit native assembly (.s), skip linking |
At the default -O2, clang inlines and reorders code aggressively.
A debugger's "break at this source line" becomes unreliable, because
the line may not correspond to a single instruction anymore. -O0 keeps
the generated code close to the source structure, which you want
when you step through a bug, at the cost of a slower binary. Reach for
-O2/-O3 again after debugging.
Manual compiling
./build/nurlc hello.nu > hello.ll
clang hello.ll stdlib/runtime.native.o -lm -lpthread -o hello
./helloLink against stdlib/runtime.native.o, not stdlib/runtime.o — after a
normal build the latter is LLVM bitcode (for link-time optimization), and a
plain clang link rejects it with "file format not recognized".
nurlc emits only the functions your main can actually reach. An
import brings in a whole module — importing stdlib/ext/json.nu for
json_parse also brings the pretty-printer, the comparison helpers
and the float formatter — and handing all of that to clang means
paying for optimizing code the linker then throws away. Dropping it
at the source of the IR instead is worth 30–40% of the clang step
on a stdlib-heavy program.
The binary is unchanged: link-time optimization was already removing
the same code, just later. Reachability is computed over the finished
IR, so closures, generic instantiations, destructors and dynamic
trait vtables are all handled without special cases, and a file with
no main — a module you intend to link into something else — is
left whole. nurlc --no-dce emits everything, which is what you want
when diffing IR against an older compiler.
If you installed the prebuilt toolchain
The prebuilt curl | sh installer gives you nurlc, nurlpkg, and
nurlfmt, but not the nurl.sh convenience wrapper or a local runtime. See Installation from source.
Compiling to WebAssembly
See the online playground
to try NURL in the browser without an install, and
docs/PLATFORMS.md
for the full target list when you are ready to cross-compile.
Last updated on