Suman Thakur
Suman Thakur

Reputation: 31

Including CPU architecture specific source files in Rust

I'm working on a Rust executable project (audio codec + driver) that needs to compile to ARM Cortex-M, as well as ARM64 and X86 Linux platforms. We would like to have the project structure such that target specific code can be put in separate target specific files and directories, while target independent code kept in only one place. For example, we would like the top level main.rs to conditionally include arm64/main.rs, thumb/main.rs, and x86/main.rs files, where each target specific main.rs file is likely to do vastly different things.

My questions are:

  1. What's the best way to do such a thing? Usually, in C/C++ this is trivial, but I don't know how to do this using cfg! macros.
  2. Is there a way to specify these things directly in Cargo.toml instead of having them in Rust source files?

Any help, or pointers to projects that do this sort of thing is highly appreciated.

Upvotes: 2

Views: 1163

Answers (1)

ddulaney
ddulaney

Reputation: 1101

You can use the #[cfg(...)] attribute on anything, including functions, modules, and individual blocks of code.

The simplest way would be to create several main functions in one file, where each has a #[cfg(...)] attribute on it. The reference has a big list of configuration options you can use.

#[cfg(target_arch = "x86_64")]
fn main() {
    println!("Hello from x86_64");
}

#[cfg(target_arch = "arm")]
fn main() {
    println!("Hello from ARM");
}

But you asked about multiple files. In Rust, each file is a module, and you can attach the same cfg attribute to the module declaration. For example, you might have two arch-specific files:

// main_x86_64.rs
pub fn main() {
    println!("Hello from x86_64");
}
// main_arm.rs
pub fn main() {
    println!("Hello from ARM");
}

Then, in the real main function, conditionally compile one of them in and conditionally call one main function or the other.

// main.rs

#[cfg(target_arch = "x86_64")]
mod main_x86_64;

#[cfg(target_arch = "arm")]
mod main_arm;

#[cfg(target_arch = "x86_64")]
fn main() {
    main_x86_64::main();
}

#[cfg(target_arch = "arm")]
fn main() {
    main_arm::main();
}

If you're looking for a broader pattern, I'd point you to the way core organizes platform-specific things. There's an arch module that conditionally compiles in each platform's submodule on just that platform. You can see in the source code that there's a cfg attribute for each submodule so that it only gets compiled in on that platform.

Upvotes: 4

Related Questions