Getting Started rustup rustc cargo — the file that is not a crate
rustc compiles a file. cargo new makes a crate. The rest of the book assumes the crate.
<!-- hal:authoritative:yaml -->
rustc compiles a file. cargo new makes a crate. The rest of the book assumes the crate.
§I — Frame
Duha session 01. First fire of the TRPL spine. The chapter is Getting Started. Three moves: install the toolchain with rustup, print Hello, world! with rustc, then start the same program again with cargo new.
Nine flat applied lessons already sit in Polyglot-Dev/Rust/ (2026-05-20 through 2026-07-17). They are pair-refractions from an older Fajr habit. They are not this track. Ownership, typestate, and trait objects wait for their own chapters. Do not skip Ch.1 because those files exist.
The book is Klabnik and Nichols, official stable, on disk under 09-Tomes. Lattice does not index it yet. Ground from the chapter HTML. Bootcamp does not cover Rust. Blandy 2017 stays on the shelf today. Ch.1 already names rustup, rustc, and cargo. A second cite that repeats those three names is noise.
Coin the name now: the file that is not a crate.
A lone main.rs compiled with rustc is a file. It produces a binary next to the source. That is a real program. It is not a crate. A crate has a name, an edition, a src/ tree, a Cargo.toml, and later a Cargo.lock. cargo new exists because the rest of this book, and every crate you will clone, assumes that layout. If you stay on rustc main.rs past this chapter, you will have no place to put a dependency and no lockfile to pin it.
Done-criteria from the syllabus: rustc and cargo present; hello world builds; you can say why cargo new exists.
Castle already answers the first proof. rustc 1.96.0 (ac68faa20 2026-05-25), cargo 1.96.0 (30a34c682 2026-05-25), rustup 1.29.0. Still walk the install. The chapter is the install. Verification is not a skip.
§II — rustup: one installer, two binaries
The book installs Rust through rustup. rustup manages Rust versions and the tools that travel with them. You need a network for the first download. The installer puts the latest stable compiler on the machine. Stability means the examples that compile in the book keep compiling on newer stable releases. Error text can change. The programs should not.
On Linux or macOS the install command is one line:
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
The script installs rustup, then rustup installs stable Rust. A successful finish prints Rust is installed now. Great! You may be asked for a password. After the script, restart the shell or source the env file it names so ~/.cargo/bin is on PATH.
You also need a linker. Rust compiles to object files and a linker joins them into one executable. On macOS the linker arrives with a C compiler. If you see linker errors, run:
$ xcode-select --install
Linux users install GCC or Clang from the distribution. Ubuntu's package is build-essential. Windows is a different path: https://www.rust-lang.org/tools/install, then Visual Studio for the MSVC linker. This lesson is written on a Mac. If you refuse rustup, the book points at Other Rust Installation Methods on the Rust Forge. Distro packages lag.
Proof that the install landed:
$ rustc --version
You should see a version, a commit hash, and a date, in this shape:
rustc x.y.z (abcabcabc yyyy-mm-dd)
On castle today that line is rustc 1.96.0 (ac68faa20 2026-05-25). If the command is missing, PATH is the first suspect. On macOS and Linux: echo $PATH. You want ~/.cargo/bin in that list. On Windows CMD: echo %PATH%. In PowerShell: echo $env:Path. If PATH is correct and rustc still fails, the community page is the next stop.
cargo --version is the second proof. rustup installs cargo with rustc. If you installed Rust by some other method and cargo is missing, install cargo before you continue. The rest of the book assumes it.
Two maintenance commands:
$ rustup update
$ rustup self uninstall
The first moves you to a newer stable. The second removes rustup and the toolchains it manages. You will not uninstall today.
rustup doc opens the local copy of the documentation in a browser. The standard library API lives there. When a type or function is in std and you do not remember the signature, that is the page. You do not need a network for it after the install.
~/.cargo/bin holds the shims you type. rustup show prints the active toolchain. The book makes no demand about editors. Appendix D is the later pointer. Do not stop this session to pick an IDE. Ch.1 has no crates.io dependency; leave the book's later get-dependencies prefetch until you need it. Lines you type in the book start with $. Do not type the dollar.
§III — rustc: Hello, world! as a file
The book assumes you can use a terminal. Rust does not care where the file lives. For the exercises, make a projects directory in your home and keep the work there.
$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world
Create main.rs. Rust source ends in .rs. Multi-word names use _ between words: hello_world.rs, not helloworld.rs. Today's file is main.rs because main is the program.
Listing 1-1 in the book is three lines:
fn main() {
println!("Hello, world!");
}
Save it. From ~/projects/hello_world:
$ rustc main.rs
$ ./main
Hello, world!
On Windows the run line is .\main. Either way the terminal should print Hello, world!. If it does not, go back to the troubleshooting section of Installation and check PATH.
That is a compiled program. rustc is the compiler. You passed it a source file. It wrote a binary. On macOS and Linux ls now shows main and main.rs. On Windows CMD dir /B shows main.exe, main.pdb, and main.rs. The .pdb is debug information. The executable is what you ran.
Compilation and execution are separate steps. Rust is ahead-of-time compiled. You can hand someone the main binary and they can run it without Rust installed. rustc is close to gcc or clang if you have that background.
Anatomy, in the book's order.
fn main() { } declares a function named main. main is special. It is the first code that runs in every executable Rust program. This main takes no parameters and returns nothing. The body sits inside {}. Opening brace on the same line as the declaration, one space before it. rustfmt will enforce that. rustup already installed it.
The only statement in the body is println!("Hello, world!");.
Three facts.
First: println! is a macro. The ! is the tell. A function would be println without the bang. Macros generate code. They do not always obey function rules. Chapter 20 is the macros chapter. Today you need the bang. If you write println("Hello, world!") the compiler will refuse it.
Second: "Hello, world!" is a string argument. The macro writes that string to the screen, then a newline.
Third: the semicolon ends the statement. Most Rust lines end with one.
This main.rs is the file that is not a crate. It compiles. It runs. It has no package name, no edition key, no [dependencies] table, and no src/ directory. rustc is enough for a file. It is not enough for the rest of the book.
If you want a second print, add a second println! and compile again. rustc does not watch the file. Change the string, forget to compile, run the old binary. The binary is a snapshot. After rustc main.rs, ls shows main next to main.rs. If you later run cargo init without moving the source, crate metadata sits next to a rustc binary cargo does not own. Move the code into src/ first, then cargo init. Delete the rustc binary. Cargo will build a new one under target/.
§IV — cargo new: why the crate exists
Cargo is Rust's build system and package manager. It builds your code, downloads the libraries you name, and builds those libraries. Those libraries are dependencies. The book calls packages of code crates.
The hello-world file has no dependencies. If you had started it with Cargo, you would only have used the build half. You will want the other half as soon as a program needs a crate from crates.io. Chapter 2 does. That is why this chapter refuses to leave you on rustc.
Confirm cargo:
$ cargo --version
On castle: cargo 1.96.0 (30a34c682 2026-05-25). If you see command not found, cargo is not on PATH or was never installed. Fix that before cargo new.
From ~/projects (not from inside hello_world):
$ cargo new hello_cargo
$ cd hello_cargo
Cargo creates a directory of that name and a project inside it. List the files. You get Cargo.toml, a src/ directory, and src/main.rs. If you were not already inside a Git repository, you also get a Git repo and a .gitignore. cargo new --help lists the --vcs options, including none.
Open Cargo.toml. Listing 1-2 in the book looks like this:
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]
TOML is Tom's Obvious, Minimal Language. Cargo's config format. [package] holds the name, the version, and the edition. Leave edition as generated.
[dependencies] is empty. You will fill it in Chapter 2 when rand arrives. A crate name in that table is how Cargo knows what to fetch. rustc has no such table.
Open src/main.rs. Cargo wrote the same three-line program you typed by hand. Two differences from the rustc project: the source lives under src/, and the crate metadata lives in Cargo.toml at the top of the tree. Cargo expects source in src/. The top level is for README, license, config, and anything that is not source. That split is the first reason cargo new exists. Default cargo new is a binary crate. The entry is src/main.rs.
If you already have the rustc project and you want Cargo around it, move the code into src/ and add a Cargo.toml. Walk it:
$ cd ~/projects/hello_world
$ mkdir src
$ mv main.rs src/
$ cargo init
$ cargo run
cargo new starts a directory. cargo init adopts one. After cargo init, delete the old ./main rustc binary so you do not run the snapshot by habit. The crate binary will live under target/debug/.
Build from hello_cargo:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
Cargo writes the executable to target/debug/hello_cargo (or hello_cargo.exe on Windows). The default profile is debug: unoptimized, with debuginfo. Run it with ./target/debug/hello_cargo. The first cargo build also writes Cargo.lock. That file pins exact dependency versions. This crate has none, so the lock is thin. Do not edit it by hand. Cargo owns it.
.gitignore from cargo new ignores target/. Do not commit that directory. cargo run builds if needed, then runs:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
If the source has not changed, Cargo skips the compile and runs the existing binary. If you edited src/main.rs, you will see Compiling hello_cargo again, then the run.
cargo check type-checks and compiles far enough to know the program is legal, then stops short of an executable. It is faster than cargo build because it skips the link and the binary. Use it while you write. Use cargo build or cargo run when you need the file.
Recap, in the book's own list:
cargo newcreates a project.cargo buildbuilds it.cargo runbuilds and runs it.cargo checkchecks without a binary.- The binary lives under
target/debug, not next to the source.
From here the book stops giving separate Windows and Unix command lines. Cargo's commands are the same on every OS. That is the second reason cargo new exists. rustc gave you ./main versus .\main versus main.exe. Cargo hides that fork.
When you want the fast binary you would hand to someone else:
$ cargo build --release
That profile writes target/release/hello_cargo. Optimizations make the program faster and the compile slower. Debug is the rebuild-often profile. Release is the ship profile. If you ever time a program, time the release binary. Timing target/debug is a measurement of the wrong artifact.
Why cargo new exists, said in one breath, because the syllabus asks you to say it:
rustc compiles a file and leaves the binary beside it. That is fine for three lines. A crate needs a name, an edition, a src/ tree, a place to list other crates, a lockfile that pins them, a target/ tree that is not the source tree, a check that does not link, and a release profile that does. cargo new writes that shape in one command so you do not invent a layout the rest of the toolchain will not read. The rest of TRPL assumes that shape. So does every public crate you will clone.
If you cannot say that, you are still holding the file that is not a crate and calling it a project.
§V — Three proofs
The syllabus names three done-criteria. Run them.
**Proof 1. rustc and cargo are present.**
$ rustc --version
$ cargo --version
Both must print a version line. On castle they already do. If either command is missing, you are not done. rustup is the installer. PATH is the usual miss. rustup doc opening in a browser is extra confirmation the install is whole, not a required third binary.
Proof 2. Hello world builds.
Two legal builds. The file:
$ cd ~/projects/hello_world
$ rustc main.rs
$ ./main
The crate:
$ cd ~/projects/hello_cargo
$ cargo run
Both must print Hello, world!. If only the rustc path works, cargo is missing or you never ran cargo new. If only the cargo path works, you skipped the file on purpose. Do both. The contrast is the lesson.
**Proof 3. You can say why cargo new exists.**
Say it out loud. cargo new writes a crate: Cargo.toml, src/main.rs, a target/ destination after the first build, and a lockfile Cargo will fill when a dependency appears. It exists because rustc main.rs does not. If your answer is "because everyone uses it," that is a habit, not a reason. The reason is the layout and the commands that read the layout.
§VI — Closing
Ch.1 is three tools. rustup installs them. rustc compiles a file. cargo builds a crate. The file is real. The crate is what the rest of the book will open.
Name it when you see a lone main.rs sitting next to its binary with no toml: the file that is not a crate. Compile it if you want. Start the next program with cargo new.
Session 02 is TRPL Ch.2, the guessing game. Args of a sort, Result, rand from crates.io, a compare. Do not start it in this folder. Do not write it today.
Examine well. The version line is the first proof. The print is the second. The sentence about cargo new is the third. The function name main will still be pretty. The door is the crate.
Related
- Syllabus: Duha Rust syllabus, session 01
- Grounding tome: TRPL Ch.1 Getting Started (Klabnik / Nichols, stable)
- Next fire: session 02, TRPL Ch.2 Guessing Game (unwritten)