-
Notifications
You must be signed in to change notification settings - Fork 1
Build and Configure
This page explains how to build the library and how build-time/runtime configuration works across Rust, C/C++, and Python.
The repo includes build.py (source), a wrapper around Cargo and Maturin that:
- Sets packaged default environment variables (e.g.,
DEVICE_IDENTIFIER). - Enables feature flags (
embedded,python). - Optionally installs missing Rust targets via
rustup. - Produces consistent output for CI and local builds.
Examples:
./build.py release
./build.py check
./build.py check release
./build.py embedded release target=thumbv7em-none-eabihf device_id=FC
./build.py python
./build.py test release
./build.py maturin-install max_recent_rx_ids=256 env:MAX_STACK_PAYLOAD=128
Useful options:
-
checkrunscargo clippy -D warningsfor the default, python, and embedded builds. -
testruns the same clippy checks, then:-
cargo nextest run --features timesyncwhen cargo-nextest is installed, otherwisecargo test --features timesync -
cargo test --doc --features timesyncwhen nextest is used, since nextest does not run doctests - a stable Criterion smoke pass for
packet_pathsandrouter_system_paths cargo build --features python-
cargo build --no-default-features --target <embedded-target> --features embeddedwhen a matching cross C toolchain is available
-
-
device_id=<id>sets the packagedDEVICE_IDENTIFIERdefault for the build. -
static_schema_path=<path>setsSEDSNET_STATIC_SCHEMA_PATHfor runtime registry seeding. -
static_ipc_schema_path=<path>setsSEDSNET_STATIC_IPC_SCHEMA_PATHfor a runtime IPC/link-local seed. -
max_stack_payload=<n>setsMAX_STACK_PAYLOADfor inline payload storage. -
cryptographyis enabled by default and provides the cryptography provider APIs. -
env:KEY=VALUEpasses any compile-time env var used by src/config.rs (source). -
target=<triple>sets the Rust target triple for embedded builds.
From Cargo.toml (source):
-
std(default): host build with std. -
embedded: enables embedded defaults,timesync, and no_std-friendly behavior. -
python: enables pyo3 bindings. -
compression(default): enables payload compression (implemented withzstd-safe). -
timesync: enables time sync helpers and built-in time sync packet types. -
cryptography(default): enables Rust cryptography provider helpers plus optional C callback registration APIs.
Examples:
- Disable compression:
default-features = falseand omitcompression. - Embedded + compression: enable both
embeddedandcompression.
Compression notes:
- Compression is opportunistic (only used when it reduces size).
- Backend is fixed to
zstd-safefor simplicity/consistency across builds. - There is no compression-level build option.
- For cross-target embedded builds, enabling
compressionrequires a usable target C toolchain (forzstd-sys, e.g.arm-none-eabi-gccorCC_<target>override).
When timesync is enabled, the build adds the SEDSNET_TIME_SYNC endpoint and
SEDSNET_TIME_SYNC_* packet types directly in code (like SEDSNET_ERROR), plus the router-managed
internal network clock and FFI accessors for current network time. See Time-Sync
for roles, packet fields, internal clock behavior, and master-side setter APIs.
Python builds via maturin in this repo enable timesync by default (see
pyproject.toml (source)).
./build.py test is the intended top-level validation command for local development and CI-style checks in this repo.
It covers four layers:
- Static analysis: strict
cargo clippy -D warningsfor default,python, and embedded variants. - Rust unit and integration tests:
cargo nextest run --features timesyncwhen available, otherwisecargo test --features timesync, includingsrc/tests.rs, Rust system tests intests/rust-system-test/, and the Rust harness that configures and runs the C system tests intests/c-system-test/c_system_test.rs. - Benchmark smoke: run Criterion benchmarks into a dedicated
sedsnet_smokebaseline, with plot generation disabled, longer timing than the old fast path, and a wider smoke-test noise threshold so validation exercises benchmark code without treating normal workstation variance as a regression. - Build validation: host
pythonfeature build and embedded-feature build when an embedded cross C toolchain is present.
The C system tests exercise the static C ABI, multi-endpoint routing, relay forwarding, discovery, and time-sync
behavior through compiled executables in c-system-test/. The main multi-node C test now waits for every asserted
endpoint count before shutdown so it does not fail early when one simulated board drains slightly slower than another.
The Rust system tests under tests/rust-system-test/ cover the higher-level multi-node behaviors that matter most for
regressions:
- router-to-router and router-to-relay forwarding
- discovery route learning and selective forwarding
- adaptive multi-path routing
- reliable dropped-frame recovery
- end-to-end reliable verification and directed ACK return-path routing
- time-sync election, failover, and multi-node convergence
This repo does not currently publish or gate on a single required coverage percentage in build.py test. Coverage is
tracked primarily through regression tests across unit, Rust system, and C system layers. If you want a local
percentage/HTML report, use cargo-llvm-cov:
cargo llvm-cov --features timesync --workspace --htmlThat produces a local report under target/llvm-cov/html/.
For a fuller description of the test layers and recommended commands, see Testing.
Every build embeds a default DEVICE_IDENTIFIER. In v4 that name is discovery/config metadata; packed frames route by
compact address and do not repeat the hostname on every packet. Runtime APIs can override the active default or an
individual router/relay identity.
Recommended (Rust):
# .cargo/config.toml
[env]
DEVICE_IDENTIFIER = "GROUND_STATION_26"
CMake:
set(SEDSNET_DEVICE_IDENTIFIER "FC26_MAIN" CACHE STRING "" FORCE)
build.py (source):
./build.py release device_id=GROUND_STATION
Runtime overrides:
- Rust:
set_runtime_device_identifier("GROUND_STATION"),RouterConfig::with_sender(...), andRelayConfig::with_sender(...). - C:
seds_set_runtime_device_identifier(...),seds_router_set_sender_id(...),seds_relay_set_sender_id(...), andseds_router_configure_address(...). - Python:
sedsnet.set_runtime_device_identifier(...),Router(hostname=..., address_mode=..., requested_address=...),router.set_sender_id(...), androuter.configure_address(...).
Configuration values are read via option_env! in
src/config.rs (source).
You can set them via .cargo/config.toml,
build.py env:KEY=VALUE, or CMake SEDSNET_ENV_<KEY> variables.
These values are packaged defaults, not fixed board behavior for host/prebuilt builds. The active node can change
identity, time-sync role, memory pool limits, retry/reliable queue limits, string/binary static sizing, float string
precision, and compression threshold at runtime. MAX_STACK_PAYLOAD is the exception: it defines the compiled inline
payload capacity used by the stack-backed payload type, so runtime configuration can choose behavior up to that compiled
capacity but cannot enlarge the type layout after compilation.
Supported keys (defaults shown):
-
DEVICE_IDENTIFIER(TEST_PLATFORM) -
MAX_RECENT_RX_IDS(128) -
STARTING_QUEUE_SIZE(128 bytes) -
MAX_QUEUE_BUDGET(102400 bytes) -
QUEUE_GROW_STEP(3.2) -
PAYLOAD_COMPRESS_THRESHOLD(16 bytes) -
STATIC_STRING_LENGTH(1024) -
STATIC_HEX_LENGTH(1024) -
STRING_PRECISION(8) -
MAX_STACK_PAYLOAD(64, viadefine_stack_payload!) -
MAX_HANDLER_RETRIES(3) -
RELIABLE_RETRANSMIT_MS(250) -
RELIABLE_MAX_RETRIES(8) -
RELIABLE_MAX_PENDING(64) -
RELIABLE_MAX_RETURN_ROUTES(64) -
RELIABLE_MAX_END_TO_END_PENDING(RELIABLE_MAX_PENDING) -
RELIABLE_MAX_END_TO_END_ACK_CACHE(MAX_RECENT_RX_IDS)
MAX_QUEUE_BUDGET, MAX_RECENT_RX_IDS, STARTING_QUEUE_SIZE, and QUEUE_GROW_STEP are defaults,
not the only way to size a node. Rust can pass RuntimeMemoryConfig through
RouterConfig::with_memory_config(...) or RelayConfig::with_memory_config(...). C can use
seds_router_new_with_memory(...) and seds_relay_new_with_memory(...). Python can pass
max_queue_budget, max_recent_rx_ids, starting_queue_size, and queue_grow_step to
Router(...) or Relay(...).
The remaining active tuning values are process-wide runtime settings:
- Rust:
runtime_tuning_config()andset_runtime_tuning_config(RuntimeTuningConfig { ... }). - C:
seds_get_runtime_tuning_config(...)andseds_set_runtime_tuning_config(...). - Python:
sedsnet.runtime_tuning_config()andsedsnet.set_runtime_tuning_config(...).
The active queue budget is the shared queue-owned memory budget for each router or relay. RX queues,
TX queues, reliable replay/out-of-order buffers, and discovery topology state draw from this budget
dynamically. The recent packet ID cache preallocates
min(max_recent_rx_ids * sizeof(u64), max_queue_budget) bytes at construction and reserves that
amount from the same budget.
MAX_QUEUE_SIZE is still accepted as a legacy environment alias for the default budget, but new
builds should use MAX_QUEUE_BUDGET, build.py max_queue_budget=<n>, or CMake
SEDSNET_MAX_QUEUE_BUDGET only when they want to change the packaged default.
v4 removes compile-time user schema generation. build.rs no longer turns
telemetry_config.json into application-specific Rust enum variants or binding constants.
Default builds start with only built-in internal entries:
- telemetry error endpoint/type
- reliable-control packet types
- discovery endpoint/types
- time-sync endpoint/types when
timesyncis enabled
Applications add user endpoints and data types at runtime:
- Rust registration APIs in
config - C ABI registration APIs
- Python registration APIs
- JSON seeding through env, path, or bytes
- discovery schema sync from peers
Runtime JSON seeding options:
SEDSNET_STATIC_SCHEMA_PATH=/path/to/telemetry_config.jsonSEDSNET_STATIC_IPC_SCHEMA_PATH=/path/to/ipc_config.json- Rust
register_schema_json_path(...)/register_schema_json_bytes(...) - C
seds_schema_register_json_file(...)/seds_schema_register_json_bytes(...) - Python
register_schema_json_file(...)/register_schema_json_bytes(...)
Embedded builds include telemetry_config.json bytes only when an application provides that file
locally before building, then parse those bytes at runtime. The default crate build does not require
or include application JSON.
CMakeLists.txt (source) invokes build.py (source) and exposes variables for embedded builds.
Common CMake variables:
-
SEDSNET_EMBEDDED_BUILD(ON/OFF) -
SEDSNET_FORCE_RELEASE(ON/OFF, forces Cargo release profile even under a Debug parent build) -
SEDSNET_TARGET(Rust target triple) SEDSNET_DEVICE_IDENTIFIERSEDSNET_MAX_STACK_PAYLOAD-
SEDSNET_ENABLE_C_WRAPPER(ON/OFF, buildssedsnet::c_wrapper) -
SEDSNET_ENABLE_CPP_WRAPPER(ON/OFF, exposessedsnet::cpp_wrapper) -
SEDSNET_ENABLE_CRYPTOGRAPHY(ON/OFF, enablescryptographyand definesSEDS_ENABLE_CRYPTOGRAPHY) -
SEDSNET_ENV_<KEY>for any config env var
After add_subdirectory, link the target:
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE sedsnet::sedsnet)
Python bindings are built with maturin.
Options:
-
./build.py python(develop build) -
./build.py maturin-build(wheel) -
./build.py maturin-install(build + install)
If you use maturin develop directly, ensure you are in the correct virtualenv.
build.rs (source) is intentionally minimal in v4. It tracks build environment keys and whether optional embedded JSON bytes are available. It does not generate user schema constants.
Use runtime JSON seeding for schema paths instead of build-script schema overrides.
Bare-metal builds expect the following symbols to be provided by the host environment:
void *telemetryMalloc(size_t)void telemetryFree(void *)void telemetry_lock(void)void telemetry_unlock(void)void seds_error_msg(const char *, size_t)void telemetry_panic_hook(const char *, size_t)
See Usage-C-Cpp for an example stub implementation.