Skip to main content

bindings/
bindings.rs

1//! Declaring a whole API with `library!`.
2//!
3//! Run with `cargo run --example bindings`.
4
5#![allow(clippy::multiple_unsafe_ops_per_block)]
6
7use std::ffi::{CStr, c_char, c_int, c_long};
8
9use dlsym::{Bindings, Library};
10
11dlsym::library! {
12    /// A few functions from the C library.
13    pub struct LibC {
14        unsafe extern "C" {
15            /// Safe to call with any argument, so no `unsafe` needed.
16            pub safe fn labs(x: c_long) -> c_long;
17            pub fn strlen(s: *const c_char) -> usize;
18            pub fn atoi(s: *const c_char) -> c_int;
19            pub fn sprintf(buf: *mut c_char, fmt: *const c_char, ...) -> c_int;
20            /// Not every C library has it: `None` when missing.
21            #[optional]
22            pub fn strlcpy(dst: *mut c_char, src: *const c_char, size: usize) -> usize;
23        }
24    }
25}
26
27fn main() -> dlsym::Result<()> {
28    #[cfg(not(windows))]
29    let lib = Library::this()?;
30    // SAFETY: msvcrt is a system library.
31    #[cfg(windows)]
32    let lib = unsafe { Library::open("msvcrt.dll") }?;
33    // Resolves every symbol now; a missing non-optional one is an error.
34    let libc = LibC::load(lib)?;
35
36    println!("labs(-42) = {}", libc.labs(-42));
37    // SAFETY: valid C strings.
38    unsafe {
39        println!("strlen(\"dlsym\") = {}", libc.strlen(c"dlsym".as_ptr()));
40        println!("atoi(\"123\") = {}", libc.atoi(c"123".as_ptr()));
41    }
42
43    let mut buf = [0 as c_char; 32];
44    // SAFETY: the buffer is large enough and the format matches.
45    unsafe {
46        libc.sprintf()
47            .with(|f| f(buf.as_mut_ptr(), c"%05.1f".as_ptr(), 2.5f64))
48    };
49    // SAFETY: `sprintf` NUL-terminated the buffer.
50    println!("sprintf = {:?}", unsafe { CStr::from_ptr(buf.as_ptr()) });
51
52    // SAFETY: never called with a null pointer here; we only check presence.
53    match unsafe { libc.strlcpy(buf.as_mut_ptr(), c"x".as_ptr(), buf.len()) } {
54        Some(n) => println!("strlcpy is available ({n})"),
55        None => println!("strlcpy is not available in this C library"),
56    }
57    Ok(())
58}