Building Your Own: Packages, Patches, and Overrides
Part 5 of The Thingino Developer’s Journey / <- Part 4
You’ve built firmware, customized it, maybe ported a camera. Now you want to put your own software on the thing — or fix someone else’s. This is where Thingino stops being a build system you operate and becomes one you extend.
Anatomy of a package
Thingino is a BR2_EXTERNAL tree, so adding a package never touches
Buildroot itself. Drop a directory into package/ and it’s auto-discovered:
package/mytool/
|-- Config.in # the menuconfig entry
`-- mytool.mk # how to fetch, build, install
A real, complete example from the tree — package/jsonpath/jsonpath.mk:
JSONPATH_SITE_METHOD = git
JSONPATH_SITE = https://github.com/openwrt/jsonpath
JSONPATH_VERSION = b9034210bd331749673416c6bf389cccd4e23610
JSONPATH_LICENSE = ISC, BSD-3-Clause
JSONPATH_DEPENDENCIES = json-c libubox
define JSONPATH_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/jsonpath $(TARGET_DIR)/usr/bin/jsonpath
endef
$(eval $(cmake-package))
That’s the whole thing. Declare where the source lives, what it depends on,
how to install the result, and which build-system class to use
(cmake-package, autotools-package, generic-package…). Buildroot
handles cross-compilation, sysroots, and ordering. Add
BR2_PACKAGE_MYTOOL=y to a camera defconfig — or your local.fragment from
Part 3 while experimenting — and it’s in the image.
Browse package/ for templates: thingino-daynightd shows a package with
bundled files and init scripts; the thingino-webui tree shows how big one
can get.
The one command that changes your life
Full rebuilds are for robots. When you’re working on one package:
CAMERA=<camera> make rebuild-mytool
This dircleans the package, rebuilds it, reinstalls it into the target
filesystem, and re-finalizes the image — a couple of minutes instead of
thirty. Pair it with IP=... make ota (or scp -O the binary straight over
for the truly impatient) and your loop is tight.
Source overrides: hacking on the actual source
Package sources normally come from tarballs or git checkouts that Buildroot
fetches and unpacks into output/. Editing files in output/build/... is a
trap — your changes evaporate on the next dirclean. The correct tool is a
source override: point Buildroot at a local checkout you control.
Thingino automates it:
./scripts/manage-package-overrides.sh -l # list override candidates
./scripts/manage-package-overrides.sh prudynt-t # clone + wire up an override
This clones the package’s source into overrides/prudynt-t/ and adds one
line to local.mk:
PRUDYNT_T_OVERRIDE_SRCDIR = $(BR2_EXTERNAL)/overrides/prudynt-t
From now on, builds rsync from your checkout. Edit, then
make rebuild-prudynt-t, flash, repeat. Real git history, real branches,
real diffs — in a normal repository that happens to feed a firmware build.
The same script disables (-d), re-enables (-e), updates (-u), and
removes (-r) overrides.
Two things to know:
- Overrides bypass Buildroot patches. If the package normally carries patches, apply them to your checkout manually before you start editing, or you’re debugging a source tree that never existed.
- Override mappings can live in the root
local.mkor in your scoped user layers (user/common/local.mk,user/<camera>/local.mk) — Part 3’s precedence rules apply.
Patch discipline
Fixing a bug in an upstream package you don’t want to fork? Buildroot’s
patch convention: drop NNNN-description.patch files into the package
directory and they apply in sort order at extraction time.
One Thingino-specific commandment: U-Boot support is delivered as a single
enormous patch (package/all-patches/uboot/<version>/0001-from-<version>-to-thingino.patch).
Never edit that patch. Add numbered follow-ups (0002-your-fix.patch,
0003-...) in the same directory; they apply after it, in order. Buildroot
patches live in package/all-patches/buildroot/ and are managed by
make update — same rule: append, don’t rewrite.
When producing patches, use your real identity and sign off
(git format-patch, Signed-off-by: matching your git config) — patches
are commits with a passport.
Streamers, briefly
The default video pipeline is prudynt; setting BR2_PACKAGE_RAPTOR_IPC=y
switches a build to the newer raptor stack. If you’re planning to add an
entirely new streamer backend, that’s a documented rabbit hole with its own
Kconfig plumbing — see docs/streamer.md before digging.
What you learned
- A package is two small files in
package/; Buildroot does the rest. make rebuild-<pkg>+ OTA is the inner loop.- Source overrides give you real git checkouts for package development — just remember they bypass patches.
- Patches append in numbered order; the big U-Boot patch is load-bearing and sacred.
Next up: Part 6 — Going Parallel: you now have ports in review, a package mid-refactor, and a bug report from the Discord. Time to stop switching branches and start multiplying yourself. Git worktrees, the god-level unlock.