Rust Development Environment

Compiling and Running Programs

In Rust, turning source code into a running program is a two-step process: first, the compiler translates .rs source files into a standalone native binary executable; second, the operating system loads and executes that binary. You can perform these steps either manually with rustc (for single files) or automatically with cargo (for projects).

Workflow Comparison: rustc vs cargo

1. Single-File Manual Workflow (`rustc`):
   main.rs  ──[ rustc --edition 2024 main.rs ]──>  ./main  ──[ ./main ]──>  Program Output

2. Project Workflow (`cargo`):
   src/main.rs ──[ cargo build ]──> target/debug/<pkg> ──[ ./target/debug/<pkg> ]──> Output
        │                                                                              ^
        └────────────────────────────[ cargo run ]─────────────────────────────────────┘
                               (Compiles if needed + runs in one command)
Workflow Command to Compile Only Command to Compile & Run Output Binary Location
Single file (rustc) rustc --edition 2024 file.rs rustc --edition 2024 file.rs && ./file ./file (current directory)
Cargo debug mode cargo build cargo run target/debug/<package_name>
Cargo release mode cargo build --release cargo run --release target/release/<package_name>
Type-check only (no binary) cargo check N/A Metadata only in target/debug/deps/

Compiling and Running a Single File with rustc

For quick experiments or single-file programs that do not depend on external crates from crates.io, compile the file with rustc and execute the resulting binary:

// greet.rs
fn main() {
    let args: Vec<String> = std::env::args().collect();
    println!("Executable path: {}", args[0]);
    println!("Arguments passed: {:?}", &args[1..]);
}
rustc --edition 2024 greet.rs
./greet alpha beta
Executable path: ./greet
Arguments passed: ["alpha", "beta"]

Once ./greet is compiled, it is a self-contained native machine binary. You can run ./greet as many times as you like—or copy it to another machine with the same OS and CPU architecture—without invoking rustc again.

Compiling and Running a Project with cargo

Inside a Cargo project directory, cargo build compiles the project without running it, while cargo run compiles any modified files and immediately launches the binary:

cargo build
./target/debug/my_project

Or in a single step:

cargo run
   Compiling my_project v0.1.0 (/Users/username/my_project)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/my_project`
Hello, world!

Incremental Rebuilds

If you run cargo run a second time without modifying any .rs files or Cargo.toml, Cargo detects that the binary in target/debug/ is already up to date, skips rustc completely, and executes the binary immediately:

cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/my_project`
Hello, world!

Suppressing Cargo Status Lines (--quiet / -q)

By default, Cargo prints Compiling, Finished, and Running status lines to standard error (stderr). Pass -q (or --quiet) to suppress Cargo's status messages so only your program's output appears in the terminal:

cargo run -q
Hello, world!

Passing Command-Line Arguments to Your Program

When using cargo run, place a double dash (--) between Cargo's own flags and the arguments intended for your program:

cargo run -q -- --input data.csv --limit 50

Everything before -- (-q) configures cargo, and everything after -- (--input data.csv --limit 50) is passed directly to your binary's main function via std::env::args().

Exit Codes and Process Termination

When main() finishes normally, the Rust runtime exits the process with status code 0 (indicating success to the operating system shell).

  • If the program panics (panic!("...")) or returns an Err from fn main() -> Result<(), E>, the process exits with a non-zero status code (101 for panics, 1 for Err).
  • In shell scripts, you can inspect the exit code of the last run via $? (echo $?).