CLI Usage Guide
Complete reference for the neurc command-line compiler.
Installation
After building from source:
# Install compiler globally
cargo install --path compiler/neurc
# Or run directly from source
cargo run -p neurc -- <command> <args>Commands
check
Validate syntax and types without generating code.
Syntax:
neurc check <file.nr>Examples:
# Check a single file
neurc check examples/basics/hello.nr
# With debug logging
RUST_LOG=debug neurc check examples/basics/function_call.nrOutput:
- Success:
Type checking passed for "examples/basics/hello.nr" (1 module(s), N HIR items), whereNcounts the implicit prelude's items as well as the file's - Failure:
Type errors found in "<file>":, then one located diagnostic per error, thenError: N type error(s) found
Exit codes:
- 0: No errors found
- 1: Errors found
compile
Compile Neuro source to native executable.
Syntax:
neurc compile <file.nr> [options]Options:
-o, --output <FILE>: output path (default: the input filename without its extension)-O, --optimization <0-3>: optimization level (default:0); see Optimization--emit <exe|obj|llvm-ir>: artifact to write (default:exe); see Emitting an object file and Emitting LLVM IR--gpu-arch <CHIP>: the GPU that@gpukernels andDevice::GPUtensors are built for (default:sm_60); see Choosing a GPU.runtakes it too
Examples:
# Default output (hello.exe on Windows)
neurc compile examples/basics/hello.nr
# Custom output path
neurc compile examples/basics/hello.nr -o bin/my_program
# Custom output with .exe extension
neurc compile examples/basics/hello.nr -o bin/my_program.exe
# Compile from different directory
neurc compile ../path/to/program.nr
# With debug logging
RUST_LOG=debug neurc compile examples/basics/hello.nrChoosing a GPU
--gpu-arch names a chip, and the prefix picks the vendor. sm_NN is an NVIDIA compute
capability. The kernels ship as PTX, which the CUDA driver compiles for any GPU at or above it,
so the default sm_60 covers every recent NVIDIA card. gfxNNN is an AMD architecture. The
kernels are compiled to a code object for exactly that chip, and the program opens HIP
(libamdhip64.so) instead of the CUDA driver.
neurc compile --gpu-arch gfx90a model.nr # an MI200-series GPUCompiling for AMD needs ROCm, because the code object is linked with ROCm's ld.lld
($ROCM_PATH/llvm/bin/ld.lld, /opt/rocm by default); without it the compile fails and says
so. Running needs the HIP runtime and a GPU of that architecture. A program that only moves
tensors with .to(Device::GPU(0)) links the same runtime, so the flag matters for it too.
neurc refuses a chip name with neither prefix, or one LLVM 23 has no processor for.
Emitting an object file
--emit obj stops before the linker and writes the object file to the output path. Because
an object may be a library, it does not require a main function; the default
--emit exe still does.
This is how a Neuro module is made callable from another language. A tensor value is a
DLPack handle (see tensors), so a function returning
Tensor<T, S> returns a DLManagedTensorVersioned* that NumPy, PyTorch or JAX consumes
with no conversion step:
neurc compile --emit obj -o tensors.o tensors.nr
cc -shared -o libtensors.so tensors.o -lmimport ctypes, numpy as nplib = ctypes.CDLL("./libtensors.so")lib.make_batch.restype = ctypes.c_void_ptools/dlpack_differential.py is a worked version of exactly this: it links a library of
tensor-returning functions and checks every result against NumPy's own, reading dtype, rank,
extents and strides from the handle. Run it with
python tools/dlpack_differential.py --neurc target/debug/neurc, or as part of the suite
through cargo test -p neurc --test numpy_differential.
tools/grad_differential.py links the same way for a different reason: it calls compiled
scalar functions at perturbed points and takes their gradients by central differences, which
is how a derivative this compiler generates gets checked against a computation that shares
none of its machinery. Run it with
python tools/grad_differential.py --neurc target/debug/neurc, or through
cargo test -p neurc --test grad_differential.
neurc does not link the shared library itself: -shared is the platform C compiler's job,
and on Windows a DLL additionally needs an export list.
Emitting LLVM IR
--emit llvm-ir stops before instruction selection and writes the textual module (default
output: the input name with .ll). Like --emit obj it does not require a main function.
neurc compile --emit llvm-ir -o twice.ll twice.nrThe module carries the host data layout and triple, so it can be handed straight to opt,
llc or clang. -O still selects the middle-end pass pipeline: -O0 emits the module as
codegen built it, which is what a tool that rewrites the IR wants, and -O2 emits what the
object path would have given the backend.
Output:
- Success:
Successfully compiled <input.nr> -> <output_path> - Failure: the failing stage's errors, then
Compilation failed: <reason>plus a numberedCaused by (n):chain
Exit codes:
- 0: Compilation successful
- 1: Compilation failed
- 2: the command line itself was rejected (an unknown flag,
-O4, a--gpu-archwith neither prefix), before any file was read. This holds for every command
-o may not name a source file of the program being compiled: neurc refuses rather than
overwrite it with the executable, object or IR.
run
Compile a source file and run the resulting program immediately.
Syntax:
neurc run <file.nr> [options]Options:
-O, --optimization <0-3>: optimization level (default:0); see Optimization--gpu-arch <CHIP>: as forcompile; see Choosing a GPU
The executable is written to a temporary directory and removed once the program exits, so
run never leaves a binary beside the source. Use compile when you want to keep one.
Examples:
neurc run examples/basics/hello.nr
neurc run examples/basics/hello.nr -O2Output: the program's own stdout and stderr, with no compiler banner. Compiler and
linker failures still report on stderr as Run failed: <reason> plus a Caused by (n): chain.
Exit codes:
- The program's own exit code, when it was built and started
- 1: compilation, linking, or process startup failed, or the program was killed by a signal
Environment Variables
RUST_LOG
Control logging verbosity:
# Windows (PowerShell)
$env:RUST_LOG="debug"
neurc compile program.nr
# Unix
RUST_LOG=debug neurc compile program.nrLevels:
error: only errorswarn: warnings and errorsinfo: informational messagesdebug: each compilation step (recommended for troubleshooting)trace: everything
Examples:
RUST_LOG=error neurc compile program.nr # Minimal output
RUST_LOG=info neurc compile program.nr # Standard output
RUST_LOG=debug neurc compile program.nr # Detailed diagnosticsLLVM_SYS_231_PREFIX, MLIR_SYS_230_PREFIX, TABLEGEN_230_PREFIX
Building the compiler needs all three, each pointing at the one prefix that holds LLVM 23 and MLIR 23:
prefix=/opt/llvm-mlir-23 # Arch / CachyOS (source build)
prefix=/usr/lib/llvm-23 # Ubuntu / Debian (apt.llvm.org)
prefix=$(brew --prefix llvm) # macOS
export LLVM_SYS_231_PREFIX=$prefix MLIR_SYS_230_PREFIX=$prefix TABLEGEN_230_PREFIX=$prefixSee the Installation Guide for full setup.
Workflow Examples
Basic Development
# 1. Write code in editor
vim program.nr
# 2. Check for errors (fast)
neurc check program.nr
# 3. Fix errors, re-check
neurc check program.nr
# 4. Compile when ready
neurc compile program.nr
# 5. Run executable
./program # Unix
.\program.exe # WindowsRapid Iteration
# Check-compile-run loop (Unix)
neurc check program.nr && neurc compile program.nr && ./program
# Windows (PowerShell)
neurc check program.nr; if ($?) { neurc compile program.nr; if ($?) { .\program.exe } }Debugging Compilation Issues
# Enable debug logging
RUST_LOG=debug neurc compile program.nr 2> debug.log
# Review debug.log for detailed diagnostics
cat debug.logOutput Files
Executable
Default executable naming:
- Windows:
<input>.exe(e.g.,program.nr→program.exe) - Unix:
<input>without extension (e.g.,program.nr→program)
Custom output with -o:
neurc compile program.nr -o custom_name
neurc compile program.nr -o bin/release/appTemporary Files
compile writes the object file (.o on Unix, .obj on Windows) into a fresh temporary
directory and removes the directory once linking finishes, whether the link succeeded or not.
--emit obj writes the object to the output path instead.
Error Handling
Errors go to stderr with exit code 1. compile wraps the failing stage's message in a
Compilation failed: line followed by a numbered Caused by (n): chain.
Parse Errors
Example:
error: unexpected token RightBrace, expected expression --> bad.nr:3:1 |3 | } | ^ Error: Parsing failedInformation provided:
- The file, line and column of the offending token (the end of the file when the input stopped early), with the source line underlined
- The offending token and what the parser expected
Type Errors
Example:
Type errors found in "bad.nr":error: type mismatch: expected i32, found bool --> bad.nr:2:5 |2 | val x: i32 = true | ^^^^^^^^^^^^^^^^^ Error: 1 type error(s) foundInformation provided:
- Every type error, not just the first: the type checker keeps going
- Each error's kind, the file, line and column it occurs at, the offending line of source with a caret under the span, and the expected/found types
- A use-after-move adds a
note: moved herepointing at where the value went
A program spread over several modules prints the message without a location: a span there indexes the module that raised the error rather than the file named on the command line.
Code Generation and Link Errors
Codegen failures print as Compilation failed: Code generation error: ...; link failures
name the linker invocation, for example:
Compilation failed: Failed to link object file to executable Caused by (1): Failed to execute cc - ensure a C compiler (gcc/clang) is installed Caused by (2): No such file or directory (os error 2)On Unix the linker driver is cc. On Windows neurc tries clang, then lld-link, then
MSVC's cl.exe, and when all three fail it reports each driver's own reason.
Common causes:
- Missing C toolchain (clang or MSVC on Windows, gcc/clang on Unix)
- Missing system libraries
Performance
Compilation Times
With a release build of neurc, check on any program in examples/ finishes in a few
milliseconds and compile (linking included) in well under a second. A debug build of neurc
itself is noticeably slower. For the speed of the programs it produces, see the
benchmarks.
Optimization
neurc compile supports optimization levels -O0 through -O3.
-O0: fastest compile, no optimization. A debug build: integer overflow panics-O1: basic optimization. From here up, integer overflow wraps-O2: balanced optimization (the usual choice for a release build)-O3: maximum optimization
Platform-Specific Notes
Windows
Requirements:
- MSVC Build Tools 2022
- LLVM 23 (the
clang+llvm-*-x86_64-pc-windows-msvcdevelopment archive) - a static libxml2 copied in as
xml2s.lib(see troubleshooting)
Executable extension: Always .exe
Path separators: Use backslashes or forward slashes
# Both workneurc compile examples\basics\hello.nrneurc compile examples/basics/hello.nrLinux
Requirements:
- GCC or Clang (
build-essentialon Debian,base-develon Arch) - LLVM 23
Executable extension: none
macOS
Requirements:
- Xcode Command Line Tools
- LLVM 23 (via Homebrew,
llvm)
Apple Silicon: supported
Executable extension: none
Advanced Usage
Target
neurc compiles for the host target only, and the linker driver is fixed (see
Code Generation and Link Errors).
Build Scripts
Integrate into build scripts:
#!/bin/bash
set -e
echo "Checking Neuro programs..."
neurc check src/main.nr
neurc check src/utils.nr
echo "Compiling..."
neurc compile src/main.nr -o bin/app
echo "Build complete!"CI/CD Integration
# Example GitHub Actions workflow- name: Install LLVM run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh sudo ./llvm.sh 23 sudo apt-get install -y llvm-23-dev libmlir-23-dev mlir-23-tools libpolly-23-dev libzstd-dev zlib1g-dev for var in LLVM_SYS_231_PREFIX MLIR_SYS_230_PREFIX TABLEGEN_230_PREFIX; do echo "$var=/usr/lib/llvm-23" >> "$GITHUB_ENV" done - name: Build Neuro compiler run: cargo build --release -p neurc - name: Compile program run: cargo run --release -p neurc -- compile program.nr - name: Run tests run: ./programTroubleshooting
See Troubleshooting Guide for common issues and solutions.
Planned
Debug information (neurc compile -g) and incremental compilation with a persistent cache
are on the roadmap; see the Quick Roadmap.