Skip to content
CryoCryo home
Stdlibffi

libc

import std::ffi::libc; · source

The libc surface

// Declarations are grouped by the header they come from, one extern block per group:
extern "C" {
    function kill(pid: i32, sig: i32) -> i32;
    function raise(sig: i32) -> i32;
    function sigaction(sig: i32, act: u8*, oldact: u8*) -> i32;
    function sigprocmask(how: SigprocmaskHow, set: u8*, oldset: u8*) -> i32;
    // ...
}

// Closed sets are typed enums, variant names verbatim from the header:
type enum Whence : i32 {
    SEEK_SET  = 0;
    SEEK_CUR  = 1;
    SEEK_END  = 2;
    SEEK_DATA = 3;
    SEEK_HOLE = 4;
}

// Bit-flag families and error codes are plain constants:
const O_RDONLY: i32 = 0;
const O_WRONLY: i32 = 1;
const O_RDWR:   i32 = 2;
const EINTR:    i32 = 4;

// Layout-stable structs are real Cryo types:
type struct timespec {
    tv_sec:  i64;
    tv_nsec: i64;
}

function errno() -> i32;

A single home for every extern "C" the standard library needs — some 640 functions — plus broad coverage of the POSIX and glibc surface for downstream use. Modules call libc::read(...), libc::sin(...) and so on, which keeps the rest of the tree free of inline extern blocks.

Functions mirror the libc and POSIX headers verbatim — same names, same signatures, same errno semantics. Idiomatic wrappers that return Result, work in Slice<u8>, or retry on EINTR live at the call site, not here. io::fd is the canonical example.

Sections are grouped by header, so you can skim for a function the way you would in man 3 or /usr/include:

errno.h    signal.h     fcntl.h      sys/stat.h   sys/uio.h    unistd.h
stdio.h    stdlib.h     string.h     ctype.h      time.h       sys/wait.h
sys/socket.h  arpa/inet.h  netdb.h   sys/select.h poll.h       sys/mman.h
sys/epoll.h   sys/eventfd.h  sys/signalfd.h  dirent.h  pthread.h  termios.h
sys/ioctl.h   locale.h     pwd.h     grp.h        regex.h      math.h
dlfcn.h    sys/resource.h

Where glibc and msvcrt disagree — errno values above 34, the _O_* open flags, the errno accessor itself — the declarations are gated per target with ![target(unix)] / ![target(windows)], so one libc:: spelling resolves to the right symbol on each.

Typed enums and flag constants

The split is deliberate and worth knowing before you go looking for a name.

Closed sets of mutually exclusive values are type enum Name : i32, so they pass to libc as typed parameters and the compiler catches a wrong-family argument. Variant names are kept verbatim from the C header — ClockId::CLOCK_MONOTONIC, not ClockId::Monotonic — so call sites read like the man pages.

type enum Whence : i32 {
    SEEK_SET = 0;
    SEEK_CUR = 1;
    SEEK_END = 2;
    SEEK_DATA = 3;
    SEEK_HOLE = 4;
}

type enum ClockId : i32 {
    CLOCK_REALTIME = 0;
    CLOCK_MONOTONIC = 1;
    CLOCK_PROCESS_CPUTIME_ID = 2;
    CLOCK_THREAD_CPUTIME_ID = 3;
    CLOCK_MONOTONIC_RAW = 4;
    CLOCK_REALTIME_COARSE = 5;
    CLOCK_MONOTONIC_COARSE = 6;
    CLOCK_BOOTTIME = 7;
    CLOCK_REALTIME_ALARM = 8;
    CLOCK_BOOTTIME_ALARM = 9;
    CLOCK_TAI = 11;
}

type enum AddressFamily : i32 {
    AF_UNSPEC = 0;
    AF_UNIX = 1;
    AF_INET = 2;
    AF_AX25 = 3;
    AF_IPX = 4;
    AF_APPLETALK = 5;
    AF_NETROM = 6;
    AF_BRIDGE = 7;
    AF_ATMPVC = 8;
    AF_X25 = 9;
    AF_INET6 = 10;
    AF_NETLINK = 16;
    AF_PACKET = 17;
    AF_BLUETOOTH = 31;
}

type enum Protocol : i32 {
    IPPROTO_IP = 0;
    IPPROTO_ICMP = 1;
    IPPROTO_IGMP = 2;
    IPPROTO_TCP = 6;
    IPPROTO_UDP = 17;
    IPPROTO_IPV6 = 41;
    IPPROTO_GRE = 47;
    IPPROTO_ESP = 50;
    IPPROTO_AH = 51;
    IPPROTO_ICMPV6 = 58;
    IPPROTO_RAW = 255;
}

type enum ShutdownHow : i32 {
    SHUT_RD = 0;
    SHUT_WR = 1;
    SHUT_RDWR = 2;
}

type enum DirentType : u8 {
    DT_UNKNOWN = 0;
    DT_FIFO = 1;
    DT_CHR = 2;
    DT_DIR = 4;
    DT_BLK = 6;
    DT_REG = 8;
    DT_LNK = 10;
    DT_SOCK = 12;
    DT_WHT = 14;
}

The full set: Whence, ClockId, ItimerWhich, AddressFamily, Protocol, SocketLevel, ShutdownHow, EpollOp, DirentType, MutexType, DetachState, CancelState, CancelType, LockType, FadviseAdvice, MadviseAdvice, BufferingMode, SigprocmaskHow, LocaleCategory, Resource, RusageWho, PriorityWhich, and the termios TcAction / TcQueue / TcFlow.

Bit-flag families stay as plain consts, because they get OR'd together and compared against return values, which a closed enum does not fit: O_*, S_IF*, POLL*, MAP_*, EPOLL*, AI_*, signal numbers, and errno codes.

C structs

Layout-stable POSIX structs are defined here as Cryo types with matching field order, so you can construct them directly:

type struct timespec {
    tv_sec:  i64;
    tv_nsec: i64;
}

type struct timeval {
    tv_sec:  i64;
    tv_usec: i64;
}

type struct tm {
    tm_sec:    i32;
    tm_min:    i32;
    tm_hour:   i32;
    tm_mday:   i32;
    tm_mon:    i32;
    tm_year:   i32;
    tm_wday:   i32;
    tm_yday:   i32;
    tm_isdst:  i32;
    tm_gmtoff: i64;
    tm_zone:   u8*;
}

type struct iovec {
    iov_base: u8*;
    iov_len:  u64;
}

type struct pollfd {
    fd:      i32;
    events:  i16;
    revents: i16;
}

type struct in_addr {
    s_addr: u32;
}

type struct in6_addr {
    s6_addr: u8[16];
}

type struct rlimit {
    rlim_cur: u64;
    rlim_max: u64;
}

type struct winsize {
    ws_row:    u16;
    ws_col:    u16;
    ws_xpixel: u16;
    ws_ypixel: u16;
}

type struct regmatch_t {
    rm_so: i64;
    rm_eo: i64;
}

Platform-variant structs are treated as opaque byte buffers that you pack and unpack yourself — sockaddr_in, struct stat, addrinfo, epoll_event, struct termios, and the pthread_* family. The accompanying SIZEOF_* constants give the Linux x86-64 size so a u8[SIZEOF_X] buffer comes out the right length. net::addr::sockaddr does exactly this for sockaddr_in.

Errno, signal, mode, fcntl, epoll, and ioctl values are the Linux x86-64 / glibc ABI. Other platforms re-derive them from the corresponding headers.

Floating-point classification — isnan, isinf, finite, signbit, fpclassify — is deliberately not declared here. It is implemented in pure Cryo over the IEEE-754 bit pattern instead, since those are macros rather than exported symbols in most libcs.