I want to build a no_std static library with rust.
I got the following:
[package]
name = "nostdlb"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lib.rs:
#![no_std]
pub fn add(left: usize, right: usize) -> usize {
left + right
}
Despite setting the panic behaviour for both dev and release to abort cargo gives the following error:
error: `#[panic_handler]` function required, but not found
error: could not compile `nostdlb` due to previous error
I thought the panic handler is only required when there is no stack unwinding provided by std?
No, you need to write your own one. If you need just aborting, consider using the following one:
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
I also highly recommend to unmangle the function and use C calling convention if you’re going to use this symbol somewhere (not import it the library as a crate, but link it manually):
#[no_mangle]
extern fn add(right: usize, left: usize) -> usize {
right + left
}
Related
Suppose I have three crates: foo, bar, and baz.
Cargo.toml:
[workspace]
members = [
"foo",
"bar",
"baz",
]
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
foo/Cargo.toml:
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[lib]
name = "foo"
crate-type = ["staticlib"]
[dependencies]
bar = { path = "../bar", default-features = false }
foo/src/lib.rs:
#![no_std]
extern crate bar as _;
use core::alloc::{GlobalAlloc, Layout};
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
struct Allocator;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
todo!()
}
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
todo!()
}
}
bar/Cargo.toml:
[package]
name = "bar"
version = "0.1.0"
edition = "2018"
[lib]
name = "bar"
[features]
default = ["heap"]
heap = []
bar/src/lib.rs:
#![no_std]
#![feature(alloc_error_handler)]
use core::alloc::GlobalAlloc;
use core::alloc::Layout;
extern crate alloc;
#[cfg(feature = "heap")]
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
struct Allocator;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
todo!()
}
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
todo!()
}
}
#[panic_handler]
fn panic(_: &core::panic::PanicInfo<'_>) -> ! {
todo!();
}
#[alloc_error_handler]
fn alloc_fail(_: Layout) -> ! {
todo!();
}
baz/Cargo.toml:
[package]
name = "baz"
version = "0.1.0"
edition = "2018"
[lib]
name = "baz"
crate-type = ["staticlib"]
[dependencies]
bar = { path = "../bar" }
baz/src/lib.rs:
#![no_std]
extern crate bar as _;
Here, bar provides the global allocator, and both foo and baz depend on bar. However, foo doesn't enable bar's global allocator to use its original allocator, so foo depends on bar without the default features.
Running cargo clippy on each directory (foo/, bar/, and baz/) succeeds. However, running the command on the project root causes an error:
%cargo clippy
Checking bar v0.1.0 (/tmp/tmp.wlBjM4wNFx/bar)
Checking baz v0.1.0 (/tmp/tmp.wlBjM4wNFx/baz)
Checking foo v0.1.0 (/tmp/tmp.wlBjM4wNFx/foo)
error: the `#[global_allocator]` in this crate conflicts with global allocator in: bar
error: could not compile `foo` due to previous error
Actually, there are no global allocator conflicts as foo uses its original global allocator and disables bar's one. How to avoid this error?
Versions
rustup 1.24.3 (ce5817a94 2021-05-31)
cargo 1.56.0-nightly (b51439fd8 2021-08-09)
rustc 1.56.0-nightly (0035d9dce 2021-08-16)
This is workspace's property. bjorn3 said on Zulip:
If foo, bar and baz are all compiled together, the heap feature will be globally enabled for bar if either foo or baz depends on it. Cargo will take the union of all the features each dependent crate requires and compile dependencies once with these features.
So, bar is compiled with the heap feature because baz requires it, its feature is also enabled when foo is compiled. Thus, both foo's and bar's global allocators are enabled simultaneously, causing the error.
I am trying a build a library using the CLion IDE with Rust plugin installed. After a successful build, the library is not generated in the target/debug directory.
This is my project structure:
src/lib.rs
pub mod Math;
src/Math.rs
pub struct Arithmetic {
x: i32,
y: i32,
}
impl Arithmetic {
pub fn new(&mut self, x: i32, y: i32) {
self.x = x;
self.y = y;
}
pub fn add() -> i32 {
2 + 3
}
pub fn sub() -> i32 {
2 - 3
}
pub fn mul() -> i32 {
2 * 3
}
pub fn div() -> i32 {
2 / 3
}
}
Cargo.toml
[package]
name = "Test_Lib"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
What am I doing wrong?
Your project structure looks fine, and should be building as a Rust library.
But you shouldn't be concerned whether .rlib is built, because the file alone isn't useful for anything other than Cargo's private usage.
If you're trying to make a library usable outside of internal Rust/Cargo usage (such as .dll/.lib or .so/.a), then you will have to use the C ABI or C++ ABI and set crate-type to staticlib or cdylib.
If you want to use this library in other Rust projects, then don't even look into the target directory. Rust libraries aren't manually built one-by-one. Cargo builds the whole dependency tree in one go. Publish your crate on crates.io, or a git repository or add it to another project via path.
I'm trying to write a multi-threaded bare-metal application for the STM32F4Discovery using the Real-Time For the Masses (RTFM) crate. I've frankensteined together a minimal application from an example for the STM32F3Discovery board and this example:
#![deny(unsafe_code)]
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rtfm as rtfm;
extern crate cortex_m_semihosting;
extern crate panic_semihosting;
extern crate stm32f4;
use stm32f4::stm32f407;
use rtfm::app;
app! {
device: stm32f407,
}
fn init(_p: init::Peripherals) {
}
fn idle() -> ! {
loop {
rtfm::wfi();
}
}
I can get it to compile but linking with rust-lld fails with
= note: rust-lld: error: undefined symbol: main
I am confused because when I run cargo expand I do get a main function:
fn main() {
#![allow(path_statements)]
let init: fn(init::Peripherals) = init;
rtfm::atomic(unsafe { &mut rtfm::Threshold::new(0) },
|_t|
unsafe {
let _late_resources =
init(init::Peripherals{core:
::stm32f407::CorePeripherals::steal(),
device:
::stm32f407::Peripherals::steal(),});
});
let idle: fn() -> ! = idle;
idle();
}
I'm new to Rust (in fact I was hoping to learn the language with this project) and have no idea where the error might be located.
As you ask the compiler to not insert main, there is no main symbol in your program.
Rust uses symbol mangling so your main function doesn't have a symbol named main.
The answer depends on your contextm but generally this should do it:
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
}
All additional information can be found here
I'm trying to do some dynamic library loading in Rust. I'm getting a segmentation fault when passing a large Vec from a dynamically loaded library function. It's a basic function that creates a Vec<i32> of a specified size. If the Vec gets much bigger than 8MB, the program hits a segfault on OSX. I haven't had the same problem when running on linux, can anyone look at this and tell me if I'm doing something wrong here? I'm running this with:
$ cargo build --release
$ ./target/release/linkfoo
8281
[1] 84253 segmentation fault ./target/release/linkfoo
Cargo.toml
[package]
name = "linkfoo"
version = "0.1.0"
authors = ["Nate Mara <nathan.mara#kroger.com>"]
[dependencies]
libloading = "0.3.0"
[lib]
name = "foo"
crate-type = ["dylib"]
main.rs
extern crate libloading as lib;
fn main() {
let dylib = lib::Library::new("./target/release/libfoo.dylib").expect("Failed to load library");
let func = unsafe {
let wrapped_func: lib::Symbol<fn(&[i32]) -> Vec<i32>> = dylib.get(b"alloc")
.expect("Failed to load function");
wrapped_func.into_raw()
};
let args = vec![8182];
println!("{}", func(&args).len());
}
lib.rs
#[no_mangle]
pub fn alloc(args: &[i32]) -> Vec<i32> {
let size = args[0] as usize;
let mut mat = Vec::with_capacity(size);
for _ in 0..size {
mat.push(0);
}
mat
}
Rust uses the system allocator for dynamic libraries, and jemalloc for all other code. This difference in loaders was causing the segfault, and I was able to fix it by adding this to the top of main.rs:
#![feature(alloc_system)]
extern crate alloc_system;
I am using quickcheck to validate some properties of my code. At one point, I need an ASCII byte, so I tried to write an implementation of Arbitrary like this:
extern crate quickcheck;
use quickcheck::{quickcheck,Arbitrary,Gen};
#[derive(Debug,Copy,Clone)]
struct AsciiChar(u8);
impl Arbitrary for AsciiChar {
fn arbitrary<G>(g: &mut G) -> AsciiChar
where G: Gen
{
let a: u8 = g.gen_range(0, 128);
AsciiChar(a)
}
}
#[test]
fn it_works() {}
This fails with the error:
src/lib.rs:12:21: 12:40 error: source trait is private
src/lib.rs:12 let a: u8 = g.gen_range(0, 128);
^~~~~~~~~~~~~~~~~~~
Some searching led me to various bug reports (1, 2, 3, 4) that all seem to suggest I need to use the supertrait of Gen, which is rand::Rng. I updated my crates and use statements to
extern crate quickcheck;
extern crate rand;
use rand::Rng;
use quickcheck::{quickcheck,Arbitrary,Gen};
But I continue to get the same error.
I've tried with
rustc version 1.1.0-dev (b402c43f0 2015-05-07) (built 2015-05-07)
rustc 1.1.0-dev (3ca008dcf 2015-05-12) (built 2015-05-12)
I'm also using quickcheck v0.2.18
Ah, this was a tricky one. To progress in my testing, I added this hack:
impl Arbitrary for AsciiChar {
fn arbitrary<G>(g: &mut G) -> AsciiChar
where G: Gen
{
let a: u8 = Arbitrary::arbitrary(g);
AsciiChar(a % 128)
}
}
After that compiled, I got this error:
src/lib.rs:419:5: 419:23 error: use of unstable library feature 'rand': use `rand` from crates.io
src/lib.rs:419 extern crate rand;
^~~~~~~~~~~~~~~~~~
src/lib.rs:419:5: 419:23 help: add #![feature(rand)] to the crate attributes to enable
My problem was that I forgot to add rand to my Cargo.toml. I was thinking that I would just magically get the same version pulled in by quickcheck.
The ultimate problem was that I hadn't actually used the correct version of Rng, the one that Gen was a subtrait of. Very confusing!
After adding rand to my Cargo.toml, I am back in business.
That's strange. I can reproduce your initial error, but your suggested fix works for me:
extern crate quickcheck;
extern crate rand;
use quickcheck::{Arbitrary,Gen};
use rand::Rng;
#[derive(Debug,Copy,Clone)]
struct AsciiChar(u8);
impl Arbitrary for AsciiChar {
fn arbitrary<G>(g: &mut G) -> AsciiChar
where G: Gen
{
let a: u8 = g.gen_range(0, 128);
AsciiChar(a)
}
}
#[test]
fn it_works() {}
Running cargo test on both beta5 and the 2015-05-12 nightly works.