---
title: Build Integration
description: Compile a Rust Thru program with cargo, the RISC-V target, the SDK
  linker script, and the make integration.
source_url:
  html: https://thru.org/docs/sdks/rust-program-sdk/build-integration/
  md: https://thru.org/docs/sdks/rust-program-sdk/build-integration.md
---

# Build Integration

Use this page when you need to compile a Rust program against the installed SDK and produce a deployable binary.

## Prerequisites

Start with [Set Up Thru DevKit](https://thru.org/docs/program-development/setting-up-thru-devkit.md), then install the SDK:

```bash
thru dev toolchain install
thru dev sdk install rust
```

The CLI installs the Rust SDK under `~/.thru/sdk/rust`. Programs are compiled by `cargo` for `riscv64imac-unknown-none-elf`, and the raw binary is produced by `cargo objcopy` from `cargo-binutils`:

```bash
rustup target add riscv64imac-unknown-none-elf
cargo install cargo-binutils
rustup component add llvm-tools
```

## Project layout

A downstream project needs four things copied or referenced from the SDK: the two crates as path dependencies, `build.rs`, `link.x.in`, and `.cargo/config.toml`.

```text
my-thru-project/
├── .cargo/config.toml
├── Cargo.toml
├── build.rs
├── link.x.in
└── src/main.rs
```

## `Cargo.toml`

**Cargo.toml**

```toml
[package]
name = "my-thru-project"
version = "0.1.0"
edition = "2021"

[dependencies]
thru-core = { path = "../thru-rust-sdk/core" }
thru-sdk-macros = { path = "../thru-rust-sdk/macros" }

[profile.release]
panic = "abort"
opt-level = "z"
lto = true
codegen-units = 1
debug = 2
strip = false
```

`panic = "abort"` is required: the SDK is `no_std` and provides its own panic handler. Keeping `debug = 2` and `strip = false` preserves the DWARF info that `thru debug resolve` needs to map program counters back to source lines.

## `.cargo/config.toml`

**.cargo/config.toml**

```toml
[build]
target = "riscv64imac-unknown-none-elf"

[target.riscv64imac-unknown-none-elf]
rustflags = [
  "-C", "target-feature=+crt-static",
  "-C", "target-feature=-a,+zba,+zbb,+zbc,+zbs",
  "-C", "link-arg=-Tlink.x",
]
```

The target features disable atomics and enable the bit-manipulation extensions the Thru VM supports. `-Tlink.x` selects the SDK linker script.

## `build.rs` and `link.x.in`

Copy both from the SDK root unchanged. `build.rs` copies `link.x.in` into `OUT_DIR` as `link.x` and adds it to the link search path:

**build.rs**

```rust
use std::{env, fs, path::PathBuf};

fn main() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let dest_path = out_dir.join("link.x");

    let content = fs::read_to_string("link.x.in").unwrap();
    fs::write(dest_path, content).unwrap();

    println!("cargo:rustc-link-search={}", out_dir.display());
    println!("cargo:rerun-if-changed=link.x.in");
}
```

`link.x.in` emits the 8-byte Thru VM program header, then places `.text._start` and `.text.start` — the sections the `#[entry]` macro generates — at the start of the image. Do not reorder or drop those `KEEP` entries.

## Build

```bash
cargo build --release --bin my-thru-project
cargo objcopy --release --bin my-thru-project -- -O binary my-thru-project.bin
```

The ELF lands in `target/riscv64imac-unknown-none-elf/release/`, and `my-thru-project.bin` is the raw image you deploy. Keep the ELF: it carries the debug info for symbolization.

## Make integration

The SDK also ships a make wrapper for projects that prefer `make` over raw cargo. `thru_rust_sdk.mk` includes the base configuration, the Thru VM machine configuration (`RUST_TARGET`, `CARGO_BUILD_FLAGS`, `CARGO_PROFILE_DIR`), and the rule generator:

**GNUmakefile**

```makefile
THRU_RUST_SDK_DIR := $(HOME)/.thru/sdk/rust/thru-sdk
include $(THRU_RUST_SDK_DIR)/thru_rust_sdk.mk
```

Every `Local.mk` under the project is discovered automatically. Declare each program there, where the first argument is the output name and the second is the cargo example name — the make wrapper builds cargo *examples*, so program sources live in `examples/`:

**Local.mk**

```makefile
$(call make-cargo-bin,my_thru_program,my_thru_program)
```

`make` then writes both `build/thruvm/bin/my_thru_program.bin` and `.elf`. `make clean` and `make distclean` also run `cargo clean`.

## Deploy

Deployment is the same as for C programs — create the program account from the `.bin` and execute against it. See [Build a C Program](https://thru.org/docs/program-development/building-a-c-program.md) for the CLI sequence and [Program development lifecycle](https://thru.org/docs/program-development/program-development-lifecycle.md) for the wider workflow.

## Related pages

- [Program Structure](https://thru.org/docs/sdks/rust-program-sdk/program-structure.md)
- [Set Up Thru DevKit](https://thru.org/docs/program-development/setting-up-thru-devkit.md)
- [Debugging](https://thru.org/docs/program-development/debugging.md)
