# Rust Development Ubuntu Setup
Adding Rust development on top of an Ubuntu machine already configured per [[General_Development_Ubuntu_Setup]]. Most of the stack carries over — Ghostty, Starship, Git, GitHub CLI, VS Code, Claude Code, and the bash setup all work identically. This guide only covers the Rust-specific additions, and everything installs the same way on `amd64` and `arm64`. It's the Linux counterpart to [[Rust_Development_Mac_Tahoe_Setup]].
> [!tip] AI assistance is optional
> The reference to Claude Code above assumes you completed Part 7 of the General guide. If you skipped it or use a different AI tool, this guide's instructions still work — the language toolchain doesn't depend on any AI being present.
> [!info] Coexistence
> C, Python, Ruby, Go, and Rust can all live on the same system without interfering. Each language's toolchain installs to its own prefix: `uv` under `~/.local/share/uv/`, `rv` under `~/.cargo/bin`, Go under `~/go/`, Rust under `~/.rustup/` and `~/.cargo/`, C tooling under apt. No conflicts.
---
## Prerequisite: a C linker
Rust compiles to native code and uses the system C toolchain as its linker (`cc`). On Ubuntu that's provided by `build-essential`, which you installed in the General guide. If you skipped it:
```bash
sudo apt install -y build-essential pkg-config
```
Without `cc`, `cargo build` fails with `linker 'cc' not found`.
---
## Install Rust via rustup
**Use rustup, not apt's `rustc` package.** The Rust team maintains rustup as the canonical toolchain manager; the apt build lags behind and doesn't handle toolchain switching or component management. The installer detects your architecture (`x86_64`/`aarch64`):
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
The installer is interactive. Accept the default ("Proceed with standard installation") unless you have a specific reason to customize. It installs:
- `rustc` — the compiler
- `cargo` — the package manager and build tool
- `rustup` — the toolchain manager (multiple Rust versions, stable/nightly switching)
- `rustfmt` — the formatter
- `clippy` — the linter
- The native toolchain for your architecture
Everything lands in `~/.cargo/` and `~/.rustup/`.
### Add Cargo's bin directory to PATH
The installer typically appends this for you, but verify it's in `~/.bashrc`:
```bash
# Rust — make cargo-installed binaries callable
. "$HOME/.cargo/env"
```
Reload with `source ~/.bashrc`, then verify:
```bash
rustc --version
cargo --version
rustup --version
```
### Updating Rust
```bash
rustup update
rustup update nightly
rustup show
```
### Installing additional toolchains
```bash
rustup toolchain install nightly
rustup run nightly cargo build
rustup override set nightly
```
---
## Global Rust tooling
Install these once — they're used across all Rust projects:
```bash
# Watches files, reruns tests/build
cargo install cargo-watch
# Dependency security audit (checks against RustSec advisories)
cargo install cargo-audit
# Faster parallel test runner
cargo install cargo-nextest
# cargo-edit — adds `cargo upgrade` and more (`cargo add`/`rm` are built-in)
cargo install cargo-edit
# cargo-outdated — shows outdated deps
cargo install cargo-outdated
```
All of these land in `~/.cargo/bin/`, which is on your PATH from the `. "$HOME/.cargo/env"` line.
> [!info] These compile from source
> `cargo install` builds each tool from source for your architecture, so each takes 1–3 minutes. That's expected — the upside is they're always current and optimized for your CPU.
---
## VS Code extensions for Rust
```bash
# The official rust-analyzer language server
code --install-extension rust-lang.rust-analyzer
# CodeLLDB — debugger that works natively on Linux (amd64 + arm64)
code --install-extension vadimcn.vscode-lldb
# crates — shows latest versions of crates in Cargo.toml
code --install-extension serayuzgur.crates
# Even Better TOML (you may already have it from the General guide)
code --install-extension tamasfe.even-better-toml
```
> [!info] rust-analyzer vs the old "Rust" extension
> The extension named just "Rust" (RLS-based) is deprecated. `rust-analyzer` (published by `rust-lang.rust-analyzer`) replaced it years ago and is the official choice.
---
## VS Code settings
Append to your existing `settings.json` at `~/.config/Code/User/settings.json`:
```json
{
// ── Rust ──────────────────────────────────────────────────
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.rulers": [100]
},
"rust-analyzer.check.command": "clippy",
"rust-analyzer.cargo.features": "all",
"rust-analyzer.inlayHints.chainingHints.enable": true,
"rust-analyzer.inlayHints.parameterHints.enable": true,
"rust-analyzer.inlayHints.typeHints.enable": true,
"rust-analyzer.inlayHints.closureReturnTypeHints.enable": "always",
"rust-analyzer.lens.enable": true,
"rust-analyzer.lens.run.enable": true,
"rust-analyzer.lens.debug.enable": true,
"rust-analyzer.hover.actions.enable": true
}
```
> [!info] `rust-analyzer.check.command: "clippy"`
> By default, rust-analyzer uses `cargo check` for diagnostics. Switching to `clippy` runs the linter continuously, so you get style and correctness warnings inline as you type.
---
## Full demo: A calculator program
This walks through building, testing, debugging, and publishing a four-function calculator from scratch. Parallel implementations exist in C, Python, Ruby, and Go.
### Create the project
```bash
cd ~/projects
cargo new --lib calc-rust
cd calc-rust
# Add a binary target directory for the CLI/GUI
mkdir -p src/bin
```
### `Cargo.toml`
```toml
[package]
name = "calc"
version = "0.1.0"
edition = "2021"
[lib]
name = "calc"
path = "src/lib.rs"
[[bin]]
name = "calc"
path = "src/bin/calc.rs"
[[bin]]
name = "calc-gui"
path = "src/bin/calc_gui.rs"
[dependencies]
# (GUI dep added in the GUI section)
[dev-dependencies]
```
### `src/lib.rs` — the core library
```rust
//! Four-function calculator library.
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum CalcError {
DivideByZero,
UnknownOperator(String),
ParseError(String),
}
impl fmt::Display for CalcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CalcError::DivideByZero => write!(f, "division by zero"),
CalcError::UnknownOperator(op) => write!(f, "unknown operator '{op}'"),
CalcError::ParseError(s) => write!(f, "cannot parse '{s}' as a number"),
}
}
}
impl std::error::Error for CalcError {}
pub fn add(a: f64, b: f64) -> f64 { a + b }
pub fn sub(a: f64, b: f64) -> f64 { a - b }
pub fn mul(a: f64, b: f64) -> f64 { a * b }
pub fn div(a: f64, b: f64) -> Result<f64, CalcError> {
if b == 0.0 {
Err(CalcError::DivideByZero)
} else {
Ok(a / b)
}
}
/// Dispatch to the appropriate operation based on `op`.
/// Supported operators: "+", "-", "*", "x", "/".
pub fn calculate(a: f64, op: &str, b: f64) -> Result<f64, CalcError> {
match op {
"+" => Ok(add(a, b)),
"-" => Ok(sub(a, b)),
"*" | "x" => Ok(mul(a, b)),
"/" => div(a, b),
_ => Err(CalcError::UnknownOperator(op.to_string())),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(calculate(6.0, "+", 7.0), Ok(13.0));
}
#[test]
fn test_sub() {
assert_eq!(calculate(10.0, "-", 3.0), Ok(7.0));
}
#[test]
fn test_mul_star() {
assert_eq!(calculate(4.0, "*", 5.0), Ok(20.0));
}
#[test]
fn test_mul_x() {
assert_eq!(calculate(4.0, "x", 5.0), Ok(20.0));
}
#[test]
fn test_div() {
assert_eq!(calculate(20.0, "/", 4.0), Ok(5.0));
}
#[test]
fn test_div_by_zero() {
assert_eq!(calculate(5.0, "/", 0.0), Err(CalcError::DivideByZero));
}
#[test]
fn test_unknown_operator() {
assert!(matches!(
calculate(1.0, "?", 2.0),
Err(CalcError::UnknownOperator(_))
));
}
#[test]
fn test_operations_table() {
let cases: &[(f64, &str, f64, f64)] = &[
(1.0, "+", 1.0, 2.0),
(0.0, "+", 0.0, 0.0),
(-1.0, "+", 1.0, 0.0),
(1.5, "+", 2.5, 4.0),
(10.0, "-", 20.0, -10.0),
(3.0, "*", 4.0, 12.0),
];
for (a, op, b, expected) in cases {
assert_eq!(
calculate(*a, op, *b),
Ok(*expected),
"calculate({a}, {op:?}, {b}) should equal {expected}"
);
}
}
}
```
### `src/bin/calc.rs` — the CLI
```rust
//! Command-line entry point for the four-function calculator.
use std::env;
use std::process::ExitCode;
use calc::calculate;
fn usage(prog: &str) {
eprintln!("Usage: {prog} <number> <op> <number>");
eprintln!(" op: + - * /");
eprintln!("Example: {prog} 6 + 7");
}
fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
usage(&args[0]);
return ExitCode::from(1);
}
let a: f64 = match args[1].parse() {
Ok(v) => v,
Err(_) => {
eprintln!("Error: cannot parse '{}' as a number", args[1]);
return ExitCode::from(1);
}
};
let b: f64 = match args[3].parse() {
Ok(v) => v,
Err(_) => {
eprintln!("Error: cannot parse '{}' as a number", args[3]);
return ExitCode::from(1);
}
};
match calculate(a, &args[2], b) {
Ok(result) => {
// Print as integer if it came out whole
if result == (result as i64) as f64 {
println!("{}", result as i64);
} else {
println!("{result}");
}
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("Error: {e}");
ExitCode::from(1)
}
}
}
```
### `.gitignore`
Cargo generates a minimal one. Append if needed:
```
target/
```
> [!info] `Cargo.lock` — commit it?
> For **binary** crates (you distribute compiled executables), commit `Cargo.lock` for reproducible builds. For **library** crates, don't. This project is a binary, so keep it in git.
### Build and run
```bash
# Run the CLI (debug build, fast to compile)
cargo run --bin calc -- 6 + 7
cargo run --bin calc -- 10 - 3
cargo run --bin calc -- 4 x 5
cargo run --bin calc -- 20 / 4
# Release build (optimized)
cargo build --release
./target/release/calc 6 + 7
# Install to ~/.cargo/bin/ so `calc` is callable anywhere
cargo install --path . --bin calc
# Run tests
cargo test
# Or with nextest for faster parallel runs
cargo nextest run
# Lint
cargo clippy -- -D warnings
# Format all files in place
cargo fmt
# Full quality gate (common in CI)
cargo fmt --check && cargo clippy -- -D warnings && cargo test
```
### Debug in VS Code
With `vadimcn.vscode-lldb` installed, CodeLens appears above each `fn main()` and each `#[test]` with "Run | Debug" buttons. Click **Debug** to step through.
For the CLI with arguments, create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug calc CLI",
"type": "lldb",
"request": "launch",
"cargo": {
"args": ["build", "--bin=calc"],
"filter": { "name": "calc", "kind": "bin" }
},
"args": ["6", "+", "7"],
"cwd": "${workspaceFolder}"
},
{
"name": "Debug unit tests",
"type": "lldb",
"request": "launch",
"cargo": {
"args": ["test", "--no-run", "--lib"],
"filter": { "name": "calc", "kind": "lib" }
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}
```
Set a breakpoint, hit **F5**, step through native code with full variable inspection. (CodeLLDB bundles its own LLDB, so this works without installing a system debugger.)
### Publish to GitHub
```bash
git init
git add .
git commit -m "Initial commit: four-function calculator"
gh repo create calc-rust --private --source=. --remote=origin --push
```
### `CLAUDE.md` for this project
```markdown
# Project: calc-rust
## Purpose
Four-function command-line calculator in Rust — pedagogical example.
## Conventions
- Rust 2021 edition, stable toolchain
- Library (src/lib.rs) + binaries (src/bin/)
- Tests colocated with code via #[cfg(test)] mod tests
- Format with rustfmt (default style)
- Lint with clippy — treat warnings as errors in CI
## Commands
- Run CLI: `cargo run --bin calc -- <a> <op> <b>`
- Run GUI: `cargo run --bin calc-gui`
- Build release: `cargo build --release`
- Install: `cargo install --path . --bin calc`
- Test: `cargo test` (or `cargo nextest run` for parallel)
- Lint: `cargo clippy -- -D warnings`
- Format: `cargo fmt`
- Quality gate: `cargo fmt --check && cargo clippy -- -D warnings && cargo test`
## Style
- 4-space indent, 100-column line length
- snake_case for functions and variables, CamelCase for types
- Return `Result<T, E>` with a concrete error enum for recoverable errors
- Use `#[derive(Debug, PartialEq)]` on public types where possible
- Doc comments (`///`) on every public item
```
---
## Full demo: A calculator GUI
Same calculator, wrapped in a graphical interface. This uses **iced**, a pure-Rust, Elm-inspired GUI toolkit — the most popular Rust GUI library in 2026.
### Why iced?
| Option | Pros | Cons |
|--------|------|------|
| **iced** | Pure Rust, Elm architecture (predictable state), native-feeling, actively developed | Still pre-1.0 (API shifts between versions) |
| **egui** | Immediate-mode, great for tools/debug UIs, very simple | Custom widget look |
| **Slint** | Declarative DSL, compiles to native, excellent perf | Custom language (`.slint` files) |
| **Tauri** | HTML/JS frontend + Rust backend | Bundles a webview |
| **GTK-rs** | Native GTK widgets | Heavier dependencies |
For a pedagogical calculator in Rust, iced is the right default. The Elm architecture (Model + Update + View) makes the state machine obvious and unit-testable.
### System dependencies for iced
iced renders through `wgpu` (Vulkan/GL) and uses `winit` for windowing. On Linux it needs a few development libraries for fonts and the windowing system:
```bash
sudo apt install -y pkg-config libfontconfig1-dev libxkbcommon-dev
```
Vulkan/GL drivers are part of a normal desktop Ubuntu install (Mesa); the packages above cover the build-time headers iced links against. These are available for both architectures.
### Add iced as a dependency
```bash
cargo add iced
```
Or pin it in `Cargo.toml`:
```toml
[dependencies]
iced = "0.13"
```
### `src/bin/calc_gui.rs` — the GUI
```rust
//! Graphical four-function calculator using iced.
use iced::widget::{button, column, container, row, text, text_input};
use iced::{Element, Length, Task, Theme};
use calc::calculate;
pub fn main() -> iced::Result {
iced::application("Calculator", Calculator::update, Calculator::view)
.theme(|_| Theme::Dark)
.window_size((260.0, 360.0))
.run()
}
#[derive(Debug, Clone)]
pub enum Message {
Press(String),
Clear,
}
#[derive(Default)]
pub struct Calculator {
current: String,
stored: Option<f64>,
pending_op: Option<String>,
display: String,
}
impl Calculator {
pub fn new() -> Self {
Self {
display: "0".to_string(),
..Default::default()
}
}
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::Press(label) => self.handle_press(&label),
Message::Clear => self.clear(),
}
Task::none()
}
pub fn handle_press(&mut self, label: &str) {
match label {
d if d.chars().all(|c| c.is_ascii_digit() || c == '.') => {
self.current.push_str(d);
self.display = self.current.clone();
}
"+" | "-" | "*" | "/" => {
self.apply_pending();
self.pending_op = Some(label.to_string());
}
"=" => {
self.apply_pending();
self.pending_op = None;
}
_ => {}
}
}
pub fn clear(&mut self) {
self.current.clear();
self.stored = None;
self.pending_op = None;
self.display = "0".to_string();
}
fn apply_pending(&mut self) {
if self.current.is_empty() {
return;
}
let value: f64 = match self.current.parse() {
Ok(v) => v,
Err(_) => {
self.display = "Error".to_string();
self.reset_internal();
return;
}
};
let new_value = match (self.stored, self.pending_op.as_deref()) {
(None, _) | (_, None) => value,
(Some(s), Some(op)) => match calculate(s, op, value) {
Ok(v) => v,
Err(_) => {
self.display = "Error".to_string();
self.reset_internal();
return;
}
},
};
self.stored = Some(new_value);
// Format: integer if whole
self.display = if new_value == (new_value as i64) as f64 {
(new_value as i64).to_string()
} else {
format!("{new_value}")
};
self.current.clear();
}
fn reset_internal(&mut self) {
self.current.clear();
self.stored = None;
self.pending_op = None;
}
pub fn view(&self) -> Element<Message> {
let display = text_input("0", &self.display)
.size(28)
.align_x(iced::alignment::Horizontal::Right);
let btn = |label: &str| -> Element<Message> {
button(text(label).size(18).center())
.width(Length::Fill)
.padding(12)
.on_press(Message::Press(label.to_string()))
.into()
};
let grid = column![
row![btn("7"), btn("8"), btn("9"), btn("/")].spacing(5),
row![btn("4"), btn("5"), btn("6"), btn("*")].spacing(5),
row![btn("1"), btn("2"), btn("3"), btn("-")].spacing(5),
row![btn("0"), btn("."), btn("="), btn("+")].spacing(5),
]
.spacing(5);
let clear = button(text("Clear").center())
.width(Length::Fill)
.padding(10)
.on_press(Message::Clear);
container(
column![display, grid, clear]
.spacing(10)
.padding(10),
)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn press_sequence(presses: &[&str]) -> Calculator {
let mut c = Calculator::new();
for p in presses {
c.handle_press(p);
}
c
}
#[test]
fn initial_display() {
let c = Calculator::new();
assert_eq!(c.display, "0");
}
#[test]
fn single_digit() {
let c = press_sequence(&["5"]);
assert_eq!(c.display, "5");
}
#[test]
fn multi_digit() {
let c = press_sequence(&["1", "2", "3"]);
assert_eq!(c.display, "123");
}
#[test]
fn simple_addition() {
let c = press_sequence(&["6", "+", "7", "="]);
assert_eq!(c.display, "13");
}
#[test]
fn chained_operations() {
// 2 + 3 * 4 → (2+3)*4 = 20 (left-to-right)
let c = press_sequence(&["2", "+", "3", "*", "4", "="]);
assert_eq!(c.display, "20");
}
#[test]
fn division() {
let c = press_sequence(&["2", "0", "/", "4", "="]);
assert_eq!(c.display, "5");
}
#[test]
fn division_by_zero() {
let c = press_sequence(&["5", "/", "0", "="]);
assert_eq!(c.display, "Error");
}
#[test]
fn clear_resets_state() {
let mut c = press_sequence(&["5", "+", "3"]);
c.clear();
assert_eq!(c.display, "0");
assert!(c.current.is_empty());
assert!(c.stored.is_none());
assert!(c.pending_op.is_none());
}
#[test]
fn decimal_input() {
let c = press_sequence(&["1", ".", "5", "+", "2", ".", "5", "="]);
assert_eq!(c.display, "4");
}
}
```
### Run everything
```bash
# CLI
cargo run --bin calc -- 6 + 7
# GUI (first build is slow — iced pulls in winit, wgpu, etc.)
cargo run --bin calc-gui
# All tests (library + GUI state machine)
cargo test
# Release builds
cargo build --release
./target/release/calc-gui
```
The first iced build is slow (several minutes) because it compiles the whole graphics stack — winit for windowing, wgpu for rendering. Subsequent builds are cached and fast.
> [!info] Shipping iced apps
> For a distributable Linux package (e.g. a `.deb`), use `cargo bundle`:
> ```bash
> cargo install cargo-bundle
> cargo bundle --release
> ```
> This produces a package under `target/release/bundle/`.
---
## Starship prompt — Rust auto-detection
The general Starship config already includes the `[rust]` module. When you `cd` into this project, the prompt shows:
```
~/projects/calc-rust main 1.86.0 ❯
```
Reading left-to-right: directory, git branch, Rust version.
---
## Installing CLI tools from other Rust projects
`cargo install` is the equivalent of `uv tool install` or `go install` — it installs binaries globally (to `~/.cargo/bin/`) from crates.io or a git URL:
```bash
# Install ripgrep from crates.io (you may already have it via apt)
cargo install ripgrep
# Install tokei (fast code counter)
cargo install tokei
# Install from a git repo
cargo install --git https://github.com/you/your-tool.git
```
> [!info] Cargo vs apt for Rust tools
> Many popular Rust CLIs (ripgrep, bat, fd, eza) are available via both `apt` and `cargo install`. `apt` gives you precompiled binaries and faster installation; `cargo install` compiles from source but gives you the latest version optimized for your CPU. For daily use, prefer `apt`; use `cargo install` when apt doesn't carry the tool or you want a specific version.
---
## direnv — auto-activate this project's environment
With direnv hooked into your shell (see [[General_Development_Ubuntu_Setup]]), an `.envrc` in the project root loads when you `cd` in and unloads when you leave. Rust doesn't need direnv to choose a toolchain — that's what `rust-toolchain.toml` is for — but `.envrc` is handy for dev env vars and for running freshly built binaries by name.
```bash
# from the project root
cat > .envrc <<'EOF'
export RUST_BACKTRACE=1
export RUST_LOG=debug
# call ./target/debug/calc as just `calc` after `cargo build`
PATH_add target/debug
EOF
direnv allow
```
> [!info] Pin the toolchain with `rust-toolchain.toml`, not direnv
> direnv has no built-in Rust integration (there is no `use rust`). To lock a project to a toolchain, add a `rust-toolchain.toml` with a `[toolchain]` section and `channel = "stable"` (or a version like `"1.81.0"`); rustup reads it automatically on every `cargo` command. Keep `.envrc` for environment variables and convenience `PATH` entries.
---
## Troubleshooting
> [!warning] `rustc: command not found` after installing
> The installer adds `. "$HOME/.cargo/env"` to your shell config. Verify with `grep cargo/env ~/.bashrc`. If missing, add it and open a fresh terminal.
> [!warning] `cargo build` error: "linker `cc` not found"
> Install the C toolchain: `sudo apt install -y build-essential`.
> [!warning] iced build fails on `fontconfig` or `xkbcommon`
> Install the dev headers: `sudo apt install -y pkg-config libfontconfig1-dev libxkbcommon-dev`.
> [!warning] Very slow first build of a GUI project
> iced (and egui, and Slint) pull in substantial graphics dependencies. The first `cargo build` for a GUI project typically takes 3–8 minutes; subsequent builds are incremental. This is normal.
> [!warning] iced window doesn't open in a VM
> iced needs working GL/Vulkan. Enable 3D acceleration in your hypervisor. The CLI and the state-machine tests run fine without a display.
> [!warning] `rust-analyzer` seems unresponsive in VS Code
> Run `cargo check` in a terminal first — rust-analyzer uses cargo under the hood. Check the "Rust Analyzer Language Server" output panel for errors.
---
## Summary — the one-shot Rust addition
> [!warning] This is a checklist, not a script
> Copy and paste one block at a time. The first step **runs the interactive rustup installer** — read its prompts and respond before continuing. The `cargo install` commands compile from source (1–3 minutes each). After running these, **append the Rust settings block** above to `~/.config/Code/User/settings.json`.
```bash
# Linker (if not already present)
sudo apt install -y build-essential pkg-config
# Rust toolchain (interactive installer — accept defaults)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"
# Global Cargo tooling
cargo install cargo-watch cargo-audit cargo-nextest cargo-edit cargo-outdated
# iced GUI system dependencies (for the GUI demo)
sudo apt install -y libfontconfig1-dev libxkbcommon-dev
# VS Code extensions
code --install-extension rust-lang.rust-analyzer
code --install-extension vadimcn.vscode-lldb
code --install-extension serayuzgur.crates
# Paste the Rust block into ~/.config/Code/User/settings.json
# Verify
rustc --version && cargo --version && rustup --version
```
About five minutes of install time on top of the general setup (the `cargo install` calls compile from source).
---
## Related notes
- [[General_Development_Ubuntu_Setup]]
- [[Rust_Development_Mac_Tahoe_Setup]] — the macOS counterpart
- [[Python_Development_Ubuntu_Setup]]
- [[C_Development_Ubuntu_Setup]]
- [[Ruby_Development_Ubuntu_Setup]]
- [[Go_Development_Ubuntu_Setup]]
- [Cargo Cheat Sheet](https://doc.rust-lang.org/cargo/)
- [iced Architecture Notes](https://book.iced.rs/architecture.html)