esp_idf_sys/start.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#![cfg(any(feature = "binstart", feature = "libstart"))]
// When compiling a binary Rust crate in STD (e.g. in Cargo-first builds) and NOT doing
// any tricks like using #[no_main] or #[start], the Rust compiler will autogenerate
// a C function with the signature as below which will be proxying
// the real Rust main function of your binary crate
//
// So to bridge this function with the real C "app_main()" entrypoint
// that ESP-IDF expects it is enough to implement app_main() and call in it
// the "main" C function autogenerated by the Rust compiler
//
// See https://github.com/rust-lang/rust/issues/29633 for more information
#[cfg(all(feature = "std", feature = "binstart"))]
extern "C" {
fn main(p1: isize, p2: *const *const u8) -> isize;
}
// When compiling a static Rust library crate (e.g. by using a PIO->Cargo or a CMake->Cargo) build,
// there is no main function that the Rust compiler expects, nor autogeneration of a callable
// wrapper around it.
//
// In that case (and if the "libstart" feature is enabled), it is _us_ (not the Rust compiler)
// expecting the user to define a rust #[no_mangle] "main" function and it is our code below which is explicitly
// calling it from app_main(). If the user does not define a main() runction in Rust, there will
// be a linkage error instead of the nice Rust syntax error for binary crates.
//
// Another restriction of the "libstart" feature is that the Rust main function will always have one
// fixed signature: "fn main() -> ()" - as opposed to the flexibility of main() in binary crates
// where it can have quite a few different returning types
//
// When compiling a binary Rust crate in no_std, we end up in identical situation:
// - There is no Rust "lang = start" item defined
// - As such, there is no magic C "main" function defined for, which would proxy our binary crate main
#[cfg(any(all(not(feature = "std"), feature = "binstart"), feature = "libstart"))]
extern "Rust" {
fn main();
}
#[no_mangle]
pub extern "C" fn app_main() {
unsafe {
// #[cfg(all(feature = "uart0_driver_init", esp_idf_comp_driver_enabled, esp_idf_comp_vfs_enabled))]
// uart_init::init_uart0();
#[cfg(all(feature = "std", feature = "binstart"))]
main(0, &[core::ptr::null()] as *const *const u8);
#[cfg(any(all(not(feature = "std"), feature = "binstart"), feature = "libstart"))]
main();
}
}
// TODO: Move to `esp-idf-hal`. We should start precisely in the state ESP IDF was configured to be. The below should become a utility method,
// ideally as part of `esp_idf_hal::uart` and possibly with support from future ESP IDF VFS safe APIs
// #[cfg(all(feature = "uart0_driver_init", esp_idf_comp_driver_enabled, esp_idf_comp_vfs_enabled))]
// mod uart_init {
// use crate::{esp_vfs_dev_uart_use_driver, uart_driver_install};
// use core::{ffi::c_int, ptr::null_mut};
// const UART_BUFFER_SIZE: c_int = 512;
// const UART_QUEUE_SIZE: c_int = 10;
// pub(super) fn init_uart0() {
// // Enable UART0 driver so stdin can be read.
// unsafe {
// crate::esp!(uart_driver_install(
// 0,
// UART_BUFFER_SIZE,
// UART_BUFFER_SIZE,
// UART_QUEUE_SIZE,
// null_mut(),
// 0
// ))
// .expect("unable to initialize UART0 driver");
// esp_vfs_dev_uart_use_driver(0);
// }
// }
// }