Awesome
<div align="center">⚡ Cairo Native ⚡
A compiler to convert Cairo's intermediate representation "Sierra" code <br> to machine code via MLIR and LLVM.
</div>For in-depth documentation, see the developer documentation.
Disclaimer
🚧 Cairo Native is still being built therefore API breaking changes might happen often so use it at your own risk. 🚧
For versions under 1.0
cargo
doesn't comply with
semver, so we advise to pin the version the version you
use. This can be done by adding cairo-native = "0.1.0"
to your Cargo.toml
Getting Started
Dependencies
- Linux or macOS (aarch64 included) only for now
- LLVM 18 with MLIR: On debian you can use apt.llvm.org, on macOS you can use brew
- Rust 1.78.0 or later, since we make use of the u128 abi change.
- Git
Setup
This step applies to all operating systems.
Run the following make target to install the dependencies (both Linux and macOS):
make deps
Linux
Since Linux distributions change widely, you need to install LLVM 18 via your package manager, compile it or check if the current release has a Linux binary.
If you are on Debian/Ubuntu, check out the repository https://apt.llvm.org/ Then you can install with:
sudo apt-get install llvm-18 llvm-18-dev llvm-18-runtime clang-18 clang-tools-18 lld-18 libpolly-18-dev libmlir-18-dev mlir-18-tools
If you decide to build from source, here are some indications:
<details><summary>Install LLVM from source instructions</summary># Go to https://github.com/llvm/llvm-project/releases
# Download the latest LLVM 18 release:
# The blob to download is called llvm-project-18.x.x.src.tar.xz
# For example
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.7/llvm-project-18.1.7.src.tar.xz
tar xf llvm-project-18.1.7.src.tar.xz
cd llvm-project-18.1.7.src.tar
mkdir build
cd build
# The following cmake command configures the build to be installed to /opt/llvm-18
cmake -G Ninja ../llvm \
-DLLVM_ENABLE_PROJECTS="mlir;clang;clang-tools-extra;lld;polly" \
-DLLVM_BUILD_EXAMPLES=OFF \
-DLLVM_TARGETS_TO_BUILD="Native" \
-DCMAKE_INSTALL_PREFIX=/opt/llvm-18 \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DLLVM_PARALLEL_LINK_JOBS=4 \
-DLLVM_ENABLE_BINDINGS=OFF \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_ENABLE_LLD=ON \
-DLLVM_ENABLE_ASSERTIONS=OFF
ninja install
</details>
Setup a environment variable called MLIR_SYS_180_PREFIX
, LLVM_SYS_181_PREFIX
and TABLEGEN_180_PREFIX
pointing to the llvm directory:
# For Debian/Ubuntu using the repository, the path will be /usr/lib/llvm-18
export MLIR_SYS_180_PREFIX=/usr/lib/llvm-18
export LLVM_SYS_181_PREFIX=/usr/lib/llvm-18
export TABLEGEN_180_PREFIX=/usr/lib/llvm-18
Alternatively, if installed from Debian/Ubuntu repository, then you can use
env.sh
to automatically setup the environment variables.
source env.sh
MacOS
The makefile deps
target (which you should have ran before) installs LLVM 18
with brew for you, afterwards you need to execute the env.sh
script to setup
the needed environment variables.
source env.sh
Make targets:
Running make
by itself will check whether the required LLVM installation and
corelib is found, and then list available targets.
% make
LLVM is correctly set at /opt/homebrew/opt/llvm.
./scripts/check-corelib-version.sh 2.6.4
Usage:
deps: Installs the necesary dependencies.
build: Builds the cairo-native library and binaries in release mode.
build-native: Builds cairo-native with the target-cpu=native rust flag.
build-dev: Builds cairo-native under a development-optimized profile.
runtime: Builds the runtime library required for AOT compilation.
check: Checks format and lints.
test: Runs all tests.
proptest: Runs property tests.
coverage: Runs all tests and computes test coverage.
doc: Builds documentation.
doc-open: Builds and opens documentation in browser.
bench: Runs the hyperfine benchmark script.
bench-ci: Runs the criterion benchmarks for CI.
install: Invokes cargo to install the cairo-native tools.
clean: Cleans the built artifacts.
stress-test Runs a command which runs stress tests.
stress-plot Plots the results of the stress test command.
stress-clean Clean the cache of AOT compiled code of the stress test command.
Included Tools
Aside from the compilation and execution engine library, Cairo Native includes a few command-line tools to aid development, and some useful scripts.
These are:
- The contents of the
/scripts/
folder cairo-native-compile
cairo-native-dump
cairo-native-run
cairo-native-test
cairo-native-stress
scarb-native-dump
scarb-native-test
cairo-native-compile
Compiles a Cairo project outputting the generated MLIR and the shared library.
Exits with 1 if the compilation or run fails, otherwise 0.
Usage: cairo-native-compile [OPTIONS] <PATH> [OUTPUT_MLIR] [OUTPUT_LIBRARY]
Arguments:
<PATH> The Cairo project path to compile and run its tests
[OUTPUT_MLIR] The output path for the mlir, if none is passed, out.mlir will be the default
[OUTPUT_LIBRARY] If a path is passed, a dynamic library will be compiled and saved at that path
Options:
-s, --single-file Whether path is a single file
--allow-warnings Allows the compilation to succeed with warnings
-r, --replace-ids Replaces sierra ids with human-readable ones
-O, --opt-level <OPT_LEVEL> Optimization level, Valid: 0, 1, 2, 3. Values higher than 3 are considered as 3 [default: 0]
-h, --help Print help
-V, --version Print version
cairo-native-dump
Usage: cairo-native-dump [OPTIONS] <INPUT>
Arguments:
<INPUT>
Options:
-o, --output <OUTPUT> [default: -]
--starknet Compile a starknet contract
-h, --help Print help
cairo-native-run
This tool allows to run programs using the JIT engine, like the cairo-run
tool, the parameters can only be felt values.
Example: echo '1' | cairo-native-run 'program.cairo' 'program::program::main' --inputs - --outputs -
Exits with 1 if the compilation or run fails, otherwise 0.
Usage: cairo-native-run [OPTIONS] <PATH>
Arguments:
<PATH> The Cairo project path to compile and run its tests
Options:
-s, --single-file Whether path is a single file
--allow-warnings Allows the compilation to succeed with warnings
--available-gas <AVAILABLE_GAS> In cases where gas is available, the amount of provided gas
--run-mode <RUN_MODE> Run with JIT or AOT (compiled) [default: jit] [possible values: aot, jit]
-O, --opt-level <OPT_LEVEL> Optimization level, Valid: 0, 1, 2, 3. Values higher than 3 are considered as 3 [default: 0]
-h, --help Print help
-V, --version Print version
cairo-native-test
This tool mimics the cairo-test
tool
and is identical to it in interface, the only feature it doesn't have is the profiler.
Compiles a Cairo project and runs all the functions marked as `#[test]`.
Exits with 1 if the compilation or run fails, otherwise 0.
Usage: cairo-native-test [OPTIONS] <PATH>
Arguments:
<PATH> The Cairo project path to compile and run its tests
Options:
-s, --single-file Whether path is a single file
--allow-warnings Allows the compilation to succeed with warnings
-f, --filter <FILTER> The filter for the tests, running only tests containing the filter string [default: ]
--include-ignored Should we run ignored tests as well
--ignored Should we run only the ignored tests
--starknet Should we add the starknet plugin to run the tests
--run-mode <RUN_MODE> Run with JIT or AOT (compiled) [default: jit] [possible values: aot, jit]
-O, --opt-level <OPT_LEVEL> Optimization level, Valid: 0, 1, 2, 3. Values higher than 3 are considered as 3 [default: 0]
-h, --help Print help
-V, --version Print version
For single files, you can use the -s, --single-file
option.
For a project, it needs to have a cairo_project.toml
specifying the
crate_roots
. You can find an example under the cairo-tests/
folder, which
is a cairo project that works with this tool.
cairo-native-test -s myfile.cairo
cairo-native-test ./cairo-tests/
This will run all the tests (functions marked with the #[test]
attribute).
cairo-native-stress
This tool runs a stress test on Cairo Native.
A stress tester for Cairo Native
It compiles Sierra programs with Cairo Native, caches, and executes them with AOT runner. The compiled dynamic libraries are stored in `AOT_CACHE_DIR` relative to the current working directory.
Usage: cairo-native-stress [OPTIONS] <ROUNDS>
Arguments:
<ROUNDS>
Amount of rounds to execute
Options:
-o, --output <OUTPUT>
Output file for JSON formatted logs
-h, --help
Print help (see a summary with '-h')
To quickly run a stress test and save logs as json, run:
make stress-test
This takes a lot of time to finish (it will probably crash first), you can kill the program at any time.
To plot the results, run:
make stress-plot
To clear the cache directory, run:
make stress-clean
scarb-native-dump
This tool mimics the scarb build
command.
You can download it on our releases page.
This tool should be run at the directory where a Scarb.toml
file is and it will
behave like scarb build
, leaving the MLIR files under the target/
folder
besides the generated JSON sierra files.
scarb-native-test
This tool mimics the scarb test
command.
You can download it on our releases page.
Compiles all packages from a Scarb project matching `packages_filter` and
runs all functions marked with `#[test]`. Exits with 1 if the compilation
or run fails, otherwise 0.
Usage: scarb-native-test [OPTIONS]
Options:
-p, --package <SPEC> Packages to run this command on, can be a concrete package name (`foobar`) or a prefix glob (`foo*`) [env: SCARB_PACKAGES_FILTER=] [default: *]
-w, --workspace Run for all packages in the workspace
-f, --filter <FILTER> Run only tests whose name contain FILTER [default: ]
--include-ignored Run ignored and not ignored tests
--ignored Run only ignored tests
--run-mode <RUN_MODE> Run with JIT or AOT (compiled) [default: jit] [possible values: aot, jit]
-O, --opt-level <OPT_LEVEL> Optimization level, Valid: 0, 1, 2, 3. Values higher than 3 are considered as 3 [default: 0]
-h, --help Print help
-V, --version Print version
Benchmarking
Requirements
- hyperfine:
cargo install hyperfine
- cairo 2.7.1
- Cairo Corelibs
- LLVM 18 with MLIR
You need to setup some environment variables:
$MLIR_SYS_180_PREFIX=/path/to/llvm18 # Required for non-standard LLVM install locations.
$LLVM_SYS_181_PREFIX=/path/to/llvm18 # Required for non-standard LLVM install locations.
$TABLEGEN_180_PREFIX=/path/to/llvm18 # Required for non-standard LLVM install locations.
You can then run the bench
makefile target:
make bench
The bench
target will run the ./scripts/bench-hyperfine.sh
script.
This script runs hyperfine commands to compare the execution time of programs in the ./programs/benches/
folder.
Each program is compiled and executed via the execution engine with the cairo-native-run
command and via the cairo-vm with the cairo-run
command provided by the cairo
codebase.
The cairo-run
command should be available in the $PATH
and ideally compiled with cargo build --release
.
If you want the benchmarks to run using a specific build, or the cairo-run
commands conflicts with something (e.g. the cairo-svg package binaries in macos) then the command to run cairo-run
with a full path can be specified with the $CAIRO_RUN
environment variable.