Describes the different layers of the Ditto Rust SDK.
Ditto's core codebase is written in Rust.
Currently, however, Rust does not have a stable ABI suitable for directly linking.
Therefore the Rust SDK, like the other Ditto SDKs, is exposed through an external interface that uses the C ABI calling conventions.
This core library is compiled as a both a static and dynamic library for a variety of architectures.
The dittolive-ditto-sys
crate contains Rust bindings to this C ABI library.
The build.rs
script will also attempt to identify the proper library binary for the host environment, download it from Ditto, and link to it.
The Rust SDK includes this -sys
crate as a dependency and then exposes an idiomatic Rust interface on top of this library, along with documentation and example apps.
The following outlines the general process of getting started with a new App based on the Ditto Rust SDK. Rust currently does not support a stable ABI. To work around this, the Ditto Rust SDK is distributed in two parts: an ergonomic, open-source crate and a closed-source pre-compiled library. It is essential to have the correct library for both your development system and ultimate production target.
There are also some key terms you will need to know, especially for cross-compiling the RustSDK.
x86_64-apple-darwin
) for example.arm-unknown-linux-gnueabihf
.The easiest way to get started with the Ditto Rust SDK is to use a pre-built Ditto library for your target architecture, where available.
nightly
tool chain for your current development machine using [rustup]https://rustup.rscargo new
Cargo.toml
file. Add a dittolive-ditto
as a dependency. This is the crate for the Ditto Rust SDK.cargo build
. This will trigger linking against the Ditto SDK for the current host system. If Ditto is not present for the current host system, this step will report an error when run with --verbose
logging. If curl
is present on the host system and the binary component of the Ditto SDK is absent, the build.rs
script will attempt to download the appropriate library for the compilation target automatically. This step will also create a TARGET_DIR
target directory (ie. target/debug
) in the project root. This is a good location for putting the binary component of the Ditto SDK, especially if the development and production hosts are different.pkg_config
may not automatically find the correct library for your target platform. In this event the Ditto library should be downloaded manually. Manually prefetching this library may also be desirable for offline CI pipelines and other situations where network access is not desired.https://software.ditto.live/rust/Ditto/<version>/<target-tripple>/<profile>/<library-name>
For example, on an x86_64 MacOS developer machine, one would use https://software.ditto.live/rust/Ditto/1.0.3-alpha1/x86_64-apple-darwin/release/libdittoffi.dylib
.DITTOFFI_SEARCH_PATH
may be used to manually set a directory to be used to find the binary component of the Ditto SDK. This is especially helpful when cross-compiling for different target architectures.cargo run
executes successfully and doesn't throw a linker error.libdbus
for Linux Bluetooth Transport and various MacOS Frameworks (ie. CoreFoundation, Security). The cargo
documentation provides guidance of various ways to provide these libraries to each platforms linker.If you have access to a copy of the full Ditto source code, you can compile the binary component of the Rust SDK, libdittoffi
yourself. The compilation host machine will need 4GB of RAM (or swap file) for linking purposes. If your target machine doesn't have this, you'll need to cross-compile (see section below).
CC
, ld
) for both the host and target system. If you are compiling on Mac OS for Linux, this will require more set up (described in a following section).
bash
export DITTO_TARGET=x86_64-unknown-linux-gnu
libdittoffi
for your target platform. This can take a while.
bash
(cd ffi && cargo build --release --target $DITTO_TARGET)
libdittoffi.a
and libdittoffi.so
in $DITTO_ROOT/target/$DITTO_TARGET/release/
. This path is known as your TARGET_DIR
and is configured by a file .cargo/config.toml
in DITTO_ROOT. Each target and profile (release, debug) will get its own sub-directory. Note that on Windows and Mac OS, the library file extensions will be different (.dll
and .dylib
, respectively).libdittoffi.so
into a cannonical search location for the target's linker to find. When compiling on the execution device, we recommend a symlink to /usr/local/lib
or /opt/ditto/lib
. This will make it easy for any apps outside of DITTO_ROOT to find libdittoffi.so
.
bash
sudo ln -sf "$DITTO_ROOT/target/$DITTO_TARGET/release/libdittoffi.so" /usr/local/bin
bash
export DITTOFFI_SEARCH_PATH="$DITTO_ROOT/target/$DITTO_TARGET/release"
bash
cargo new myapp
Cargo.toml
[dependencies]
dittolive-ditto.path = "$DITTO_ROOT/rust"
dittolive-ditto
(the Rust SDK) which in turn will build dittolive-ditto-sys
which links to libdittoffi.so
or libdittoffi.a
.
bash
cargo build
libdittoffi.a
you can set the LIBDITTO_STATIC=1
env var. However, this may result in missing symbol errors on some platforms where shared system libraries are otherwise linked in by default. For example, on linux you may see errors about missing libdbus
symbols and on Mac OS Darwin, missing system framework symbols, because these symbols are only available as shared libraries. Your app will need to be configured to tell the linker how to source these symbols.
bash
LIBDITTO_STATIC=1 cargo build
bash
cargo build --release --target $DITTO_TARGET
libdittoffi.so
and any other dynamically linked libraries.
bash
$APP_ROOT/target/$DITTO_TARGET/release/myapp
The build.rs
script for dittolive-ditto-sys makes a best effort attempt to locate, and if absent download, libdittoffi
in spite of each target OS having distinct linkers and conventions for managing shared libraries.
The absolute location of these files depends on whether the SDK is built from source or downloaded from crates.io as a dependency.
The search order is as follows:
DITTOFFI_SEARCH_PATH
env var is set to a valid directory, use this.
This takes priority over all other methods.target/$DITTO_TARGET/{debug,release}
). This is automatic for Cargo.deps
folder for the CARGOBUILDTARGET (ie. target/$DITTO_TARGET/{debug,release}/deps
). This is automatic for Cargo.cargo
./usr
, /lib
, /usr/local/lib
, /opt
.pkg_config
. Note that Raspberry Pi OS does not ship with pkg_config
.vcpkg
.The end result of this search is to ensure that two key arguments are passed to the target linker when building your app:
* -ldittoffi
- Your app should be linked against the ditto library
* -L DITTOFFI_SEARCH_PATH
- The directory where the ditto library for the target system can be found
You can see this process by building with cargo build -vv
.
If desired, you can explicitly provide these two arguments using cargo rustc
to build your app, or otherwise configuring your apps build system to provide these values when linking.
We recommend explicitly specifying the search path for the ditto library, especially when cross-compiling, to ensure the correct DITTO_TARGET architecture is used.
Many IOT devices make poor compilation hosts for Rust, and thus it is better to cross-compile on a developer machine with more resources and then execute on the target IOT device.
scp
, sftp
, or rsync
..devcontainer/devontainer.json
's build.Dockerfile
key to point to the docker image for your DITTO_TARGET. In this case Dockerfile.armv-unknown-linux-gnueabihf
./workspaces/ditto
, which will be our effective DITTO_ROOT going forward.bash
(cd ffi && cargo build --release)
bash
scp $DITTO_ROOT/target/$DITTO_TARGET/release/libdittoffi.so pi@raspberrypi:/home/pi
bash
sudo ln -sf /home/pi/libdittoffi.so /usr/local/lib/libdittoffi.so
bash
ldd ./myapp
This should verify the target devices linker can resolve all the shared libraries (including libdittoffi.so) on the target deviceThe following env vars are commonly used to configure the Ditto SDK.
RUST_SDK_LOG_LEVEL
- Sets the log level of the Ditto libraries internal logger. Values are error, warn, info, debug, and verbose. Default is "info".DITTOFFI_SEARCH_PATH
- Explicitly define where to look for libdittoffi
for your platform.DITTO_DB_PATH
- The absolute path where Ditto should store local copies of documents and attachments. This can also be provided programatically.The following are common patterns used to configure test and example apps
DITTO_LICENSE
- EnvVar containing a valid Ditto license token.DITTO_APP_NAME
- The full name of your app. Typically defined in reverse DNS format (ie. "live.ditto.carsapp").DITTO_SITE_ID
- A 64 bit unique identifier of this specific instance of your app. Often associated with a Security subject or Identity.DITTO_BINDIP
- The IP and/or Port (ie. 0.0.0.0:8080) where Ditto should listen for TCP or WebSocket Transport traffic.