Lesson 4: Full Yocto Builds vs Development Builds
Understand why engineers don’t rebuild and flash an entire Linux system every time they modify a C++ application.
We’ll use your physical Qualcomm board and an IDS service as our running example.
4.1 Let’s start with a real engineering problem
Imagine your Qualcomm board is already running Linux.
The board has the following software installed:
Qualcomm Embedded Linux Board
│
├── Linux Kernel
│
├── Root Filesystem
│ ├── System Libraries
│ ├── Configuration Files
│ └── Linux Commands
│
├── LCM Service
│
└── IDS Service
├── ids-daemon
├── libids.so
└── ids-config.jsonYou discover a bug in ids-daemon.cpp.
void processEvent() {
// Old buggy implementation
}You fix it:
void processEvent() {
// Fixed implementation
}Now you want to test your change on the board.
There are two main approaches:
- Build a new Linux image containing your updated IDS application and flash it.
- Build only the updated application or package and deploy it to the existing Linux system.
Both approaches are useful, but for different purposes.
4.2 Approach 1: Full image build and flashing
Think of a full image as preparing an entire operating system installation.
Your Yocto image contains the selected Linux components, libraries, services, configuration files and applications.
What command builds a complete image?
On your Yocto build host:
bitbake <image-recipe-name>For example, with the generic Yocto image:
bitbake core-image-minimalYour Qualcomm project might instead use a custom image recipe such as product-image, but we must identify its actual name rather than assume one.
BitBake determines the necessary dependencies and builds an image containing the requested packages.
Important distinction: Building an image does not automatically mean recompiling everything from scratch. If previous build results are valid, BitBake reuses them.
What happens after the build?
The image and related artifacts are typically found under:
build/tmp/deploy/images/<machine>/There might be an ext4 image, UBI image, kernel or boot image, device trees, and vendor-specific flashing artifacts.
You then use the flashing procedure supported by your board.
For example:
Yocto output: rootfs.ext4
↓
Vendor flashing tool
↓
Board's eMMC partition
↓
Reboot
↓
Updated root filesystemThis is only an example. A raw NAND board may instead use a UBI artifact, and some Qualcomm platforms require multiple signed firmware components.
When do we prefer this?
A full image build and controlled image deployment are useful when:
- Updating the Linux kernel or boot components.
- Modifying base system libraries.
- Changing rootfs organization or system configuration.
- Testing a complete software release.
- Ensuring the delivered system contains the correct versions of all components.
A full-image update may not require overwriting every flash partition. A product’s updater might replace only a rootfs partition or an inactive A/B slot.
Mini recap
A full image represents a prepared Linux system. You build it to validate the complete combination of components, not just your modified application.
4.3 Approach 2: Build only IDS and deploy it
Now suppose the existing Linux system is fine.
Only ids-daemon.cpp has changed.
Why rebuild and flash an operating system when you only need to test one application?
Instead, you can build the IDS recipe separately.
On the Yocto build host:
bitbake ids-daemonThis builds the IDS recipe and whatever prerequisite work is necessary.
It does not automatically rebuild the final root filesystem image or flash the board.
What files might the build produce?
Depending on the recipe, you could have:
ids-daemon
libids.so.1
ids-daemon.service
ids-config.jsonYocto can also produce an installable package:
ids-daemon_1.1_arm.ipkThis filename is illustrative; real package names include the target package architecture and version information.
Common package formats include:
Your project chooses its package format through Yocto configuration.
Binary vs package
A binary might be only one executable file:
/usr/bin/ids-daemonA package can contain multiple files and metadata:
IDS Package
│
├── /usr/bin/ids-daemon
├── /etc/ids/config.json
├── /usr/lib/systemd/system/ids-daemon.service
└── Package metadata
├── Version
└── DependenciesA package manager can track versions, installed files, and dependencies. Simply copying a binary does not provide all those benefits.
In Yocto, recipe building, installation staging, packaging, and final image generation are separate stages.
4.4 Why are full Yocto builds slow?
Imagine your image requires hundreds of components.
It might involve compiling a cross-toolchain, system libraries, Linux kernel, utilities, and proprietary software.
A clean build can take considerable time because it performs a lot of work.
What makes a build expensive?
- Downloading and preparing source code
- Compiling large C/C++ codebases and the Linux kernel
- Packaging programs, libraries, and their dependencies
- Assembling filesystem and image artifacts
However, Yocto has an important optimization: shared state cache (sstate).
How sstate works
Let’s say you successfully built these components yesterday:
Linux Kernel ✓ Built
OpenSSL ✓ Built
BusyBox ✓ Built
LCM ✓ Built
IDS ✓ BuiltToday you modify IDS.
Get Ankush Dhanda’s stories in your inbox
Join Medium for free to get updates from this writer.
BitBake can reuse unaffected task results while rebuilding work whose inputs changed.
Conceptual illustration, not measured build times. Whether work is reused depends on task inputs, dependencies, and cache validity.
Yocto uses task signatures to decide whether cached results can be reused. It doesn’t merely compare the names of recipes.
Another important distinction:
bitbake <image-name> after a small application change may also be relatively fast, because much of the previous work can be reused. The remaining image assembly and validation work still takes time, which is why developers often use smaller deployment workflows.
4.5 The three common ways to test your IDS change
This is how I’d think about development on your Qualcomm board.
Method A: Copy the compiled binary
Compile ids-daemon, transfer it to a writable development location, and execute it.
Fast for isolated changes, but you must handle libraries, configuration, permissions, and any running service yourself.
Method B: Install an application package
Build an IPK, RPM or DEB package and install it using the target’s compatible package manager.
Better for tracking files and dependencies, provided package management is available and configured.
Method C: Use Yocto devtool
Use Yocto’s development tooling to modify, build and deploy a recipe to a running target.
Useful for the edit-build-test cycle when the target supports development deployment.
Example using devtool
Yocto provides a useful development workflow:
# On the Yocto development host
devtool modify ids-daemon# Edit files in the workspacedevtool build ids-daemon# Development board only, after verifying
# compatibility, SSH and writable target paths:
devtool deploy-target ids-daemon root@BOARD_IP
The deploy-target command copies the files installed by the recipe onto the target. It bypasses package management and does not automatically install missing runtime dependencies.
Yocto explicitly recommends this for development, not production deployment.
You can use devtool undeploy-target to restore previously overwritten files from that development deployment, subject to the target and deployment state.
Don’t run these deployment commands yet on your Qualcomm device. First, we’ll verify its filesystem mode and whether IDS is safe to stop or update.
4.6 What if the new binary doesn’t work?
This is where embedded Linux becomes interesting.
Suppose IDS works on Board A but not on Board B.
Both boards have the same processor architecture.
You compile the IDS binary and copy it to both.
Board A:
IDS started successfullyBoard B:
error while loading shared libraries:
libids.so.1: cannot open shared object fileWhy?
Because compiling your application doesn’t guarantee that every required runtime library is available on the target.
If a necessary library is missing or incompatible, the application may fail before entering main().
There are several other compatibility requirements:
- Correct CPU architecture and ABI.
- Compatible C/C++ runtime libraries.
- Compatible shared-library versions.
- Required configuration files.
- Correct permissions and runtime environment.
- Necessary kernel features, interfaces or drivers.
Practical commands to diagnose this
On your development machine:
file ids-daemon
readelf -h ids-daemon
readelf -d ids-daemon | grep NEEDEDThe first command identifies the file type and architecture.
The second shows ELF information, including its machine type.
The third shows declared dynamic-library dependencies.
On the board:
uname -m
ls /usr/lib
cat /proc/mountsYou can also inspect the dynamic loader’s error message when launching the application, provided doing so is safe for the device.
This is why an SDK matched to the target matters. It helps build applications against the intended target headers, libraries and ABI. We’ll cover that in Lesson 5.
4.8 Hands-on exercise using your physical board
We’ll start entirely with read-only inspection.
Safe observation exercise
No flashing, service stopping, package installation, or filesystem changes are required.
Step 1: Check the running architecture
On the Qualcomm board:
uname -m
uname -rThis tells you the userspace-reported machine architecture and running kernel version.
Step 2: Is the rootfs writable?
cat /proc/mounts | grep ' / 'Example output might contain:
/dev/mmcblk0p3 / ext4 ro,relatime 0 0The ro means this mount is read-only.
Or:
/dev/mmcblk0p3 / ext4 rw,relatime 0 0Here rw means this mount is read-write.
The backing device and filesystem are only examples; your board might show ubifs, overlay, or a different device.
If the root is an overlay filesystem, the output needs more careful interpretation because the underlying system files may still be read-only.
Step 3: Identify the IDS executable and dependencies
If IDS is installed:
command -v ids-daemonOr search selected conventional directories:
ls /usr/bin | grep -i ids
ls /usr/lib | grep -i idsIf your board uses systemd:
systemctl status ids-daemonThe unit may have another name, so a service-not-found response doesn’t necessarily mean IDS is absent.
Step 4: Check for package-management support
command -v opkg
command -v rpm
command -v dpkgOne or more may be present, or none.
If there is no package manager, that doesn’t prevent updating the device through an image-update mechanism or a controlled developer deployment method.









