Overview
The Isar build system layers a BitBake-style meta-recipe model on top of Debian's binary package model. When a target image is assembled, two parallel dependency chains resolve: the BitBake recipe level (which decides what gets compiled or fetched) and the Debian package level (which decides what is unpacked onto the final rootfs). For application code that already exists as a tested .deb artifact, integrating that file is a matter of teaching the Isar layer how to map a recipe name to a binary package name, and how to feed that binary into the image assembly.
This guide walks through a minimal working configuration based on the public prebuilt-deb reference for the Siemens IOT2050 Isar example. The pattern generalizes to any Isar-based image (Raspberry Pi, generic amd64, custom boards) and is the same path that gets followed for runtime payloads such as node-red, tcf-agent, or proprietary customer binaries.
Isar Build System Architecture
Isar (Intelligent System for Automated Rootfs assembly) is the Debian-flavored build system maintained by Siemens for the IOT2050. It runs inside kas and uses BitBake as its task scheduler. Conceptually it is the Debian analogue of the Yocto/OpenEmbedded stack: same task engine, different package format and a different set of base classes.
Two dependency planes are visible to every recipe:
-
BitBake recipe plane.
IMAGE_INSTALLis parsed by BitBake and triggers the build of any recipe that lists the requested identifier in itsPROVIDESlist. The recipe is responsible for producing one or more binary Debian packages as its output. -
Debian package plane. The actual rootfs is assembled by collecting the
.debfiles produced by the recipes.IMAGE_INSTALLis also forwarded (after the recipe name has been resolved to a package name) to the rootfs tool so that the right packages end up on the filesystem.
The split matters when a recipe generates more than one binary package, or when the recipe's own name does not match the package it produces. In that case the recipe must extend PROVIDES so that asking for the package identifier triggers the recipe build. Without that extension, BitBake will not know which recipe to schedule and the image build will either silently skip the package or fail at rootfs time with unable to locate package.
Prerequisites
- A working Isar build environment built from
kas-iot2050-example.yml(or an equivalentkasproject file) on a Linux build host with Docker or Podman. -
kas-container in
$PATH. - A valid
.debfile (architecture-correct, dependency-complete) that you have already installed and tested on a reference rootfs. fpm from Jordan Sissel is the recommended tool to assemble such files from self-compiled binaries because it lets you keep a pre-flight installable package that you can run, instrument, and validate before ever wiring it into a build. - Access to the image recipe in the
recipes-appdirectory of the Isar project, or a user-specific layer added tobblayers.conf.
.deb is the only reliable way to detect runtime dependency issues, missing shared libraries, or incorrect maintainer scripts. Isar's dpkg-prebuilt class will not rebuild or patch a foreign .deb; it only injects it into the package feed.Directory Layout
The reference layout used in the source thread puts the recipe alongside the .deb artifact inside the recipes-app/ tree. The example directory name is prebuilt-deb:
recipes-app/
prebuilt-deb/
prog_1.0.0_amd64.deb
prog_1.0.0.bb
The two-file layout keeps the binary and its recipe co-located. kas will pick up the .bb file automatically because the parent directory recipes-app is already declared in bblayers.conf by the upstream kas-iot2050-example.yml configuration.
The dpkg-prebuilt.bbclass Mechanism
Standard Isar recipe classes such as dpkg or debian expect to be pointed at a source tree from which the build derives the binary package. For a prebuilt .deb that is wasted work, and it is also unnecessary because the binary already exists.
dpkg-prebuilt.bbclass is a thin recipe class shipped with Isar that:
- Declares
DPKG_PREBUILT_PKGto point at the.debartifact inside the recipe directory. - Skips any compile, patch, or configure step because the binary is already final.
- Generates a single binary Debian package whose name matches the binary package inside the
.deb(not the recipe name). - Adds that binary package to Isar's package index so that
IMAGE_INSTALLresolution finds it.
The key behavior to remember is that the recipe name and the binary package name are independent. The recipe file can be named prog_1.0.0.bb while the package inside the .deb can be myapp. The class is designed to bridge that gap.
PROVIDES, RPROVIDES, and Package Name Resolution
BitBake uses PROVIDES to advertise identifiers a recipe can satisfy. By default, a recipe called prog_1.0.0.bb provides prog-1.0.0. If the binary .deb exposes a package called myapp, then:
-
IMAGE_INSTALL += "myapp"resolves to "build the recipe that providesmyapp". - Without an explicit
PROVIDESentry,myappis not on the provider list and the build will fail with a missing-provider error.
To close the gap, the recipe must extend its PROVIDES list to include the binary package name. The minimal extension looks like this:
PROVIDES += "myapp"
RPROVIDES:${PN} += "myapp"
The first line makes BitBake schedule this recipe when myapp is requested. The second line ensures that packages depending on myapp at the Debian level will see it as satisfied on the assembled rootfs. ${PN} resolves to the recipe name (prog-1.0.0) at parse time.
.deb produces multiple binary packages (e.g. myapp, myapp-dev, myapp-dbg), each one must appear in PROVIDES. Otherwise only the first Provides field of the control archive is exposed. Inspect the .deb with dpkg-deb -I prog_1.0.0_amd64.deb to enumerate them.Step-by-Step Integration
-
Stage the artifact and the recipe. Copy the tested
.deband the matching.bbfile intorecipes-app/prebuilt-deb/inside the Isar project. The recipe file should inheritdpkg-prebuiltand setDPKG_PREBUILT_PKGto the relative path of the.deb. -
Verify the binary package name. Run
dpkg-deb -f prog_1.0.0_amd64.deb Packageand note the value. This is the identifier you will need inPROVIDESand inIMAGE_INSTALL. -
Check declared dependencies. Run
dpkg-deb -f prog_1.0.0_amd64.deb Depends. Any dependency that is not already in the base image must be added toIMAGE_INSTALLexplicitly. -
Edit the recipe to extend
PROVIDES. For a single binary package namedmyapp:
Theinherit dpkg-prebuilt SRC_URI = "file://prog_1.0.0_amd64.deb" DPKG_PREBUILT_PKG = "${WORKDIR}/prog_1.0.0_amd64.deb" PROVIDES += "myapp" RPROVIDES:${PN} += "myapp" do_install[noexec] = "1"do_install[noexec]line is defensive: the prebuilt class already skips install, but it prevents a stray override from re-enabling it. -
Update the image recipe. In the
.bbfile that defines the target image (the file referenced by theimagetarget inkas-iot2050-example.yml), add the binary package toIMAGE_INSTALL. The upstream example removednode-redandtcf-agentfor the test; a clean integration is:IMAGE_INSTALL += "myapp" -
Trigger the build. From the project root, run the standard kas-container invocation:
This single command resolves layers, fetches sources, schedules the prebuilt recipe, and finally assembles the rootfs with the new package included../kas-container build kas-iot2050-example.yml
Building the .deb Artifact with fpm
For self-compiled application code, fpm is the path of least resistance. A typical build of a single binary, a systemd unit, and a configuration file looks like:
fpm -s dir -t deb \
-n myapp -v 1.0.0 \
--architecture amd64 \
--depends "libc6 (>= 2.31)" \
--depends "libssl3" \
--after-install postinst.sh \
--before-remove prerm.sh \
build/myapp=/usr/bin/myapp \
systemd/myapp.service=/etc/systemd/system/myapp.service \
conf/myapp.conf=/etc/myapp/myapp.conf
Three details are worth flagging:
-
Test first, integrate second. The reason
fpmis the right tool is that you cansudo dpkg -i myapp_1.0.0_amd64.debon any Debian host, run the program, exercise its maintainer scripts, and only after that success copy the artifact into the Isar tree. This is the workflow that eliminates the most common class of integration bugs. -
Pin the architecture.
--architecture amd64must match the IOT2050's target (typicallyamd64for the IOT2050-SDK,arm64for IOT2050 variants built on the arm64 base image). A mismatch causesdpkgto refuse the package at rootfs time with package architecture (arm64) does not match system (amd64). -
Declare runtime dependencies explicitly. Isar will not pull in transitive dependencies that you forgot to list.
--dependsentries becomeDepends:in the.debcontrol archive, and Isar resolves them through its own package index.
Verification
After ./kas-container build kas-iot2050-example.yml completes, validate the image with three independent checks.
-
Inspect the package index. In the build directory, locate the generated
Package.gzfile and grep for the new package:
Confirm thatzcat tmp/deploy/deb-*/Packages.gz | grep -A 5 "^Package: myapp"Package: myapp, the correctVersion, andArchitecture: amd64(orarm64) are present. -
Mount the rootfs and list the files. The image recipe will produce a tar or ext4 rootfs. Extract or mount it and confirm the binary landed at the expected path:
tar -tf tmp/deploy/images/iot2050/iot2050-image-iot2050.tar.gz | grep myapp -
Flash and run. Write the image to the IOT2050 (or boot it in QEMU with the
kas-iot2050machine definition) and verify thatdpkg -l myappshowsiistatus, that the systemd unit is enabled if applicable, and that the program starts cleanly.
Troubleshooting Matrix
| Symptom | Probable Cause | Fix |
|---|---|---|
Nothing PROVIDES 'myapp' |
Recipe does not extend PROVIDES with the binary package name |
Add PROVIDES += "myapp" and RPROVIDES:${PN} += "myapp" to the .bb
|
| Package built but not in rootfs |
IMAGE_INSTALL uses the recipe name instead of the binary package name |
Update IMAGE_INSTALL to use the package identifier from dpkg-deb -f
|
package architecture (X) does not match system (Y) |
--architecture mismatch when building with fpm |
Rebuild the .deb with the correct architecture flag |
dependency not satisfiable: libfoo |
Runtime Depends of the .deb not met by base image |
Add the missing package to IMAGE_INSTALL or to the base image recipe |
| Recipe re-runs every build with no source change | Missing SRC_URI checksum or do_fetch override still firing |
Set SRC_URI = "file://..." with a stable filename and inherit dpkg-prebuilt
|
| Multiple binary packages, only one visible | Only the first Package: field advertised via PROVIDES
|
List every package name in PROVIDES
|
fakeroot dpkg-buildpackage errors during recipe execution |
Wrong recipe class inherited; trying to rebuild a prebuilt | Switch to inherit dpkg-prebuilt and ensure no other dpkg or debian class is inherited |
Multi-Package and Complex Dependency Patterns
Real applications rarely ship as a single .deb. The same recipe pattern scales:
-
Library + app + debug split. Build three
.debfiles with fpm, name themmylib,myapp, andmyapp-dbg. List all three inPROVIDESand letIMAGE_INSTALLpick the runtime subset. -
Versioned upgrades. Bumping
PVin the recipe (prog_1.0.1.bb) is enough to trigger a rebuild of the image. If the new.debships a different package name, updatePROVIDESaccordingly; if only the upstream version changed, the file replacement is automatic. -
Per-board variants. For projects that target both the IOT2050 (amd64) and an arm64 variant, parameterize
DPKG_PREBUILT_PKGwith aMACHINE_ARCHconditional:
This lets one recipe drive both images from a singleDPKG_PREBUILT_PKG = "${WORKDIR}/prog_1.0.0_${MACHINE_ARCH}.deb"kasproject. -
Signed packages. For production builds, sign the
.debwithdpkg-sig --sign builderand configure Isar'sfeedmechanism to verify the signature. Thedpkg-prebuiltclass does not validate signatures, so the check must be added at the feed level.
Operational Checklist
Before declaring a prebuilt package integration complete, run through this list:
- Does
dpkg-deb -Ishow the expectedPackage,Version,Architecture, andDepends? - Is the recipe's
PROVIDESaligned with every binary package inside the.deb? - Is the package identifier in
IMAGE_INSTALLthe binary package name, not the recipe name? - Is
do_install[noexec]set to defend against accidental overrides? - Has the
.debbeen installed and tested on a reference host before integration? - Has the resulting image been flashed or emulated, with
dpkg -lconfirming installation?
.deb integrated via dpkg-prebuilt as a black box. The class does not run the upstream build, does not apply security patches, and does not regenerate the binary when the source changes. Patch management is your responsibility; Isar is the delivery vehicle, not the security boundary.FAQ
What recipe class handles a prebuilt .deb in Isar?
Use dpkg-prebuilt.bbclass. Inherit it with inherit dpkg-prebuilt and set DPKG_PREBUILT_PKG to the path of the .deb inside ${WORKDIR}. The class skips the compile/install pipeline and emits a single binary package whose name comes from the control archive inside the .deb.
Why does my prebuilt package show up in IMAGE_INSTALL resolution but not on the rootfs?
This usually means IMAGE_INSTALL lists the recipe name (for example prog-1.0.0) while the binary package inside the .deb is named differently (for example myapp). BitBake schedules the recipe because PROVIDES maps the recipe to the binary, but the rootfs assembler still needs the binary identifier. Replace the recipe name in IMAGE_INSTALL with the package name from dpkg-deb -f file.deb Package.
How do I integrate a multi-package .deb set built with fpm?
Build one .deb per component (runtime, devel, debug) and add every package name from dpkg-deb -f to PROVIDES in the recipe. Then list the runtime packages in IMAGE_INSTALL. The dpkg-prebuilt class can carry a single .deb; for multiple artifacts, use a wrapper recipe that stages each one with its own DPKG_PREBUILT_PKG or chain recipes through RDEPENDS.
Can I use a prebuilt .deb on both amd64 and arm64 IOT2050 images?
Yes. Parameterize DPKG_PREBUILT_PKG with ${MACHINE_ARCH} and ship one .deb per architecture in the recipe's SRC_URI. The upstream kas-iot2050 configuration exposes MACHINE variables that map cleanly to amd64 and arm64 targets.
How do I verify the integrated package on a running IOT2050?
After flashing, run dpkg -l <package-name> to confirm installation status, dpkg -L <package-name> to enumerate installed files, and any service-specific check such as systemctl status <unit>. If the package is missing, inspect tmp/deploy/deb-*/Packages.gz from the build to confirm it reached the package index.