BSP and Application Development¶
This flow covers setting up an edge build environment, choosing a starting point for your firmware, and integrating your own application into the Yocto image.
Involves: Edge, PyToloMEO, Embedded Manager
Development environment¶
ToloMEO uses kas to manage Yocto builds. The recommended setup mirrors our own: a devcontainer or a kas container so that build dependencies are fully reproducible without polluting the host system.
The meta-tolomeo repository ships a devcontainer configuration that includes kas, all required Yocto host tools, and helpers for signing and OTA package generation. Clone it and open it in VS Code or any devcontainer-compatible editor:
git clone git@gitlab.com:DAVEEmbeddedSystems/public/tolomeo-public-projects/edge/tolomeo-edge/meta-tolomeo.git
cd meta-tolomeo
Alternatively, any machine with kas installed (kas getting-started) can run builds directly through kas without a container container:
Refer to the meta-tolomeo development environment guide for the full setup instructions, including sstate cache configuration to speed up builds.
Choosing a starting point¶
There are two approaches depending on how much of the meta-tolomeo layer you need to modify.
Option A: Clone and extend meta-tolomeo¶
Clone the meta-tolomeo repository and add your recipes directly into meta-tolomeo-app.
This is the fastest path to get something running but might get harder to maintain in the
long run given that ToloMEO releases security updates every odd month.
git clone git@gitlab.com:DAVEEmbeddedSystems/public/tolomeo-public-projects/edge/tolomeo-edge/meta-tolomeo.git
Add your recipes under meta-tolomeo-app/recipes-<language>/<app-name>/ following the
patterns described below. We recommend keeping your application source code in its own
separate repository and referencing it from the recipe via SRC_URI, rather than
embedding sources inside the layer.
Option B: Own meta-layer¶
Create a separate Yocto layer for your application and bring meta-tolomeo in as a dependency through kas. This is the cleanest long-term approach: your code lives in its own repository, meta-tolomeo updates arrive without merge conflicts, and your CI pipeline stays independent.
If you are new to Yocto, start with Bootlin's
simplest-yocto-setup. It is a small,
working, real-world example of a Yocto product layer built around the same kas workflow.
Its meta-kiss layer and .config.yaml are the clearest available illustration of what
you need to create -- read through both before going further.
A Yocto layer is just a directory with a specific layout. Create it manually in a new repository:
meta-myapp/
├── conf/
│ └── layer.conf
└── recipes-myapp/
└── my-app/
├── my-app.bb
└── my-app.service
The conf/layer.conf declares the layer to BitBake. Model it directly on
meta-kiss/conf/layer.conf,
adjusting the collection name and dependencies:
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "meta-myapp"
BBFILE_PATTERN_meta-myapp = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-myapp = "9"
LAYERDEPENDS_meta-myapp = "core meta-tolomeo-distro"
LAYERSERIES_COMPAT_meta-myapp = "scarthgap"
Create a kas configuration file at the root:
---
header:
version: 14
includes:
- sources/meta-tolomeo/kas/common.yml
repos:
meta-myapp:
layers:
.:
meta-tolomeo:
url: git@gitlab.com:DAVEEmbeddedSystems/public/tolomeo-public-projects/edge/tolomeo-edge/meta-tolomeo.git
branch: scarthgap
tag: v1.2.1+26.03
path: sources/meta-tolomeo
layers:
meta-tolomeo-app:
meta-tolomeo-bsp:
meta-tolomeo-distro:
kas pulls in all layers declared in the included meta-tolomeo configuration inside sources/ and adds your
layer on top. No manual sourcing of oe-init-build-env is needed. For the full kas configuration reference see the
kas documentation.
Writing the recipe¶
Regardless of which starting point you chose, recipes follow the same structure and
conventions. Place your recipe in a recipes-<language>/<app-name>/ directory inside
your layer -- meta-tolomeo-app for Option A, meta-myapp for Option B:
For a full reference on recipe syntax see the Yocto Project recipe writing guide.
Python application¶
The tlm-services recipe in meta-tolomeo-app/recipes-python/tlm-services/ is the
canonical example of a Python application packaged with systemd integration. It uses the
python_hatchling build backend and ships multiple subpackages, each with its own systemd
service unit.
A recipe for a single Python application with a systemd service follows this pattern:
SUMMARY = "My application"
DESCRIPTION = "Short description of what my-app does."
inherit python_hatchling systemd
SRC_URI = "git://git@gitlab.com/myorg/my-app.git;protocol=ssh;branch=main \
file://my-app.service \
"
SRCREV = "abc123..."
S = "${WORKDIR}/git"
SYSTEMD_SERVICE:${PN} = "my-app.service"
FILES:${PN} += "${systemd_system_unitdir}/my-app.service"
RDEPENDS:${PN} = "python3-py-tolomeo"
The my-app.service file lives next to the .bb file and is a standard systemd unit.
BitBake's systemd class installs and enables it automatically.
If your application needs writable storage on an otherwise read-only rootfs, declare an overlayfs mount for it:
inherit overlayfs
OVERLAYFS_MOUNT_POINT[data] = "/data/overlay-my-app"
OVERLAYFS_WRITABLE_PATHS[data] = "/var/lib/my-app"
Pre-compiled binary¶
When distributing a pre-built binary for multiple architectures, place one binary per target architecture next to the recipe and select the correct one at install time:
SUMMARY = "My pre-compiled agent"
inherit systemd
SRC_URI = "file://my-agent-${PV}_x86_64 \
file://my-agent-${PV}_arm64 \
file://my-agent.service \
"
do_install() {
install -d ${D}${bindir}
case "${TARGET_ARCH}" in
x86_64)
install -m 0755 ${WORKDIR}/my-agent-${PV}_x86_64 ${D}${bindir}/my-agent
;;
aarch64)
install -m 0755 ${WORKDIR}/my-agent-${PV}_arm64 ${D}${bindir}/my-agent
;;
esac
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${WORKDIR}/my-agent.service ${D}${systemd_system_unitdir}/my-agent.service
}
SYSTEMD_SERVICE:${PN} = "my-agent.service"
Adding the application to the image¶
Applications are included in the image through package groups. Create a package group
recipe in a recipes-core/packagegroups/ directory inside your layer:
Option A -- extend TOLOMEO_IMAGE_INSTALL in
meta-tolomeo-app/recipes-core/images/include/tolomeo-image-common.inc:
Option B -- add a local_conf_header entry to your kas configuration so the package
is appended without touching meta-tolomeo files:
For quick iteration during development you can also append the package directly without a package group:
Building¶
Build the full image with kas, passing your kas configuration file:
# Option A
kas build kas/tolomeo-qemux86-64_tolomeo-devel_image-devel.yml
# Option B
kas build my-build.yml
To iterate on a single recipe without rebuilding the entire image, open a kas shell and invoke bitbake directly:
To rebuild after modifying the recipe or its source:
Once the recipe builds cleanly, rebuild the full image to verify it integrates correctly before moving to the OTA Release flow.
For production images, follow the Hardening and Secure Boot flow to
generate signing keys and build with the hardened tolomeo-prod distribution. To add
telemetry services to the image, see IoT and Telemetry.