10 KiB
br2-external-common
Common Buildroot BR2_EXTERNAL tree for all Raspberry Pi projects. This repository provides shared board support, packages, rootfs overlays, and patches that are used across multiple projects.
This repository also pins the upstream Buildroot version as a git submodule, serving as the single source of truth for which Buildroot release is used. When a project pulls in this repo, it transitively gets the tested Buildroot version.
Repository layout
br2-external-common/
├── external.desc Buildroot external tree descriptor (name: RPI_COMMON)
├── external.mk Includes all common package .mk files
├── Config.in Top-level Kconfig menu for common packages
├── Makefile Wrapper for standalone build invocations
├── buildroot/ [submodule] Upstream Buildroot, pinned to release tag
├── board/
│ └── raspberrypi/
│ ├── post_build.sh Shared post-build script (rootfs fixups)
│ ├── post_image.sh Shared post-image script (genimage invocation)
│ ├── genimage.cfg SD card partition layout
│ └── overlay/ Shared rootfs overlay (copied into target rootfs)
│ └── etc/
│ └── network/
│ └── interfaces
├── package/
│ ├── my-shared-lib/ Example shared library (CMake package)
│ └── my-common-tool/ Example shared tool (generic package)
├── patches/ Patches to upstream Buildroot packages
└── configs/
└── rpi_common_test_defconfig Minimal defconfig for standalone CI testing
Standalone setup
Use this to develop and test the common tree without any project-specific additions. This is also what CI should run on every commit to this repo.
Prerequisites
A Linux host with standard Buildroot dependencies installed. See the Buildroot manual for the full list. On Debian/Ubuntu:
sudo apt-get install -y build-essential gcc g++ bash patch gzip bzip2 \
perl tar cpio unzip rsync file bc wget libncurses-dev git
Clone and initialize
git clone git@github.com:your-org/br2-external-common.git
cd br2-external-common
git submodule update --init
This pulls the Buildroot source into buildroot/ at the pinned release tag.
Build the test image
The wrapper Makefile handles the Buildroot invocation:
make defconfig # Loads rpi_common_test_defconfig
make # Builds the full image (takes a while on first run)
The SD card image will be at output/images/sdcard.img.
Useful build commands
make menuconfig # Open Buildroot configuration menu
make savedefconfig # Save current .config back to the test defconfig
make linux-rebuild # Rebuild just the kernel (any Buildroot target works)
make my-shared-lib-rebuild # Rebuild a specific package
make clean # Clean build artifacts
make distclean # Remove the entire output directory
You can use a different defconfig by passing DEFCONFIG:
make defconfig DEFCONFIG=rpi_common_minimal_defconfig
Creating a new project
A project is a separate git repository that uses this common tree as a submodule. Each project is its own BR2_EXTERNAL and contains only project-specific packages, overlays, defconfigs, and board overrides.
Step 1: Create the project repository
mkdir br2-external-myproject
cd br2-external-myproject
git init
Step 2: Add common as a submodule
git submodule add git@github.com:your-org/br2-external-common.git common
git submodule update --init --recursive
The --recursive is important because it also pulls common's own Buildroot
submodule into common/buildroot/.
Step 3: Create the BR2_EXTERNAL descriptor
Create external.desc at the project root. The name must be unique across all
external trees and must be a valid C identifier (uppercase, underscores only):
name: MY_PROJECT
desc: My project-specific Buildroot configuration
Step 4: Create external.mk
This file includes only the project's own packages. The common packages are
handled by the common tree's own external.mk — Buildroot merges them
automatically because both trees are passed as separate BR2_EXTERNAL paths.
include $(sort $(wildcard $(BR2_EXTERNAL_MY_PROJECT_PATH)/package/*/*.mk))
Step 5: Create Config.in
Same principle — only source the project's own package configs:
menu "My Project packages"
source "$BR2_EXTERNAL_MY_PROJECT_PATH/package/my-app/Config.in"
endmenu
Step 6: Create a project defconfig
Create configs/rpi_myproject_defconfig. Start by copying the common test
defconfig and modify it:
cp common/configs/rpi_common_test_defconfig configs/rpi_myproject_defconfig
Edit the defconfig to:
- Add both overlays (common first, then project-specific):
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_RPI_COMMON_PATH)/board/raspberrypi/overlay $(BR2_EXTERNAL_MY_PROJECT_PATH)/overlay"
- Add project-specific packages:
BR2_PACKAGE_MY_APP=y
The common packages (BR2_PACKAGE_MY_SHARED_LIB, etc.) remain as-is.
Step 7: Create the wrapper Makefile
Create a Makefile at the project root:
BUILDROOT_DIR := $(CURDIR)/common/buildroot
OUTPUT_DIR := $(CURDIR)/output
BR2_EXTERNAL := $(CURDIR)/common:$(CURDIR)
DEFCONFIG ?= rpi_myproject_defconfig
CONFIG_EXISTS := $(wildcard $(OUTPUT_DIR)/.config)
.PHONY: all defconfig menuconfig savedefconfig clean distclean
all:
ifeq ($(CONFIG_EXISTS),)
@echo "No .config found. Run 'make defconfig' first."
@exit 1
endif
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR)
defconfig:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) $(DEFCONFIG)
menuconfig:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) menuconfig
savedefconfig:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) savedefconfig \
BR2_DEFCONFIG=$(CURDIR)/configs/$(DEFCONFIG)
clean:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) clean
distclean:
rm -rf $(OUTPUT_DIR)
%:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) $@
Note the key difference from the common Makefile:
BUILDROOT_DIRpoints tocommon/buildroot/(nested submodule)BR2_EXTERNALlists both trees, colon-separated:common:project
Step 8: Create supporting directories
mkdir -p overlay/etc
mkdir -p package
mkdir -p board
mkdir -p configs
echo '/output/' > .gitignore
Step 9: Commit and build
git add -A
git commit -m "Initial project skeleton"
make defconfig
make
Project directory structure
After following these steps, your project should look like this:
br2-external-myproject/
├── external.desc
├── external.mk
├── Config.in
├── Makefile
├── .gitmodules
├── .gitignore
├── common/ [submodule -> br2-external-common]
│ ├── buildroot/ [nested submodule -> upstream Buildroot]
│ ├── board/raspberrypi/
│ ├── package/
│ └── ...
├── configs/
│ └── rpi_myproject_defconfig
├── overlay/ Project-specific rootfs overlay
├── package/ Project-specific packages
│ └── my-app/
└── output/ Build output (gitignored)
Branching strategy
This repository uses long-lived branches to support multiple Buildroot versions simultaneously, mirroring Buildroot's own LTS release model.
Branch naming
main— Tracks the latest Buildroot release (currently 2026.02). Active development of shared packages happens here.YYYY.MM.x— Maintenance branches for older Buildroot LTS lines (e.g.,2023.02.x). These receive only bug fixes and minor Buildroot bumps within the same LTS series.
Creating a maintenance branch
When a project needs to stay on an older Buildroot version:
# Start from the last commit that used the older Buildroot
git checkout -b 2023.02.x <commit-hash>
# Verify the buildroot submodule points to the right tag
cd buildroot
git log --oneline -1 # Should show 2023.02.x tag
cd ..
git push -u origin 2023.02.x
Bumping a minor Buildroot version on a maintenance branch
For example, upgrading from 2023.02.1 to 2023.02.2:
git checkout 2023.02.x
cd buildroot
git fetch --tags
git checkout 2023.02.2
cd ..
git add buildroot
git commit -m "buildroot: bump to 2023.02.2"
git push
Then in the project that uses this branch:
cd common
git pull origin 2023.02.x
cd ..
git add common
git commit -m "common: pick up buildroot 2023.02.2"
Backporting shared package fixes
When a bug fix on main also applies to a maintenance branch:
git checkout 2023.02.x
git cherry-pick <commit-hash-from-main>
# Resolve conflicts if the package versions have diverged
# Test with: make defconfig && make
git push
End-of-life
When a legacy project is decommissioned, its maintenance branch can be
archived (renamed to archive/2023.02.x) or deleted. No other projects
are affected.
Adding a new shared package
- Create a directory under
package/with the package name. - Add a
Config.inwith the Kconfig entry. - Add a
.mkfile with the Buildroot package recipe. - Source the new
Config.inin the top-levelConfig.in. - Enable the package in
configs/rpi_common_test_defconfig. - Build and verify:
make my-new-package-rebuild.
See package/my-shared-lib/ (CMake example) and package/my-common-tool/
(generic example) for reference.
Adding patches to upstream Buildroot packages
Place patch files under patches/<package-name>/. Buildroot automatically
applies patches from BR2_EXTERNAL_RPI_COMMON_PATH/patches/<package-name>/
during the package build. Patches must follow Buildroot's naming convention:
NNNN-description.patch (e.g., 0001-fix-cross-compilation.patch).