Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 69f6e56

Browse files
committed
Fix nitpicks
1 parent e77e85d commit 69f6e56

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

crates/libm-cdylib/src/lib.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,22 @@ mod test_utils;
1414
#[cfg(not(test))]
1515
#[panic_handler]
1616
fn panic(_info: &core::panic::PanicInfo) -> ! {
17+
// TODO: just call libc::abort - fails to link
18+
// unsafe { libc::abort() }
1719
unsafe { core::intrinsics::abort() }
1820
}
1921

22+
// TODO: there has to be a way to avoid this
2023
#[cfg(not(test))]
2124
#[lang = "eh_personality"]
2225
extern "C" fn eh_personality() {}
2326

24-
// All functions to be exported by the C ABI.
25-
// Includes a test input/output pair for testing.
26-
// The test output will be used to override the
27-
// result of the function, and the test input
28-
// is used to call the overriden function from C.
29-
// This is needed to make sure that we are linking
30-
// against this libm during testing, and not the
31-
// system's libm.
27+
// This macro exports the functions that are part of the C ABI.
3228
//
33-
//
34-
// FIXME: missing symbols: _memcpy, _memset, etc.
29+
// It generates tests that replace the implementation of the
30+
// function with a specific value, that then is used to check
31+
// that the library is properly linked.
32+
3533
export! {
3634
fn acos(x: f64) -> f64: (42.) -> 42.;
3735
fn acosf(x: f32) -> f32: (42.) -> 42.;
@@ -41,6 +39,7 @@ export! {
4139
fn asinf(x: f32) -> f32: (42.) -> 42.;
4240
fn asinh(x: f64) -> f64: (42.) -> 42.;
4341
fn asinhf(x: f32) -> f32: (42.) -> 42.;
42+
// FIXME: fails to link. Missing symbol: _memcpy
4443
// fn atan(x: f64) -> f64: (42.) -> 42.;
4544
fn atanf(x: f32) -> f32: (42.) -> 42.;
4645
fn atanh(x: f64) -> f64: (42.) -> 42.;
@@ -51,6 +50,7 @@ export! {
5150
fn ceilf(x: f32) -> f32: (42.) -> 42.;
5251
fn copysign(x: f64, y: f64) -> f64: (42., 42.) -> 42.;
5352
fn copysignf(x: f32, y: f32) -> f32: (42., 42.) -> 42.;
53+
// FIXME: fails to link. Missing symbols
5454
//fn cos(x: f64) -> f64: (42.) -> 42.;
5555
//fn cosf(x: f32) -> f32: (42.) -> 42.;
5656
fn cosh(x: f64) -> f64: (42.) -> 42.;
@@ -83,7 +83,7 @@ export! {
8383
fn fmod(x: f64, y: f64) -> f64: (42., 42.) -> 42.;
8484
fn fmodf(x: f32, y: f32) -> f32: (42., 42.) -> 42.;
8585

86-
// different ABI than in C
86+
// TODO: different ABI than in C - need a more elaborate wrapper
8787
// fn frexp(x: f64) -> (f64, i32): (42.) -> (42., 42);
8888
// fn frexpf(x: f32) -> (f32, i32): (42.) -> (42., 42);
8989

@@ -92,7 +92,7 @@ export! {
9292
fn ilogb(x: f64) -> i32: (42.) -> 42;
9393
fn ilogbf(x: f32) -> i32: (42.) -> 42;
9494

95-
// FIXME: fail to link:
95+
// FIXME: fails to link. Missing symbols
9696
// fn j0(x: f64) -> f64: (42.) -> 42.;
9797
// fn j0f(x: f32) -> f32: (42.) -> 42.;
9898
// fn j1(x: f64) -> f64: (42.) -> 42.;
@@ -105,7 +105,7 @@ export! {
105105
fn lgamma(x: f64) -> f64: (42.) -> 42.;
106106
fn lgammaf(x: f32) -> f32: (42.) -> 42.;
107107

108-
// different ABI
108+
// TODO: different ABI than in C - need a more elaborate wrapper
109109
// fn lgamma_r(x: f64) -> (f64, i32): (42.) -> (42., 42);
110110
// fn lgammaf_r(x: f32) -> (f32, i32): (42.) -> (42., 42);
111111

@@ -119,10 +119,10 @@ export! {
119119
fn log2f(x: f32) -> f32: (42.) -> 42.;
120120
fn pow(x: f64, y: f64) -> f64: (42., 42.) -> 42.;
121121
fn powf(x: f32, y: f32) -> f32: (42., 42.) -> 42.;
122+
123+
// FIXME: different ABI than in C - need a more elaborate wrapper
122124
// fn modf(x: f64) -> (f64, f64): (42.) -> (42., 42.);
123125
// fn modff(x: f32) -> (f32, f32): (42.) -> (42., 42.);
124-
125-
// different ABI
126126
// remquo
127127
// remquof
128128

@@ -131,21 +131,24 @@ export! {
131131
fn scalbn(x: f64, n: i32) -> f64: (42., 42) -> 42.;
132132
fn scalbnf(x: f32, n: i32) -> f32: (42., 42) -> 42.;
133133

134-
// different ABI
134+
// FIXME: different ABI than in C - need a more elaborate wrapper
135135
// fn sincos
136136
// fn sincosf
137137

138+
// FIXME: missing symbols - fails to link
138139
// fn sin(x: f64) -> f64: (42.) -> 42.;
139140
// fn sinf(x: f32) -> f32: (42.) -> 42.;
140141

141142
fn sinh(x: f64) -> f64: (42.) -> 42.;
142143
fn sinhf(x: f32) -> f32: (42.) -> 42.;
143144
fn sqrt(x: f64) -> f64: (42.) -> 42.;
144145
fn sqrtf(x: f32) -> f32: (42.) -> 42.;
146+
// FIXME: missing symbols - fails to link
145147
// fn tan(x: f64) -> f64: (42.) -> 42.;
146148
// fn tanf(x: f32) -> f32: (42.) -> 42.;
147149
fn tanh(x: f64) -> f64: (42.) -> 42.;
148150
fn tanhf(x: f32) -> f32: (42.) -> 42.;
151+
// FIXME: missing symbols - fails to link
149152
// fn tgamma(x: f64) -> f64: (42.) -> 42.;
150153
// fn tgammaf(x: f32) -> f32: (42.) -> 42.;
151154
fn trunc(x: f64) -> f64: (42.) -> 42.;

crates/libm-cdylib/src/macros.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,33 @@ macro_rules! export {
33
($($test_arg:expr),*) -> $test_ret:expr;) => {
44
#[no_mangle]
55
pub extern "C" fn $id($($arg: $arg_ty),*) -> $ret_ty {
6+
// This just forwards the call to the appropriate function of the
7+
// libm crate.
8+
#[cfg(not(link_test))] {
9+
libm::$id($($arg),*)
10+
}
11+
// When generating the linking tests, we return a specific incorrect
12+
// value. This lets us tell this libm from the system's one appart:
613
#[cfg(link_test)] {
14+
// TODO: as part of the rountrip, we probably want to verify
15+
// that the argument values are the unique ones provided.
716
let _ = libm::$id($($arg),*);
817
$test_ret as _
918
}
10-
#[cfg(not(link_test))] {
11-
libm::$id($($arg),*)
12-
}
1319
}
1420

1521
#[cfg(test)]
1622
paste::item! {
23+
// These tests check that the library links properly.
1724
#[test]
18-
fn [<$id _test>]() {
25+
fn [<$id _link_test>]() {
1926
use crate::test_utils::*;
20-
let (cret_t, c_format_s) = ctype_and_cformat(stringify!($ret_ty));
27+
28+
// Generate a small C program that calls the C API from
29+
// <math.h>. This program prints the result into an appropriate
30+
// type, that is then printed to stdout.
31+
let (cret_t, c_format_s)
32+
= ctype_and_printf_format_specifier(stringify!($ret_ty));
2133
let ctest = format!(
2234
r#"
2335
#include <math.h>
@@ -40,8 +52,13 @@ macro_rules! export {
4052
let src_path = std::path::Path::new(src);
4153
let bin_path = std::path::Path::new(bin);
4254
write_to_file(&src_path, &ctest);
55+
56+
// We now compile the C program into an executable, make sure
57+
// that the libm-cdylib has been generated (and generate it if
58+
// it isn't), and then we run the program, override the libm
59+
// dynamically, and verify the result.
4360
compile_file(&src_path, &bin_path);
44-
compile_lib();
61+
compile_cdylib();
4562
check(&bin_path, $test_ret as $ret_ty)
4663
}
4764
}

crates/libm-cdylib/src/test_utils.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
use std::{fs, io, path::Path, process};
22

3+
/// Writes the `content` string to a file at `path`.
34
pub(crate) fn write_to_file(path: &Path, content: &str) {
45
use io::Write;
56
let mut file = fs::File::create(&path).unwrap();
67
write!(file, "{}", content).unwrap();
78
}
89

9-
pub(crate) fn compile_lib() {
10+
/// Compiles the libm-cdylib library as a C library.
11+
///
12+
/// This just compiles it once, all other times it just
13+
/// succeeds. We compile it with --cfg link_test to
14+
/// enable the tests.
15+
pub(crate) fn compile_cdylib() {
1016
let mut cmd = process::Command::new("cargo");
1117
cmd.arg("build");
1218
if cfg!(release_profile) {
@@ -16,8 +22,16 @@ pub(crate) fn compile_lib() {
1622
handle_err("lib_build", &cmd.output().unwrap());
1723
}
1824

25+
/// Compiles the test C program with source at `src_path` into
26+
/// an executable at `bin_path`.
1927
pub(crate) fn compile_file(src_path: &Path, bin_path: &Path) {
2028
let mut cmd = process::Command::new("CC");
29+
// We disable the usage of builtin functions, e.g., from libm.
30+
// This should ideally produce a link failure if libm is not dynamically
31+
// linked.
32+
//
33+
// On MacOSX libSystem is linked (for printf, etc.) and it links libSystem_m
34+
// transitively, so this doesn't help =/
2135
cmd.arg("-fno-builtin")
2236
.arg("-o")
2337
.arg(bin_path)
@@ -28,15 +42,17 @@ pub(crate) fn compile_file(src_path: &Path, bin_path: &Path) {
2842
);
2943
}
3044

45+
/// Run the program and verify that it prints the expected value.
3146
pub(crate) fn check<T>(path: &Path, expected: T)
3247
where
3348
T: PartialEq + std::fmt::Debug + std::str::FromStr,
3449
<T as std::str::FromStr>::Err: std::fmt::Debug,
3550
{
3651
let mut cmd = process::Command::new(path);
3752

53+
// Find the cdylib - we just support standard locations for now.
3854
let libm_path = format!(
39-
"../../target/{}/liblibm.",
55+
"../../target/{}/liblibm",
4056
if cfg!(release_profile) {
4157
"release"
4258
} else {
@@ -46,6 +62,7 @@ where
4662

4763
// Replace libm at runtime
4864
if cfg!(target_os = "macos") {
65+
// for debugging:
4966
// cmd.env("DYLD_PRINT_LIBRARIES", "1");
5067
// cmd.env("X", "1");
5168
cmd.env("DYLD_FORCE_FLAT_NAMESPACE", "1");
@@ -54,17 +71,20 @@ where
5471
format!("{}.{}", libm_path, "dylib"),
5572
);
5673
} else if cfg!(target_os = "linux") {
57-
cmd.env("LD_PRELOAD", format!("{}.{}", libm_path, "so"))
74+
cmd.env("LD_PRELOAD", format!("{}.{}", libm_path, "so"));
5875
}
76+
// Run the binary:
5977
let output = cmd.output().unwrap();
6078
handle_err(&format!("run file: {}", path.display()), &output);
79+
// Parse the result:
6180
let result = String::from_utf8(output.stdout.clone())
6281
.unwrap()
6382
.parse::<T>();
6483

6584
if result.is_err() {
6685
panic!(format_output("check (parse failure)", &output));
6786
}
87+
// Check the result:
6888
let result = result.unwrap();
6989
assert_eq!(result, expected, "{}", format_output("check", &output));
7090
}
@@ -98,7 +118,9 @@ pub(crate) fn format_output(
98118
s
99119
}
100120

101-
pub(crate) fn ctype_and_cformat(x: &str) -> (&str, &str) {
121+
/// For a given Rust type `x`, this prints the name of the type in C,
122+
/// as well as the printf format specifier used to print values of that type.
123+
pub(crate) fn ctype_and_printf_format_specifier(x: &str) -> (&str, &str) {
102124
match x {
103125
"f32" => ("float", "%f"),
104126
"f64" => ("double", "%f"),

src/math/acos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn r(z: f64) -> f64 {
6262
/// Returns values in radians, in the range of 0 to pi.
6363
#[inline]
6464
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
65-
extern "C" pub fn acos(x: f64) -> f64 {
65+
pub fn acos(x: f64) -> f64 {
6666
let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120
6767
let z: f64;
6868
let w: f64;

0 commit comments

Comments
 (0)