Build for no_std targets#
Important
Support for no_std targets is still in an immature state.
no_stdbuilds with POSIX support should be fully functional; however, they have not yet been thoroughly validated in production useno_stdbuilds for bare metal are currently proof-of-concept and do not yet support all features
Configuring the iceoryx2 build for no_std#
As is convention in the Rust ecosystem, building for no_std is done by
disabling the std feature. You can do this when specifying the dependency
in your Cargo.toml:
iceoryx2 = { version = "X.Y.Z", default-features = false }
Selecting a default logger#
Disabling the default features on the iceoryx2 crate also disables the
features that select the default logger in the iceoryx2-loggers crate.
As a result, all log messages are discarded.
For POSIX targets such as QNX 8, which currently does not have std support
upstream, a console logger implementation that uses the POSIX API is
available and can be selected by configuring the dependency in your
Cargo.toml:
iceoryx2-loggers = { version = "X.Y.Z", default-features = false, features = ["posix", "console"]}
For bare metal targets, there are no alternatives available yet, but stay tuned!
Setting up your no_std application#
When building a no_std application, you must provide implementations for
certain core functionality that the standard library would normally handle.
Take a look at the no_std examples for
a reference on how this could be done for both POSIX and bare metal targets.
Global allocator#
Since iceoryx2 uses the alloc crate, you must specify a global
allocator somewhere in the application:
#[global_allocator]
static GLOBAL: MyGlobalAllocator = MyGlobalAllocator::new();
Panic handler#
All no_std applications must define a panic handler using the
#[panic_handler] attribute:
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
// Your custom panic logic.
loop {
core::hint::spin_loop();
}
}
Application entry point#
In a no_std environment, you must define an appropriate entry point
for your platform. This can be done using the #![no_main] and
#[no_mangle] attributes.
The #![no_main] attribute prevents the compiler from emitting the main
symbol,
allowing you to define your own entry point that will be called by
the platform’s startup code. The #[no_mangle] attribute preserves the
function name in the compiled binary so it can be located by the linker.
For POSIX targets, define a C-compatible main function that returns an
exit code:
#![no_std]
#![no_main]
#[no_mangle]
extern "C" fn main() -> i32 {
// Your application code here
0 // Success
}
The startup code in the C runtime that POSIX platforms provide will automatically jump to this entry point after completing its initialization.
For bare metal targets, define a function that integrates with your platform’s startup code, for example:
#![no_std]
#![no_main]
#[no_mangle]
pub extern "C" fn entrypoint() -> ! {
// Your application code here
loop {} // Or handle exit in your platform code
}
Take a look at the startup code in the bare metal example to see how an arbitrary entry point can be integrated into the application.
Further Reading#
Documentation on the no_std Rust environment from the Rust Embedded Book.
Reference no_std examples for targets with POSIX support.
Reference no_std examples for bare metal targets.