rust-num / num-traits

Numeric traits for generic mathematics in Rust
Apache License 2.0
731 stars 135 forks source link

Linker error from primitive cast in no_std #167

Closed dbeckwith closed 4 years ago

dbeckwith commented 4 years ago

Hello,

I'm using num-rational in a no_std project (target is custom, based on x86_64-unknown-none) and am getting a linker error when using Rational32::approximate_float. It seems to be coming from a cast in this crate in an impl of ToPrimitive (I'm guessing specifically <f64 as ToPrimitive>::to_f32). I've tried explicitly enabling the libm feature for num-traits in my Cargo.toml, but that didn't help because it seems like the ToPrimitive definitions don't have libm versions.

num-rational = { version = "0.2.4", default-features = false }
 = note: rust-lld: error: undefined symbol: __truncdfsf2
          >>> referenced by cast.rs:282 ($HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.11/src/cast.rs:282)
          >>>               snos_timer-8311147c5ab4bb97.515o52wkw29kkh3p.rcgu.o:(_$LT$f64$u20$as$u20$num_traits..cast..ToPrimitive$GT$::to_f32::hb2bd91b56346d11b) in archive $PROJECT/target/x86_64-snos/debug/deps/libsnos_timer-8311147c5ab4bb97.rlib

Is the solution to this just to provide a libm version of the ToPrimitive impls? Does one already exist that I'm missing and I'm just not enabling the libm feature correctly? Any advice is appreciated.

cuviper commented 4 years ago

That's basically just casting an f64 value as f32 directly, which will compile down to an LLVM fptrunc. If your target is configured as soft-float or similar, I'm not surprised that it would call externally. That would have to be implemented in compiler-builtins -- note that truncdfsf2.c is not yet translated.

dbeckwith commented 4 years ago

I'm able to trigger the same link error with 1.0f64 as f32 as i32. I do have soft-float configured on my target.

What's your recommended approach to solving this? Is this something libm can handle? Or do I just need to wait until its implemented in compiler-builtins?

cuviper commented 4 years ago

I think compiler-builtins would be best, but you probably need to be proactive and not just wait for it. Maybe chime in on https://github.com/rust-lang/compiler-builtins/issues/327 for your target, at least. I also found that it was implemented in https://github.com/rust-lang/compiler-builtins/pull/262, but as you can see it had to be reverted.

In the shorter term, maybe you could try copying that code as your own #[no_mangle] function so the linker can use it.

dbeckwith commented 4 years ago

Yeah reading the docs of compiler-builtins more, it seems like contributing there wouldn't be too difficult. The instructions for porting the implementations seem pretty straightforward. I'll try using the impl from that PR and look into opening my own. Thanks for the help!

jschwe commented 4 years ago

I also encountered this issue. I'm trying to instrument my no_std kernel for code coverage and I'm also passing the rustflag -Clinkdead-code to the crate of my kernel. This then get's automatically passed on to num-traits, since it's a dependency. I'm already using a RUSTC_WRAPPER to only pass the flag to crates that match the name of my crate, so I'm not really sure how to prevent passing the flag to num-traits. Anyway, this then causes the error:

  = note: rust-lld: error: undefined symbol: __truncdfsf2
          >>> referenced by cast.rs:282 (/home/xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.11/src/cast.rs:282)
          >>>               hermit-ff1a22d3d69a91b2.hermit.d1fbf0rq-cgu.8.rcgu.o:(_$LT$f64$u20$as$u20$num_traits..cast..ToPrimitive$GT$::to_f32::h5c126094cee3f196) in archive /home/xxx/Dev/rusty-hermit/target/x86_64-unknown-hermit/debug/deps/libhermit_sys-ef505253ec1eda28.rlib      

I'm going to workaround this for now by providing an empty stub for the method, but it would be nice if you (@dbeckwith ) could post a short update once you solved your problem.