Hello, Cargo!

Cargo is Rust's excellent build system and package manager, and it makes Rust projects much easier to manage. You can use Cargo to create new projects, build them, test them, and distribute them. The good news is that Cargo works seamlessly with Oxide—.ox files are treated identically to .rs files. Oxide benefits directly from Cargo's powerful tooling and ecosystem.

What is Cargo?

Cargo handles several important tasks for you:

  • Building your code with cargo build
  • Running your code with cargo run
  • Testing your code with cargo test
  • Generating documentation with cargo doc
  • Publishing libraries to crates.io
  • Managing dependencies through Cargo.toml

Without Cargo, you'd need to manually compile your code with rustc, manage compilation flags, handle dependencies by hand, and coordinate all these tasks yourself. With Cargo, everything is automated and standardized.

Creating an Oxide Project

To create a new Oxide project, use Cargo with the --oxide flag:

$ cargo new --oxide hello_oxide
     Created binary (application) `hello_oxide` package
$ cd hello_oxide

This generates an Oxide project with src/main.ox containing:

fn main() {
    println!("Hello, world!")
}

Development Status: Oxide v1.0 is currently in development. The --oxide flag will be available in Cargo once the Oxide toolchain is released. For early testing before the release, you can manually create a project with cargo new and rename src/main.rs to src/main.ox.

Let's see what Cargo generated:

$ cd hello_oxide
$ ls -la
drwxr-xr-x  .git
drwxr-xr-x  .gitignore
-rw-r--r--  Cargo.toml
drwxr-xr-x  src

Let's look at the directory structure:

$ tree .
.
├── Cargo.toml
└── src
    └── main.ox

Understanding Cargo.toml

The Cargo.toml file is the manifest for your project. It contains metadata about your package and its dependencies. Here's what was created for us:

[package]
name = "hello_oxide"
version = "0.1.0"
edition = "2021"

[dependencies]

The [package] section contains metadata:

  • name: The name of your project
  • version: The current version of your code
  • edition: The Rust edition (Oxide projects use the same editions as Rust)

The [dependencies] section is where you'd list any external crates your project depends on. We don't have any dependencies yet.

Understanding the src Directory

Cargo expects your source files to be in the src directory. With the --oxide flag, Cargo creates main.ox with a simple "Hello, World!" program:

fn main() {
    println!("Hello, world!")
}

This is valid Oxide code that compiles and runs just like Rust. Let's make it feel more Oxide-like by using string interpolation:

fn main() {
    let language = "Oxide"
    println!("Hello from \(language)!")
}

The differences from the original:

  • Added a variable to demonstrate Oxide's string interpolation: "\(language)"
  • Omitted semicolons (optional in Oxide)
  • The fn main() and println!() syntax work identically in both Oxide and Rust

Building and Running Your Oxide Project

Now let's build the project using Cargo:

$ cargo build
   Compiling hello_oxide v0.1.0
    Finished dev [unoptimized + debuginfo] target/debug/hello_oxide

Congratulations! You've successfully compiled your first Oxide program with Cargo. The executable has been created in target/debug/hello_oxide (or target/debug/hello_oxide.exe on Windows).

To run it, use cargo run:

$ cargo run
   Compiling hello_oxide v0.1.0
    Finished dev [unoptimized + debuginfo] target/debug/hello_oxide
     Running `target/debug/hello_oxide`
Hello, Oxide!

The cargo run command compiles the code and then runs the resulting executable—all in one command. It's very convenient for projects you're actively working on.

A Note About Cargo.lock

When you first build your project, Cargo creates a Cargo.lock file. This file keeps track of the exact versions of dependencies you've built with. For binary projects (like this one), you should commit Cargo.lock to version control so everyone working on the project uses the same dependency versions. For libraries, it's typically not committed.

Cargo Check

If you want to verify that your code compiles without actually producing an executable, you can use cargo check:

$ cargo check
   Checking hello_oxide v0.1.0
    Finished dev [unoptimized + debuginfo] target/debug/hello_oxide

This command is much faster than cargo build because it stops after type-checking and doesn't generate code. It's perfect for getting quick feedback as you're writing code.

Using Cargo with Mixed Oxide and Rust

One powerful feature of Oxide is that you can freely mix .ox and .rs files in the same Cargo project. Cargo doesn't care which extension you use—both are compiled and linked together seamlessly.

For example, if you have existing Rust code you want to reuse, or if you're gradually migrating a project to Oxide, you can simply keep both file types in the same src/ directory:

src/
├── main.ox          # Oxide code
├── utils.rs         # Rust code
├── lib.ox           # Oxide library code
└── integrations.rs  # Rust integrations

Cargo will compile all of them together:

$ cargo build
   Compiling hello_oxide v0.1.0
    Finished dev [unoptimized + debuginfo] target/debug/hello_oxide

You can call Rust functions from Oxide and vice versa—they're compiled to the same intermediate representation and linked together. This makes it easy to adopt Oxide incrementally.

Thinking in Terms of Cargo

As you work with Rust and Oxide projects, here's a mental model for Cargo:

Cargo is to systems programming as npm is to Node.js or pip is to Python. It's the standard way projects are organized, built, and distributed. Rust's community designed Cargo exceptionally well, and Oxide benefits from this thoughtful tooling.

Every Rust and Oxide project you'll encounter follows the same structure:

  • Source code in src/
  • Dependencies listed in Cargo.toml
  • Binaries in target/debug/ or target/release/
  • Tests alongside your source code

Learning Cargo now means you'll immediately understand the structure of any Rust or Oxide project you encounter. This standardization is one of Rust's great strengths.

Building for Release

So far, we've been building in development mode with cargo build. This mode is great for development because compilation is fast and includes debug information. However, it doesn't optimize your code, so the resulting executable is slower.

When you're ready to ship your code, or when you care about performance, use the --release flag:

$ cargo build --release
   Compiling hello_oxide v0.1.0
    Finished release [optimized] target/release/hello_oxide

The executable will be in target/release/hello_oxide. Release builds take longer to compile but run much faster. You can also use:

$ cargo run --release
   Compiling hello_oxide v0.1.0
    Finished release [optimized] target/release/hello_oxide
     Running `target/release/hello_oxide`
Hello, Oxide!

For benchmarking or production deployment, always use --release.

Summary

Congratulations! You've learned the basics of working with Cargo and Oxide:

  • Cargo new creates a new project structure
  • Cargo build compiles your project
  • Cargo run compiles and runs your project
  • Cargo check quickly verifies your code compiles
  • .ox files work seamlessly with Cargo just like .rs files
  • Mixed projects are fully supported—use both .ox and .rs files in the same crate
  • Release builds provide optimizations for production use

You now have everything you need to start building Oxide projects. In the next chapter, we'll explore the fundamental concepts of the language itself.