[WIP] Provide a cdylib with the libm C ABI#192
[WIP] Provide a cdylib with the libm C ABI#192gnzlbg wants to merge 8 commits intorust-lang:masterfrom
Conversation
| #[cfg(not(test))] | ||
| #[panic_handler] | ||
| fn panic(_info: &core::panic::PanicInfo) -> ! { | ||
| unsafe { core::intrinsics::abort() } |
There was a problem hiding this comment.
TODO: I should probably call the C abort function here.
|
|
||
| #[cfg(not(test))] | ||
| #[lang = "eh_personality"] | ||
| extern "C" fn eh_personality() {} |
There was a problem hiding this comment.
There has to be a better way that avoids this, but I exhausted all my google-fu trying to find it.
There was a problem hiding this comment.
This has to do with libcore itself being built with panic=unwind, but why not just link to std and have it provide these?
There was a problem hiding this comment.
Because libstd would pull the system's libm.
| pub(crate) fn ctype_and_printf_format_specifier(x: &str) -> (&str, &str) { | ||
| match x { | ||
| "f32" => ("float", "%f"), | ||
| "f64" => ("double", "%f"), |
There was a problem hiding this comment.
IIRC, %f prints doubles. There is no format string for printing floats AFAIK - %f converts floats into a double, and prints that.
There was a problem hiding this comment.
Would it make sense when %f is a double anyway? maybe %.24f for floats %.54f for doubles makes more sense?
There was a problem hiding this comment.
Or even better maybe just %e
There was a problem hiding this comment.
For the linking tests it doesn't really matter. I'll add a comment about this.
There was a problem hiding this comment.
So I've added a comment explaining what this does right now.
If we wanted to verify the results of this lib, I think I would prefer doing so as part of the libm-test system. We could dynamically link libm as the system library, and just verify that the results of the C ABI match the results that are produced by the Rust library, or something like that.
The problem which checking the ABI here is that, if for some reason linking failed, or the symbol has a slightly different name, etc. the functions from the system library are invoked. So if we were to just simply verify the results, we can't tell whether its our libm or the system libm that's being invoked.
There was a problem hiding this comment.
Maybe there is a way to reliably prevent libm from being linked on Linux, while still being able to link, e.g., fprintf and other parts of the standard library. On MacOSX, this is IMO not worth it - everything links libSystem.dylib, which always dynamically links libm.
|
Is there anyway we can fix the linking issue? By looking the at the online docs the following functions should be present in the Kernel
There are no sincos or exp10 functions in the Kernel, they are only present in the accelerate or simd framework as vectorized version. |
|
The problem is that some symbols are missing from the cdylib, like |
|
|
||
| #[cfg(not(test))] | ||
| #[lang = "eh_personality"] | ||
| extern "C" fn eh_personality() {} |
There was a problem hiding this comment.
This has to do with libcore itself being built with panic=unwind, but why not just link to std and have it provide these?
| #![cfg_attr(not(test), no_std)] | ||
|
|
||
| #[path = "../../../src/math/mod.rs"] | ||
| mod libm; |
There was a problem hiding this comment.
Could this do extern crate libm instead?
There was a problem hiding this comment.
That would pull in std, see below.
| // fn tgamma(x: f64) -> f64: (42.) -> 42.; | ||
| // fn tgammaf(x: f32) -> f32: (42.) -> 42.; | ||
| fn trunc(x: f64) -> f64: (42.) -> 42.; | ||
| fn truncf(x: f32) -> f32: (42.) -> 42.; |
There was a problem hiding this comment.
If we really want to maintain a cdylib in this repository then I would prefer that this list were automatically inferred instead of duplicated with the definitions in the main source code. If the duplication is going to happen here then I would prefer that this cdylib is provided in a different repository than this one.
There was a problem hiding this comment.
I'm still going to have to generate some of these by hand though because of the API mismatches between this libm, and C's libm.
There was a problem hiding this comment.
Yeah even the original test harness does that, but it's not as explicit why it does it, I had to look up the musl code to understand what was going on in the test harness.
| pub extern "C" fn $id($($arg: $arg_ty),*) -> $ret_ty { | ||
| // This just forwards the call to the appropriate function of the | ||
| // libm crate. | ||
| #[cfg(not(link_test))] { |
There was a problem hiding this comment.
Adding a pretty complicated macro to test what already has a pretty complicated of tests seems like overkill? Why does the cdylib itself need to be tested when it's all already tested elsewhere?
There was a problem hiding this comment.
This tests that the C ABI we provide is compatible with <math.h>, which is what allows this library to be used from C.
We currently don't test it, and in fact, libm currently doesn't provide a C compatible ABI, which is why some of the functions in the lib.rs are commented out.
Simplest example is the libm functions returning tuples by value (e.g. (i32, f32)). The libm C ABI doesn't do that, and takes pointer arguments instead that are used as "out" parameters. So the cdylib is going to have to workaround those manually.
| @@ -0,0 +1,143 @@ | |||
| use std::{fs, io, path::Path, process}; | |||
There was a problem hiding this comment.
I personally feel like this file may be a bit over-the-top when testing, I'm not sure it's really all that necessary to be invoking Cargo from this crate's own test suite to test various C things?
If it's really this extensive then I would prefer this not live in this repository to help keep this repository manageable and not pull in a whole set of new maintenance.
There was a problem hiding this comment.
It isn't expensive on my 8 year old system - cargo is invoked on every test, but the first invocation "locks", and once the first invocation completes, all of them just return "success - the library was already built".
I can use a lazy_static! to just call cargo once, but it felt like unnecessary complexity.
|
So I've cleaned this up, and CI is green. I've added two MacOSX build jobs, and a nightly x86_64-linux build job. For the time being, the tests are only run there. This is sub-optimal. Ideally, we would have a But these are architectural decision that have to be made depending on the goals of the library, so I've opened #195 to discuss that first. |
|
It seems like this is intended to build on #198 so I'm going to hold off on reviewing/merging until that's landed. |
This PR adds a new crate
libm-cdylibthat implements the<math.h>API and that is ABI compatible with the platforms libm implementation.Since libm is usually dynamically linked, this allows replacing the libm implementation of any program in the platform with the Rust implementation, e.g., using
LD_PRELOADand similar APIs.The library is tested by just linking it to C programs that use
<cmath.h>and checking that the library is called and produce expected "unique" results that differ from the system libraries. The C programs are linked to the system library, and then the math library is dynamically overriden.Right now this works properly on macos, I'll iterate on the linux part of this on CI.