Shared-memory IPC library with a stable C ABI for embedding into C, C++, and ROS2 applications.
Renoir is written in Rust and exposes its entire API through a C-compatible FFI layer generated by cbindgen. Link librenoir.so (or .a) into any language that can call C functions no Rust toolchain required at runtime.
The primary interface. Include renoir.h and link against the shared or static library.
#include "renoir.h"
RenoirTopicManagerHandle mgr = renoir_topic_manager_create();
RenoirTopicOptions opts = {0};
opts.pattern = 0; // SPSC
opts.ring_capacity = 16; // power of 2
opts.max_payload_size = 1024;
RenoirTopicId tid;
renoir_topic_register(mgr, "/sensor/imu", &opts, &tid);
// Publisher
RenoirPublisherOptions pub_opts = {0};
RenoirPublisherHandle pub;
renoir_publisher_create(mgr, "/sensor/imu", &pub_opts, &pub);
RenoirMessageMetadata meta = {0};
renoir_publish(pub, data, len, &meta);
// Subscriber
RenoirSubscriberOptions sub_opts = {0};
RenoirSubscriberHandle sub;
renoir_subscriber_create(mgr, "/sensor/imu", &sub_opts, &sub);
RenoirReceivedMessage msg;
if (renoir_subscribe_read_next(sub, &msg) == Success) {
// msg.data, msg.data_len
renoir_message_release(&msg);
}
renoir_publisher_destroy(pub);
renoir_subscriber_destroy(sub);
renoir_topic_manager_destroy(mgr);RenoirManagerHandle mgr = renoir_manager_create();
RenoirRegionConfig cfg = {0};
cfg.name = "sensor_data";
cfg.size = 64 * 1024 * 1024;
cfg.backing_type = 1; // MemFd
RenoirRegionHandle region;
renoir_region_create(mgr, &cfg, ®ion);
RenoirRegionStats stats;
renoir_region_stats(region, &stats);
renoir_region_destroy(region);
renoir_manager_destroy(mgr);RenoirBufferPoolConfig pool_cfg = {0};
pool_cfg.buffer_size = 4096;
pool_cfg.buffer_count = 64;
RenoirBufferPoolHandle pool;
renoir_buffer_pool_create(mgr, region, &pool_cfg, &pool);
RenoirBufferHandle buf;
renoir_buffer_get(pool, &buf);
// write into buf...
renoir_buffer_return(pool, buf);
renoir_buffer_pool_destroy(pool);See examples/ for complete C++ programs covering topics, regions, buffers, and control regions.
The same functionality is available as a Rust crate.
use renoir::topic::{TopicConfig, TopicPattern};
use renoir::topic_manager_modules::TopicManager;
let manager = TopicManager::new().unwrap();
let config = TopicConfig {
name: "sensor/imu".to_string(),
pattern: TopicPattern::SPSC,
ring_capacity: 1024,
max_payload_size: 4096,
..Default::default()
};
manager.create_topic(config).unwrap();
let publisher = manager.create_publisher("sensor/imu").unwrap();
let subscriber = manager.create_subscriber("sensor/imu").unwrap();
publisher.publish(b"acceleration data".to_vec()).unwrap();
if let Some(message) = subscriber.subscribe().unwrap() {
// process message
}# Build everything (Rust library + C headers + C++ examples)
./build.sh
# Or individual steps
./build.sh build-rust # Rust library only
./build.sh build-examples # C++ examples only
./build.sh test # Run tests
./build.sh clippy # Lint
./build.sh fmt # Format
./build.sh clean # Clean all artifacts
./build.sh headers # Regenerate C headers
# Debug build
./build.sh build-all --debugOr directly with cargo:
cargo build --release
cargo testRecommended pre-push validation:
./build.sh
cargo clippy --all-targets --all-features -- -D warnings
cargo testThis sequence verifies FFI/header generation, compile integrity, lint policy, and runtime behavior before distribution.
The C header is generated at target/include/renoir.h during build.
| Flag | Default | Description |
|---|---|---|
file-backed |
yes | File-backed shared memory regions |
memfd |
yes | memfd_create support (Linux) |
c-api |
yes | C FFI bindings via cbindgen |
cli |
no | Command-line tool |
custom-allocator |
no | mimalloc global allocator |
cargo build --release --target aarch64-unknown-linux-gnu # ARM64 (Jetson, RPi 4)
cargo build --release --target armv7-unknown-linux-gnueabihf # ARMv7 (RPi 3)Renoir is organized as layered modules with explicit ownership boundaries:
| Layer | Purpose | Key paths |
|---|---|---|
| C ABI boundary | Stable handle-based API for C/C++ and ROS2 integrations | src/ffi/ |
| Topic lifecycle | Publisher/subscriber creation, routing, and metadata orchestration | src/topic_manager_modules/, src/topic/ |
| Ring and pool core | Lock-free ring transport and shared buffer pool management | src/topic_rings/, src/ringbuf/, src/shared_pools/, src/buffers/ |
| Memory and synchronization | Region allocation and cross-thread/process synchronization primitives | src/memory/, src/sync/, src/allocators/ |
| Message and compatibility | Payload formats, layout evolution, and large-message handling | src/message_formats/, src/structured_layout/, src/large_payloads/ |
Operational characteristics:
- Message handles define ownership and must be released explicitly at the FFI boundary.
- Descriptor and payload paths validate pointer/length invariants before user-visible handoff.
- Ring publish/consume paths are hardened for wraparound behavior and high-throughput contention.
- Rust 1.70+ (2021 edition)
- Linux (uses
memfd_create,eventfd,mlock) - CMake + Ninja or Make (for C++ examples)
- Targets: x86_64, aarch64, armv7
GitHub Actions pipeline runs on every push and PR:
- Lint (rustfmt, clippy, doc generation)
- Build on ubuntu/windows/macos with stable and beta
- Full test suite with per-file timeouts
- Cross-compilation for aarch64, armv7, x86_64-musl
- Security audit (cargo-audit, cargo-deny)
- Performance benchmarks on main branch
- Code coverage via tarpaulin + Codecov
MIT OR Apache-2.0