Fabrik C API Documentation
The Fabrik C API provides a thread-safe interface for integrating Fabrik cache into C/C++ applications and other toolchains.
Installation
From Releases
Download the pre-built libraries for your platform from the releases page:
- Linux:
libfabrik.so+fabrik.h - macOS:
libfabrik.dylib+fabrik.h - Windows:
fabrik.dll+fabrik.h
Building from Source
# Clone the repository
git clone https://github.com/tuist/fabrik.git
cd fabrik
# Build the library
cargo build --release --lib
# The library will be at:
# - Linux: target/release/libfabrik.so
# - macOS: target/release/libfabrik.dylib
# - Windows: target/release/fabrik.dll
# The header file will be at:
# include/fabrik.hQuick Start
Basic Example
#include <fabrik.h>
#include <stdio.h>
int main() {
// Initialize cache
FabrikCache *cache = fabrik_cache_init("/tmp/my-cache");
if (!cache) {
fprintf(stderr, "Failed to init: %s\n", fabrik_last_error());
return 1;
}
// Store data
const char *data = "Hello, World!";
const char *hash = "abc123...";
if (fabrik_cache_put(cache, hash, (uint8_t*)data, 13) != FABRIK_OK) {
fprintf(stderr, "Failed to put: %s\n", fabrik_last_error());
}
// Retrieve data
uint8_t buffer[1024];
size_t bytes_read;
if (fabrik_cache_get(cache, hash, buffer, sizeof(buffer), &bytes_read) == FABRIK_OK) {
printf("Retrieved %zu bytes\n", bytes_read);
}
// Cleanup
fabrik_cache_free(cache);
return 0;
}Building Your Application
GCC/Clang
gcc -o myapp myapp.c -I/path/to/fabrik/include -L/path/to/fabrik/lib -lfabrikCMake
cmake_minimum_required(VERSION 3.10)
project(MyApp)
# Find Fabrik
find_library(FABRIK_LIB fabrik PATHS /path/to/fabrik/lib)
include_directories(/path/to/fabrik/include)
add_executable(myapp myapp.c)
target_link_libraries(myapp ${FABRIK_LIB})pkg-config
If Fabrik is installed system-wide:
gcc -o myapp myapp.c $(pkg-config --cflags --libs fabrik)API Reference
Types
FabrikCache
Opaque handle to a cache instance. Must be freed with fabrik_cache_free().
typedef struct FabrikCache FabrikCache;Error Codes
#define FABRIK_OK 0 // Success
#define FABRIK_ERROR -1 // General error
#define FABRIK_ERROR_NOT_FOUND -2 // Artifact not found
#define FABRIK_ERROR_INVALID_HASH -3 // Invalid hash format
#define FABRIK_ERROR_IO -4 // I/O errorFunctions
fabrik_cache_init
Initialize a new cache instance with default eviction settings (5GB max size, LFU policy, 7 days TTL).
FabrikCache* fabrik_cache_init(const char *cache_dir);Parameters:
cache_dir: Path to cache directory (NULL-terminated C string)
Returns:
- Pointer to
FabrikCacheon success NULLon error (usefabrik_last_error()for details)
Example:
FabrikCache *cache = fabrik_cache_init("/home/user/.cache/fabrik");
if (!cache) {
fprintf(stderr, "Init failed: %s\n", fabrik_last_error());
}fabrik_cache_init_with_eviction
Initialize a new cache instance with custom eviction settings.
FabrikCache* fabrik_cache_init_with_eviction(
const char *cache_dir,
uint64_t max_size_bytes,
int eviction_policy,
uint64_t ttl_seconds
);Parameters:
cache_dir: Path to cache directory (NULL-terminated C string)max_size_bytes: Maximum cache size in bytes (0 for default: 5GB)eviction_policy: Eviction policy (0=LRU, 1=LFU, 2=TTL)ttl_seconds: Default TTL in seconds (0 for default: 7 days)
Returns:
- Pointer to
FabrikCacheon success NULLon error (usefabrik_last_error()for details)
Example:
// 10GB cache with LRU eviction and 14 day TTL
FabrikCache *cache = fabrik_cache_init_with_eviction(
"/home/user/.cache/fabrik",
10ULL * 1024 * 1024 * 1024, // 10GB
0, // LRU
14 * 24 * 60 * 60 // 14 days
);
if (!cache) {
fprintf(stderr, "Init failed: %s\n", fabrik_last_error());
}Eviction Policies:
0(LRU): Least Recently Used - evicts objects not accessed for longest time1(LFU): Least Frequently Used - evicts objects with lowest access count (default)2(TTL): Time To Live - evicts objects older than specified TTL
fabrik_cache_free
Free a cache instance.
void fabrik_cache_free(FabrikCache *cache);Parameters:
cache: Cache instance to free
Notes:
- Safe to call with
NULL - Must not use the cache after calling this function
fabrik_cache_put
Store an artifact in the cache.
int fabrik_cache_put(
FabrikCache *cache,
const char *hash,
const uint8_t *data,
size_t data_len
);Parameters:
cache: Cache instancehash: Content hash (SHA256, 64 hex characters)data: Data to storedata_len: Length of data in bytes
Returns:
FABRIK_OKon success- Error code on failure
Example:
const char *data = "artifact content";
const char *hash = "abc123def456...";
int result = fabrik_cache_put(cache, hash, (uint8_t*)data, strlen(data));
if (result != FABRIK_OK) {
fprintf(stderr, "Put failed: %s\n", fabrik_last_error());
}fabrik_cache_get
Retrieve an artifact from the cache.
int fabrik_cache_get(
FabrikCache *cache,
const char *hash,
uint8_t *output_buffer,
size_t buffer_size,
size_t *bytes_written
);Parameters:
cache: Cache instancehash: Content hash to retrieveoutput_buffer: Buffer to write data (must be pre-allocated)buffer_size: Size of output bufferbytes_written: Output parameter for actual bytes written
Returns:
FABRIK_OKon successFABRIK_ERROR_NOT_FOUNDif artifact doesn't existFABRIK_ERRORif buffer is too small or other error
Example:
uint8_t buffer[4096];
size_t bytes_read;
int result = fabrik_cache_get(cache, hash, buffer, sizeof(buffer), &bytes_read);
if (result == FABRIK_OK) {
printf("Read %zu bytes\n", bytes_read);
} else if (result == FABRIK_ERROR_NOT_FOUND) {
printf("Artifact not found\n");
}fabrik_cache_exists
Check if an artifact exists in the cache.
int fabrik_cache_exists(
FabrikCache *cache,
const char *hash,
int *exists
);Parameters:
cache: Cache instancehash: Content hash to checkexists: Output parameter (1 if exists, 0 if not)
Returns:
FABRIK_OKon success- Error code on failure
Example:
int exists;
if (fabrik_cache_exists(cache, hash, &exists) == FABRIK_OK) {
printf("Artifact %s\n", exists ? "exists" : "not found");
}fabrik_cache_delete
Delete an artifact from the cache.
int fabrik_cache_delete(
FabrikCache *cache,
const char *hash
);Parameters:
cache: Cache instancehash: Content hash to delete
Returns:
FABRIK_OKon success- Error code on failure
Example:
if (fabrik_cache_delete(cache, hash) == FABRIK_OK) {
printf("Artifact deleted\n");
}fabrik_last_error
Get the last error message for the current thread.
const char* fabrik_last_error(void);Returns:
- Pointer to NULL-terminated error string
NULLif no error
Notes:
- Error message is valid until next API call
- Do not free the returned pointer
- Thread-local (each thread has its own error)
fabrik_version
Get the library version string.
const char* fabrik_version(void);Returns:
- Pointer to version string (e.g., "0.8.1")
- String is statically allocated, do not free
Error Handling
All functions follow a consistent error handling pattern:
int result = fabrik_cache_put(cache, hash, data, len);
if (result != FABRIK_OK) {
// Get detailed error message
const char *error = fabrik_last_error();
fprintf(stderr, "Operation failed: %s\n", error);
// Check specific error codes
if (result == FABRIK_ERROR_NOT_FOUND) {
// Handle not found
} else if (result == FABRIK_ERROR_IO) {
// Handle I/O error
}
}Thread Safety
The Fabrik C API is fully thread-safe:
- Multiple threads can safely access the same cache instance
- Each thread has its own error state (
fabrik_last_error()) - No global state or locks required by the caller
// Thread-safe example
void* worker_thread(void *arg) {
FabrikCache *cache = (FabrikCache*)arg;
// Safe to call from multiple threads
int exists;
fabrik_cache_exists(cache, "hash123", &exists);
return NULL;
}Platform-Specific Notes
Linux
- Library:
libfabrik.so - Runtime library path: Set
LD_LIBRARY_PATHor install to/usr/lib
export LD_LIBRARY_PATH=/path/to/fabrik/lib:$LD_LIBRARY_PATH
./myappmacOS
- Library:
libfabrik.dylib - Runtime library path: Set
DYLD_LIBRARY_PATHor use@rpath
export DYLD_LIBRARY_PATH=/path/to/fabrik/lib:$DYLD_LIBRARY_PATH
./myappWindows
- Library:
fabrik.dll - Place DLL in same directory as executable or in system PATH
Examples
Note: C API examples are coming soon.
Integration Patterns
Build System Integration
Example of integrating Fabrik into a build system:
#include <fabrik.h>
void check_build_cache(const char *artifact_hash) {
FabrikCache *cache = fabrik_cache_init(".build/cache");
if (!cache) return;
int exists;
if (fabrik_cache_exists(cache, artifact_hash, &exists) == FABRIK_OK) {
if (exists) {
// Skip rebuild, artifact is cached
uint8_t buffer[1024*1024]; // 1MB buffer
size_t bytes_read;
fabrik_cache_get(cache, artifact_hash, buffer, sizeof(buffer), &bytes_read);
// Use cached artifact...
}
}
fabrik_cache_free(cache);
}Error Logging Wrapper
#define FABRIK_CHECK(op, msg) \
if ((op) != FABRIK_OK) { \
log_error("%s: %s", msg, fabrik_last_error()); \
goto cleanup; \
}
int build_with_cache() {
FabrikCache *cache = fabrik_cache_init("/tmp/cache");
if (!cache) return -1;
FABRIK_CHECK(fabrik_cache_put(cache, hash, data, len), "Failed to cache artifact");
FABRIK_CHECK(fabrik_cache_get(cache, hash, buf, sizeof(buf), &n), "Failed to retrieve");
cleanup:
fabrik_cache_free(cache);
return 0;
}Troubleshooting
Library Not Found
Symptom:
error while loading shared libraries: libfabrik.so: cannot open shared object fileSolution:
- Set
LD_LIBRARY_PATH(Linux) orDYLD_LIBRARY_PATH(macOS) - Install library to system path
- Use
-rpathlinker flag
Initialization Fails
Symptom:
fabrik_cache_init() returns NULLCommon causes:
- Invalid cache directory path
- Insufficient permissions
- Disk full
Solution:
FabrikCache *cache = fabrik_cache_init("/tmp/cache");
if (!cache) {
fprintf(stderr, "Init failed: %s\n", fabrik_last_error());
// Check permissions, disk space, path validity
}Buffer Too Small
Symptom:
fabrik_cache_get() returns FABRIK_ERROR
fabrik_last_error() says "Buffer too small"Solution: Use a larger buffer or dynamically allocate based on artifact size.
Support
- Documentation: https://github.com/tuist/fabrik
- Issues: https://github.com/tuist/fabrik/issues
- Discord: https://discord.gg/tuist
License
MPL-2.0 License - see LICENSE for details.