Building source code#
SCRAMPLE provides two minimal “Hello World” applications — one in C++ and one in Rust — that
both use the S-CORE mw::log logging library.
C++ Application (src_cpp/BUILD)#
Let’s begin with the C++ application, starting with the bazel src_cpp/BUILD file.
1cc_binary(
2 name = "scrample_cpp",
3 srcs = ["main.cpp"],
4 data = ["//config:logging.json"],
5 visibility = ["//visibility:public"],
6 deps = [
7 "@score_logging//score/mw/log",
8 ],
9)
The cc_binary produces a C++ binary. The attributes of cc_binary are documented in detail in the Bazel documentation. The scrample_cpp binary depends on:
the score_logging module (
mw::loglogging library)
The logging configuration is provided via //config:logging.json, which is made available
at runtime through Bazel’s runfiles mechanism.
Rust Application (src_rust/BUILD)#
The Rust application is defined in src_rust/BUILD:
1load("@rules_rust//rust:defs.bzl", "rust_binary")
2
3RUSTC_FLAGS = select({
4 "@platforms//os:qnx": [
5 "-Clink-arg=-lc++",
6 "-Clink-arg=-lm",
7 ],
8 "//conditions:default": [
9 "-Clink-arg=-lstdc++",
10 "-Clink-arg=-lm",
11 "-Clink-arg=-lc",
12 ],
13})
14
15rust_binary(
16 name = "scrample_rust",
17 srcs = ["main.rs"],
18 data = ["//config:logging.json"],
19 edition = "2021",
20 rustc_flags = RUSTC_FLAGS,
21 visibility = ["//visibility:public"],
22 deps = [
23 "@score_baselibs_rust//src/log/score_log",
24 "@score_logging//score/mw/log/rust/score_log_bridge",
25 ],
26)
The Rust binary uses:
score_logfrom the score_baselibs_rust module as a Rust logging facadescore_log_bridgefrom the score_logging module to bridge Rust logging to themw::logC++ backend
The RUSTC_FLAGS select expression ensures correct C++ standard library linking on both Linux and QNX targets.
Now that the targets are defined, we can build the binaries.
Before continuing, it is helpful to introduce two fundamental Bazel concepts: toolchains and platforms.
A complete explanation is beyond the scope of this small tutorial, but the following brief overview is sufficient:
A Bazel toolchain specifies which compiler and linker are used (e.g., GCC, Ferrocene).
A Bazel platform defines the target CPU architecture and OS (e.g., x86_64 Linux or x86_64 QNX).
SCRAMPLE uses the same toolchain setup as the other S-CORE modules, provided by score_bazel_cpp_toolchains. To add these toolchains to our module, we extend the MODULE.bazel file with the corresponding configuration:
1# C++ and QNX toolchains (same setup as score_baselibs / score_baselibs_rust)
2bazel_dep(name = "score_bazel_cpp_toolchains", version = "0.5.1", dev_dependency = True)
3
4gcc = use_extension("@score_bazel_cpp_toolchains//extensions:gcc.bzl", "gcc", dev_dependency = True)
5gcc.toolchain(
6 name = "score_gcc_x86_64_toolchain",
7 target_cpu = "x86_64",
8 target_os = "linux",
9 use_default_package = True,
10 version = "12.2.0",
11)
12gcc.toolchain(
13 name = "score_qcc_x86_64_toolchain",
14 sdp_version = "8.0.0",
15 target_cpu = "x86_64",
16 target_os = "qnx",
17 use_default_package = True,
18 version = "12.2.0",
19)
20use_repo(
21 gcc,
22 "score_gcc_x86_64_toolchain",
23 "score_qcc_x86_64_toolchain",
24)
25
26# Ferrocene Rust toolchains (QNX cross-compilation support)
27bazel_dep(name = "score_toolchains_rust", version = "0.9.1", dev_dependency = True)
The score_bazel_cpp_toolchains module provides GCC 12.2.0 for both Linux host builds and
QNX SDP 8.0.0 cross-compilation. The score_toolchains_rust module provides pre-built
Ferrocene toolchains for Rust.
Tip
CI/CD pipeline uses its own QNX license when building the code with QNX. If you want to build the source code with the QNX compiler locally, you must acquire a QNX 8.x “free for non commercial use” license and install QNX 8.x SDP as described in the QNX & QEMU set-up tutorial.
Since our applications depend on the logging and base libraries (as defined in the src_cpp/BUILD and src_rust/BUILD files), we also need to add the dependencies to these modules into the MODULE.bazel file:
1bazel_dep(name = "score_baselibs", version = "0.2.7")
2bazel_dep(name = "score_baselibs_rust", version = "0.1.2")
3bazel_dep(name = "score_logging", version = "0.2.1")
1bazel_dep(name = "platforms", version = "1.0.0")
2bazel_dep(name = "score_bazel_platforms", version = "0.1.2")
Bazel modules don’t inherit transitive dependencies automatically. This means that you must always list all required module dependencies explicitly in your MODULE.bazel file.
To actually use the registered toolchains, we also need to configure them in the .bazelrc file:
1common --extra_toolchains=@score_gcc_x86_64_toolchain//:x86_64-linux-gcc_12.2.0
2common --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_unknown_linux_gnu
3
4common --@score_baselibs//score/memory/shared/flags:use_typedshmd=False
5common --@score_baselibs//score/mw/log/flags:KRemote_Logging=False
6
7build:_common --@score_baselibs//score/json:base_library=nlohmann
8build:_common --cxxopt=-Wno-error=mismatched-new-delete
9build:_common --cxxopt=-Wno-error=deprecated-declarations
10
11build:x86_64-qnx --config=_common
12build:x86_64-qnx --noexperimental_merged_skyframe_analysis_execution
13build:x86_64-qnx --incompatible_enable_cc_toolchain_resolution
14build:x86_64-qnx --incompatible_strict_action_env
15build:x86_64-qnx --platforms=@score_bazel_platforms//:x86_64-qnx-sdp_8.0.0-posix
16build:x86_64-qnx --extra_toolchains=@score_qcc_x86_64_toolchain//:x86_64-qnx-sdp_8.0.0
17build:x86_64-qnx --extra_toolchains=@score_toolchains_rust//toolchains/ferrocene:ferrocene_x86_64_pc_nto_qnx800
Lines 1-2 (highlighted) register the GCC and Ferrocene toolchains for all builds.
The Ferrocene Linux toolchain is registered as a common toolchain so that proc macro crates
(compiled on the host) and QNX target crates share the same compiler metadata format,
which is required for cross-compilation compatibility.
Lines 4-5 set feature flags required by score_baselibs that are not applicable in
this demo (proprietary shared memory driver and remote logging backend).
These options must be set globally because Bazel builds all dependent modules within
the context of your module’s configuration.
Lines 11-17 (highlighted) configure Bazel to target the QNX SDP 8.0.0 platform and select the appropriate QNX and Ferrocene toolchains.
Finally, we can compile the code. Always use an explicit build configuration:
Host build (Linux x86_64):
1bazel build --config=host //src_cpp:scrample_cpp
2bazel build --config=host //src_rust:scrample_rust
QNX cross-compilation:
1bazel build --config=x86_64-qnx //src_cpp:scrample_cpp
2bazel build --config=x86_64-qnx //src_rust:scrample_rust
After a successful host build, the binaries can be found in the build folder:
1bazel-bin/src_cpp/scrample_cpp
2bazel-bin/src_rust/scrample_rust
Both apps produce the same log output to the console:
2026/05/22 12:00:00.0000000 00000000 000 ECU1 SCRM scra log info verbose 1 Hello from SCRAMPLE!
Now it is time to run the binary in the reference QNX QEMU image.