When to use "extern crate foo" and "use" clauses?

Hi,

I'm new to Rust and I'm having trouble understanding what extern crate foo does. I work mainly in C, maybe someone has a C analogy? When is it necessary to write that line?

As I understand, use would be kind of like an #include, but instead of including files it brings modules or functions into scope (? - not 100% sure).

Thanks for your help!

With the 2018 edition you should not have to write it anymore. (All new projects default to 2018 edition).

It exisits because previous versions of the compiler didn't infer which crates where used based off of your Cargo.toml file.

I guess you meant 2018? :wink:

I'm from the future, where GAT finally is getting stabilized in the amazing 2031 edition! :sunglasses:

2 Likes

Alright, makes sense. I was wondering why I couldn't find that statement in The Book. I guess I've only seen it in examples in the documentation of old, unmaintained crates.

Unfortunately it's not 100% gone yet, e.g. for working with optionally-std-using crates you still need it for extern crate alloc; and extern crate std;, and proc-macros need extern crate proc_macro;. But definitely for newcomers it shouldn't be necessary.

1 Like

Why is it still necessary in those cases?

1 Like

All of those are relatively niche usecases that require the compiler to do very different things.

alloc gives allocations to no_std almost baremetal programs.

std to optionally give std to no_std applications.

proc_macro because procedural macros need access to the token tree.

They act as flags for the compiler to work out what the application needs, and how to handle it.

1 Like

Aha! So that's where I've seen it! I'm an embedded developer and I've seen extern crate foo lines in the Embedded book and other tutorials/examples, e.g. in here.

Can someone explain then when is it needed? If that statement is needed often in the embedded development world, then I guess I should know what it is for and why is it needed.

It's needed for alloc and std because there's no way to add them as dependencies in your Cargo.toml. So you'll see a lot of crates that optionally support allocation doing something like

#![no_std]

#[cfg(feature = "alloc")]
extern crate alloc;

pub fn foo() -> usize {
    5
}

#[cfg(feature = "alloc")]
pub fn bar() -> alloc::boxed::Box<usize> {
    alloc::boxed::Box::new(5)
}

This says that by default this crate doesn't need std or alloc and has only one function available, foo; but, if you activate the alloc feature it will additionally depend on the alloc crate shipped with the compiler and provide the function bar using types from it.


The extern crate panic_halt; in that example is actually another case altogether, panic_halt's public API is a #[panic_handler] function. How #[panic_handler] and some other "weak dependencies" of core/alloc are linked together is a bit weird, and in order to make sure it is linked in you need to use either extern crate panic_halt; or use panic_halt as _; so that rustc won't just skip the crate as an unused dependency.

This is the most common case you'll see in embedded Rust, in my experience: a crate that does its work simply by being linked into the program, because it provides a special piece of data like an interrupt vector table, or a special function like a panic hook. Such a crate is never "used" by the code, so you need to extern crate it to instruct the toolchain to include it during linking.

This can also come up if you're writing very minimal embedded applications using e.g. cortex_m_rt. If you don't actually use anything from the crate, but want to have a valid interrupt vector table, you may have to extern crate it.

3 Likes

Nope, GAT will be stabilized sooner

2 Likes

There is also this section in the Rust by Example "book". Would I be able to write a use statement instead of the extern crate one, as long as I declared the dependency in Cargo.toml?