A minimal publisher/subscriber example using the Eclipse S-CORE
middleware (score::mw::com). It demonstrates the full IPC lifecycle over shared memory (SHM):
- Publisher — offers a
MotorAngleservice, continuously sendsangle_degsamples at 20 Hz (sinusoidal 90° amplitude at 1 Hz). - Subscriber — discovers the service, subscribes to the
motor_angleevent, and prints each received sample via an event-driven receive handler (no polling). - TorqueSubscriber — subscribes to a
MotorTorqueservice and printstorque_nmsamples; intended as a companion to theexample_scorePubSubMATLAB External Mode example where Simulink publishesMotorTorque.
For a detailed walkthrough of the manual build process, prerequisites, and how the patching works, see README_advanced.md.
minimal_score_pubsub_cmake/
├── datatype.h / datatype.cpp # MotorAngle/MotorTorque structs + Interface/Proxy/Skeleton
├── publisher.cpp # Service skeleton: offers and sends MotorAngle samples
├── subscriber.cpp # Service proxy: finds, subscribes, receives MotorAngle samples
├── torque_subscriber.cpp # Service proxy: subscribes to MotorTorque (published by Simulink)
├── etc/
│ └── mw_com_config.json # Service instance manifest (SHM binding, event slots)
├── build/
│ └── score_mw_sysroot/ # Middleware sysroot (headers, libs, CMake config)
├── setup_score_sysroot.sh # Builds the middleware sysroot (auto-applies patches)
├── build_and_deploy.sh # Interactive build + deploy script (recommended entry point)
├── toolchain-arm64.cmake # ARM64 cross-compilation toolchain file
├── CMakeLists.txt # CMake build configuration
└── README.md
- Bazel 8.x
- C++17-capable compiler (GCC or Clang)
- Linux host (shared memory IPC)
For ARM64 cross-compilation (e.g. Raspberry Pi 5), you also need the aarch64-linux-gnu cross-toolchain.
See README_advanced.md for setup instructions.
Tested communication repo commit:
1e03b3110c120ae3f9aff07a366ba8c99cf267d3(2026-05-06 — Adding clang-tidy checks) If the upstream repo has been updated past this commit, the sysroot patches insetup_score_sysroot.shmay need updating. See the Troubleshooting section.
The recommended way to build (and optionally deploy to a remote target) is via the interactive script:
./build_and_deploy.shThe script will guide you through:
- Target architecture (
x86orarm) - Linking mode (
staticorshared) - Whether to (re)build the middleware sysroot, and which communication repo to use
- Whether to clean the Bazel cache before building
- Whether to deploy the binaries to a remote SSH target
# ARM static build, no deploy
./build_and_deploy.sh --arch=arm --link=static --deploy=no
# ARM static build, skip sysroot rebuild, deploy to Pi
./build_and_deploy.sh --arch=arm --link=static --skip-sysroot \
--deploy=yes --target=pi@192.168.1.10
# ARM shared build, deploy to Pi, fully non-interactive
./build_and_deploy.sh --arch=arm --link=shared --clean-cache=no \
--deploy=yes --target=pi@192.168.1.10 -yAll options:
| Option | Description |
|---|---|
--arch=x86|arm |
Target architecture |
--link=static|shared |
Linking mode |
--comm-repo=PATH |
Path to eclipse-score/communication repo |
--skip-sysroot |
Skip rebuilding the middleware sysroot |
--clean-cache=yes|no |
Clean Bazel cache before sysroot build |
--deploy=yes|no |
Deploy to remote target after build |
--target=USER@HOST |
SSH target (e.g. pi@192.168.1.10) |
--deploy-dir=PATH |
Remote deploy directory (default: ~/score_pubsub) |
-y, --yes |
Accept all defaults non-interactively |
-h, --help |
Show help and exit |
After building, open two terminals on the target device (or locally for x86):
Terminal 1 — Publisher:
cd ~/score_pubsub
./publisher etc/mw_com_config.json[Publisher] Service offered. Sending data...
[Publisher] Sent motor angle [deg]: 0
[Publisher] Sent motor angle [deg]: 27.5664
...
Terminal 2 — Subscriber:
cd ~/score_pubsub
./subscriber etc/mw_com_config.json[Subscriber] Service found. Connecting...
[Subscriber] Received motor angle [deg]: 0
[Subscriber] Received motor angle [deg]: 27.5664
...
Terminal 3 — Torque Subscriber (used with the example_scorePubSub MATLAB External Mode example):
cd ~/score_pubsub
./torque_subscriber etc/mw_com_config.json[TorqueSubscriber] Received motor torque [Nm]: 0.5
...
Stop any process with Ctrl+C.
| Concept | This example |
|---|---|
| Service interface | MotorAngleInterface<Trait> — declares the motor_angle_ event |
| Data type | MotorAngle — plain struct with float angle_deg |
| Publisher side | MotorAngleSkeleton::Create() → OfferService() → Allocate() → Send() |
| Subscriber side | MotorAngleProxy::FindService() → Create() → Subscribe() → SetReceiveHandler() |
| Torque subscriber | MotorTorqueProxy::FindService() → Create() → Subscribe() → SetReceiveHandler() |
| Torque data type | MotorTorque — plain struct with float torque_nm; published by Simulink in example_scorePubSub |
| Transport | Shared memory (SHM), configured in etc/mw_com_config.json |
| Config | instanceSpecifier: score/examples/MotorAngle, serviceId: 6432, eventId: 3 |
| Torque config | instanceSpecifier: score/examples/MotorTorque (see etc/mw_com_config.json) |
The patches applied by setup_score_sysroot.sh were tested against a specific commit.
If the upstream repo has moved past it, the build may fail with compile or Bazel errors.
First, pin to the tested commit and retry:
git -C ~/score/communication checkout 1e03b3110c120ae3f9aff07a366ba8c99cf267d3
./setup_score_sysroot.sh ~/score/communication --cpu=arm64If that succeeds, the issue is a newer upstream change. See README_advanced.md — Patch maintenance for how to update the patches for the new commit.
The platforms/ directory is missing from the communication repo. Run the sysroot script
once — it will copy it automatically from the bundled platforms/ in this repo:
./setup_score_sysroot.sh ~/score/communication --cpu=arm64The tracing_runtime.cpp patch is needed but was not applied. Delete the communication
repo's Bazel cache and re-run the sysroot script (it will patch and rebuild):
bazel -C ~/score/communication clean
./setup_score_sysroot.sh ~/score/communication --cpu=arm64The @score_baselibs//score/os/utils:path target is missing from the fat library. This is
fixed in setup_score_sysroot.sh — make sure you have the latest version of the script and
rebuild the sysroot.
A previous run left literal \n sequences in MODULE.bazel (shell quoting issue). Fix:
python3 - ~/score/communication/MODULE.bazel <<'EOF'
import sys
path = sys.argv[1]
with open(path) as f: src = f.read()
src = src.replace('\\n', '\n')
with open(path, 'w') as f: f.write(src)
print("Fixed")
EOFThen re-run the sysroot script.
- Ensure publisher and subscriber use the same
mw_com_config.json. - Both processes must run as the same user (shared memory permissions).
- On a remote target: verify the config was deployed to
etc/mw_com_config.jsonrelative to the working directory, and run from inside the deploy directory:cd ~/score_pubsub && ./publisher etc/mw_com_config.json
The libmw_com.so was not installed to a system library path. Either:
# Option A — install system-wide (requires sudo on target)
sudo cp libmw_com.so /usr/local/lib/
sudo ldconfig
# Option B — set LD_LIBRARY_PATH at runtime
LD_LIBRARY_PATH=~/score_pubsub ./publisher etc/mw_com_config.json