libcall
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:
-Ladds search paths;-lresolves by name- On Linux and macOS,
LD_LIBRARY_PATH/DYLD_LIBRARY_PATHare 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
_tsuffix: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, or0 - 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::DSLare available:int(ptr),double(ptr),cstr(ptr)read values from pointersread(: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