How to Integrate a New Module into the Reference Integration#
This guide explains how to add a new S-CORE module to the
reference_integration repository,
using scrample as a concrete example.
Scrample is a minimal “Hello World” logging application with both a C++ and a Rust implementation,
demonstrating mw::log integration across both languages.
Background: Why known_good.json?#
Each S-CORE module lives in its own Git repository and evolves independently. The reference integration continuously validates that a specific combination of module versions builds and tests successfully together – the so-called known-good state.
Keeping this state in a dedicated JSON file instead of directly in Bazel’s
MODULE.bazel serves several purposes:
Single source of truth. All version pins, repository URLs, and integration metadata (test exclusions, language info, Bazel patches) are in one place and machine-readable. Tooling such as CI pipelines, workspace generators, and the Bazel module generator all consume the same data.
Separation of concerns.
known_good.jsonis the what (which commit of which module), while the generated.MODULE.bazelfile is the how (the Bazel-specific syntax). Keeping them separate avoids manual errors in Bazel syntax and keeps the intent readable without Bazel knowledge.Tooling support. Because the version data is structured JSON, it can be consumed by additional scripts:
scripts/known_good/override_known_good_repo.py– pins individual modules to a different commit (e.g. for testing a PR) without touching the canonical file.scripts/known_good/known_good_to_workspace_metadata.py– generates the workspace manager file (.gita-workspace.csv) used to clone all module repositories locally.scripts/known_good/update_module_from_known_good.py– regenerates the BazelMODULE.bazelfiles.
Reproducibility. Every entry is pinned to a full SHA-1 commit hash, making the integrated state fully reproducible regardless of branch tip movements.
Overview#
There are two files that together define which modules are integrated:
``known_good.json`` – the single source of truth for all module versions (Git hashes, repository URLs, and metadata such as test configuration). This file is edited manually.
``bazel_common/score_modules_<category>.MODULE.bazel`` – generated from
known_good.jsonby a script. Do not edit this file manually.
The general workflow is:
Add the new module entry to
known_good.json.Run the generation script to update the
.MODULE.bazelfile.Optionally add a standalone showcase so the module appears in the S-CORE CLI.
Step 1 – Add the module to known_good.json#
Open known_good.json and add your module under the appropriate category.
There are currently two categories:
target_sw– modules that are part of the target software stack (deployed on the target platform, e.g. C++ / Rust runtime components).tooling– build and development tooling modules.
Scrample is a target_sw module, so its entry goes under that key.
The hash is the full SHA-1 commit of the version to integrate – in this case
the head commit of PR #31:
"score_scrample": {
"repo": "https://github.com/eclipse-score/scrample.git",
"hash": "32abf22969081a7c4a97733cf6d1b88b9e0c9d55",
"metadata": {
"code_root_path": "//src_rust/...",
"langs": ["cpp", "rust"]
}
}
Note
code_root_path points to the Bazel target pattern used for test
discovery. For scrample the Rust sources live under src_rust/, so
that is specified explicitly instead of the default //score/....
Metadata fields explained#
Field |
Required |
Description |
|---|---|---|
|
yes |
HTTPS URL to the Git repository (ending in |
|
yes |
Full SHA-1 commit hash of the version to integrate. |
|
no |
List of Bazel label paths to |
|
no |
Bazel target pattern for the module’s source root.
Defaults to |
|
no |
Languages present in the module: |
|
no |
Additional flag values passed to test runs. |
|
no |
Bazel target patterns excluded from CI test runs (e.g. known-failing or platform-specific tests). |
|
no |
Rust coverage profile name. Defaults to |
Step 2 – Regenerate the .MODULE.bazel file#
After editing known_good.json, run the generation script:
python3 scripts/known_good/update_module_from_known_good.py --override-type git
This regenerates bazel_common/score_modules_target_sw.MODULE.bazel
with the correct bazel_dep and git_override blocks for every module
listed in known_good.json. For scrample the result looks like:
bazel_dep(name = "score_scrample")
git_override(
module_name = "score_scrample",
commit = "32abf22969081a7c4a97733cf6d1b88b9e0c9d55",
remote = "https://github.com/eclipse-score/scrample.git",
)
Alternatively, use the VS Code task:
Terminal -> Run Task… -> “Switch Bazel modules to git_overrides”
Note
For local cross-module development, use --override-type local_path
so Bazel picks up a local checkout instead of downloading from Git.
See the repository README for the full workspace setup procedure.
Step 3 – Add a standalone showcase (optional)#
If the module provides runnable example binaries, expose them to the
S-CORE CLI by adding files under showcases/standalone/.
``showcases/standalone/scrample.score.json`` – describes the examples shown in the interactive CLI menu. Scrample ships both a C++ and a Rust binary, so both are listed as separate entries:
[
{
"name": "Scrample C++ Hello World",
"description": "Hello World logging example using score::mw::log in C++",
"apps": [
{
"path": "/showcases/bin/scrample_cpp",
"args": [],
"env": {}
}
]
},
{
"name": "Scrample Rust Hello World",
"description": "Hello World logging example using score_log in Rust",
"apps": [
{
"path": "/showcases/bin/scrample_rust",
"args": [],
"env": {}
}
]
}
]
``showcases/standalone/BUILD`` – add a score_pkg_bundle entry that
bundles both binaries and the JSON config file:
score_pkg_bundle(
name = "scrample",
bins = [
"@score_scrample//src_cpp:scrample_cpp",
"@score_scrample//src_rust:scrample_rust",
],
config_data = ["//showcases/standalone:scrample.score.json"],
package_dir = "standalone",
)
``showcases/BUILD`` – reference the new _pkg_files target in the
top-level showcases bundle so it ends up in every image:
score_pkg_bundle(
name = "showcases",
bins = ["//showcases/cli"],
other_package_files = [
"//showcases/standalone:comm_pkg_files",
"//showcases/standalone:kyron_pkg_files",
"//showcases/standalone:scrample_pkg_files", # added
"//showcases/orchestration_persistency:orch_per_pkg_files",
"//showcases/simple_lifecycle:simple_lifecycle_pkg_files",
],
package_dir = "showcases",
)
The CLI auto-detects all *.score.json files at runtime, so no further
registration is needed.
Step 4 – Verify the integration#
Run a Bazel build for the new module to confirm the integration is working:
bazel build @score_scrample//src_cpp:scrample_cpp @score_scrample//src_rust:scrample_rust
Optional – Add Bazel patches#
If the module’s upstream BUILD files need adjustments (e.g. to expose
internal targets for integration testing), add patch files under
patches/<module_name>/ and reference them in the bazel_patches list
in known_good.json.
Patches must be in unified diff format and are applied with patch -p1:
git diff HEAD > patches/scrample/001-fix-visibility.patch
Add a BUILD file in patches/scrample/ that exports the patch files:
# patches/scrample/BUILD
exports_files(glob(["*.patch"]))
Then reference them in known_good.json:
"score_scrample": {
"repo": "https://github.com/eclipse-score/scrample.git",
"hash": "32abf22969081a7c4a97733cf6d1b88b9e0c9d55",
"bazel_patches": [
"//patches/scrample:001-fix-visibility.patch"
],
"metadata": {
"code_root_path": "//src_rust/...",
"langs": ["cpp", "rust"]
}
}
Testing the integration end-to-end with score_starter#
Once the module is integrated and the showcase configured, the full
end-to-end test is done via the interactive launcher score_starter
included in the repository root.
Start the launcher from the repository root:
./score_starter
A text menu appears listing all available image targets:
Use up/down arrows to navigate, Enter to run, q to quit Run QNX x86_64 QEMU > Run Linux x86_64 Docker Run Elektrobit corbos Linux for Safety Applications aarch64 QEMU Run Autosd x86_64 QEMU Exit
Select the target image with the arrow keys and press
Enter. For a quick local check, choose “Run Linux x86_64 Docker”. Bazel will build the full image (first run may take several minutes) and launch a Docker container with the S-CORE CLI.Note
The Linux image requires Docker to be running on the host. For QNX or AutoSD, additional toolchain licenses and QEMU networking setup are required – see the respective README files under
images/andrunners/.The S-CORE CLI starts automatically inside the container. It scans all
*.score.jsonfiles and presents a multi-select menu of all available examples. Both scrample entries appear automatically:Select examples to run: [ ] Communication Sender Receiver Example [ ] Kyron basic example [ ] Kyron select example [ ] Kyron safety task example [ ] Scrample C++ Hello World <- scrample entries [ ] Scrample Rust Hello World <- scrample entries [ ] ...
Select the example with
Space, confirm withEnter. The CLI launches the selected binary and streams its output to the terminal. For scrample the expected output is:2026/05/22 12:00:00.0000000 00000000 000 ECU1 SCRM scra log info verbose 1 Hello from SCRAMPLE!