libcall

test Gem Version Lines of Code

Call C functions in shared libraries from the command line.

Installation

gem install libcall

Quick Examples

libcall -lm sqrt double 16 -r double # => 4.0
libcall -lc strlen string "hello" -r usize # => 5

Usage

libcall [OPTIONS] <LIBRARY> <FUNCTION> (TYPE VALUE)...

Options

  • -l LIBRARY - library name (searches standard paths)
  • -L PATH - add library search path
  • -r TYPE - return type (void, i32, f64, cstr, ptr)
  • --dry-run - validate without executing
  • --json - JSON output
  • --verbose - detailed info
  • -h, --help - show help
  • -v, --version - show version

Library search:

  • -L adds search paths; -l resolves by name
  • On Linux and macOS, LD_LIBRARY_PATH / DYLD_LIBRARY_PATH are honored

More Examples

Output parameter with libm

libcall -lm modf double -3.14 out:double -r f64
# Result: -0.14000000000000012
# Output parameters:
#   [1] double = -3.0

JSON output

libcall --json -lm sqrt double 9.0 -r f64
# {
#   "library": "/lib/x86_64-linux-gnu/libm.so",
#   "function": "sqrt",
#   "return_type": "double",
#   "result": 3.0
# }

Dry run

libcall --dry-run -lc getpid -r int
# Library:  /lib/x86_64-linux-gnu/libc.so
# Function: getpid
# Return:   int

Type Reference

libcall supports multiple naming conventions for types, making it easy to work with C libraries.

Integer Types

Short (Rust-like) C Standard C99/stdint.h Size
i8 / u8 char / uchar int8_t / uint8_t 1 byte
i16 / u16 short / ushort int16_t / uint16_t 2 bytes
i32 / u32 int / uint int32_t / uint32_t 4 bytes
i64 / u64 long_long / ulong_long int64_t / uint64_t 8 bytes
isize / usize long / ulong ssize_t / size_t platform-dependent

Alternative names: You can use any of these:

  • C-style: char, short, int, long, unsigned_int, etc.
  • stdint-style: int8, int16, int32, int64, uint8, uint16, etc.
  • With _t suffix: int8_t, uint8_t, int32_t, size_t, etc.

Floating Point Types

Short C Standard Alternative Size
f32 float float32 4 bytes
f64 double float64 8 bytes

Pointer Types

Type Description Usage
ptr / pointer / voidp Generic pointer (void*) For arbitrary memory addresses
string / cstr / str C string (char*) For passing/returning strings

Null pointer values: Use null, NULL, nil, or 0 to pass a null pointer.

Special Types

Type Description Alternative names
void No value (return type only)
size_t Platform size type usize (unsigned)
ssize_t Signed size type isize (signed)
intptr_t / uintptr_t Pointer-sized integer intptr / uintptr
ptrdiff_t Pointer difference type
bool Boolean (as int)

Output Parameters

Prefix any type with out: to create an output parameter:

out:int       # Output integer pointer (int*)
out:double    # Output double pointer (double*)
out:string    # Output string pointer (char**)

Array Types

Syntax Description Example
TYPE[] Input array int[] 1,2,3,4,5
out:TYPE[N] Output array of N elements out:int[10]
out:TYPE[N] Output array with initializer out:int[4] 4,3,2,1

Callback Types

Keyword Description Example
func Function pointer (callback) func 'int(int a,int b){ a+b }'
callback Alias for func Same as above

Argument Syntax

Pass arguments as TYPE VALUE pairs:

libcall -lm sqrt double 16.0 -r f64
libcall -lc strlen string "hello" -r usize
  • Null pointers: Use null, NULL, nil, or 0
  • Negative numbers work as expected (e.g., double -3.14)

pkg-config Support

Set PKG_CONFIG_PATH and use package names with -l:

PKG_CONFIG_PATH=/path/to/pkgconfig libcall -lmypackage func i32 42 -r i32

Output parameters (out:TYPE)

You can pass output pointers by specifying out:TYPE. The pointer is allocated automatically, passed to the function, and printed after the call.

# double frexp(double x, int* exp)
libcall -lm frexp double 8.0 out:int -r f64

# JSON includes an "outputs" array
libcall --json -lm frexp double 8.0 out:int -r f64

Arrays

  • Input arrays: TYPE[] takes a comma-separated value list.
# zlib (Linux/macOS): uLong crc32(uLong crc, const Bytef* buf, uInt len)
libcall -lz crc32 uint 0 uchar[] 104,101,108,108,111 uint 5 -r uint
  • Output arrays: out:TYPE[N] allocates N elements and prints them after the call.
# Linux (libc): ssize_t getrandom(void* buf, size_t buflen, unsigned int flags)
libcall -lc getrandom out:uchar[16] size_t 16 uint 0 -r long
# macOS (libSystem): void arc4random_buf(void* buf, size_t nbytes)
libcall -lSystem arc4random_buf out:uchar[16] size_t 16 -r void

Callbacks (experimental)

Pass a C function pointer via a Ruby callback. Use func or callback with a quoted spec:

  • Syntax: func 'RET(TYPE name, TYPE name, ...){ ruby_code }' (alias: callback ...)
  • Inside the block, helper methods from Libcall::Fiddley::DSL are available:
    • int(ptr), double(ptr), cstr(ptr) read values from pointers
    • read(:type, ptr) reads any supported type; ptr(addr) makes a pointer

Quick examples

# Fixture function: int32_t apply_i32(int32_t, int32_t, int32_t (*)(int32_t,int32_t))
libcall -ltest -L test/fixtures/libtest/build apply_i32 \
    int 3 int 5 \
    func 'int(int a,int b){ a + b }' \
    -r i32
# => 8
# libc qsort: sort 4 ints ascending; use out:int[4] with an initializer so the result prints
libcall -lc qsort \
    out:int[4] 4,2,3,1 \
    size_t 4 \
    size_t 4 \
    callback 'int(void* a, void* b){ int(a) <=> int(b) }' \
    -r void
# Output parameters:
#   [0] int[4] = [1, 2, 3, 4]

Notes

  • Match the C signature exactly (types and arity). Blocks run in-process; exceptions abort the call.

Warning

FFI calls are inherently unsafe. You must:

  • Provide correct function signatures
  • Match argument types exactly
  • Handle memory correctly
  • Understand ABI compatibility

Incorrect usage can crash your program.

Windows Support

Supports DLLs (e.g., msvcrt.dll, kernel32.dll). Searches in System32, PATH, and MSYS2/MinGW directories. For building custom DLLs, RubyInstaller with DevKit is recommended.

Windows Examples

# Calling C runtime functions
libcall msvcrt.dll sqrt double 16.0 -r f64 # => 4.0
# Accessing environment variables
libcall msvcrt.dll getenv string "PATH" -r cstr

Development

bundle install
bundle exec rake test

License

MIT