/commands/rust/rustc-compile-single-file
rustc main.rs: compile and run a single Rust file without Cargo
- tool
- Rust
- versions
- Rust 1.x, edition 2024: Rust 1.85+
- os
- linux, macos, windows
rustc main.rs compiles one Rust source file into an executable named after it (main, or main.exe on Windows) in the current directory; run it with ./main. It is the quickest way to try a snippet without creating a Cargo project. Add --edition 2024 to use the current edition (the default is 2015) and -O for an optimized build.
Compile and run
cat > main.rs <<'EOF'
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let name = args.first().map(String::as_str).unwrap_or("world");
let total: u64 = (1..=10).sum();
println!("hello, {name}! sum 1..=10 = {total}");
}
EOF
rustc --edition 2024 main.rs
./main
./main rustc
rustc --edition 2024 -O -o fast main.rs && ./fast optimizedOutput
hello, world! sum 1..=10 = 55 hello, rustc! sum 1..=10 = 55 hello, optimized! sum 1..=10 = 55
-o fast picks the output name. On Windows rustc also writes a .pdb debug-information file next to the .exe.
Common options
| Option | Effect |
|---|---|
| --edition 2024 | Compile with the 2024 edition rules (2015 is the default; 2018 and 2021 also exist) |
| -O | Optimize, same as -C opt-level=3 |
| -o NAME | Name of the output file |
| -g | Include debug information (-C debuginfo=2) |
| --crate-type lib | Build a library (.rlib) instead of an executable |
| --target TRIPLE | Cross-compile, for example --target wasm32-unknown-unknown (the target must be installed with rustup) |
| -C target-cpu=native | Use every instruction of the CPU that compiles the program |
| --test | Build a test runner from the #[test] functions in the file |
Errors and warnings
rustc stops on the first stage that fails and prints errors with a code, the file, line and column, and a hint:
cat > bad.rs <<'EOF'
fn main() {
let count: i32 = "3";
println!("{count}");
}
EOF
rustc --edition 2024 bad.rsOutput · exit 1
error[E0308]: mismatched types --> bad.rs:2:22 | 2 | let count: i32 = "3"; | --- ^^^ expected `i32`, found `&str` | | | expected due to this error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`.
The code in brackets (here E0308) can be looked up with rustc --explain. Warnings, such as unused variables, do not stop the build; -D warnings turns them into errors.
rustc or cargo?
Use rustc for single-file experiments, teaching and quick checks. Use Cargo as soon as you need dependencies, several files with tests, or a reproducible build: cargo new creates the project, cargo run compiles and runs it, and cargo build --release is the optimized build. Cargo calls rustc for you with the right flags, edition and dependency paths.
Pitfalls
- Old edition by default. Without
--edition, code that usesasync fn,dynrules or other later syntax may fail to compile or warn. Pass the edition explicitly. - Debug builds are slow and panic on integer overflow; release builds wrap around instead. Measure performance only with
-O. ./mainnot found on Windows cmd. Incmd.exeor PowerShell, runmain.exeor.\main.exe;./mainis the Unix and Git Bash spelling.- Linker errors (
linker 'cc' not foundon Linux,link.exenot found on Windows) mean the system linker is missing, not a problem in your code: install the platform's C build tools.
Confirm it worked
The executable exists next to the source and runs. rustc --version shows which compiler built it.
FAQ
Why does a program compiled with rustc main.rs run slowly?
rustc builds without optimizations by default (opt-level 0) and with debug assertions such as integer overflow checks. Add -O, or -C opt-level=3, for a release-like build.
Can I use crates from crates.io with plain rustc?
Not practically. rustc only links crates you pass with --extern and -L paths; downloading and building dependencies is Cargo's job. Create a project with cargo new as soon as you need a dependency.
Which edition does rustc use if I do not pass --edition?
Edition 2015, for backward compatibility. Cargo projects set the edition in Cargo.toml instead, and cargo new writes the latest one.