Add BR2_EXTERNAL skeleton

This commit is contained in:
2026-03-27 20:57:59 -03:00
parent 27cfa662a3
commit 162a815132
16 changed files with 632 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/output/

6
Config.in Normal file
View File

@@ -0,0 +1,6 @@
menu "RPI Common packages"
source "$BR2_EXTERNAL_RPI_COMMON_PATH/package/my-shared-lib/Config.in"
source "$BR2_EXTERNAL_RPI_COMMON_PATH/package/my-common-tool/Config.in"
endmenu

33
Makefile Normal file
View File

@@ -0,0 +1,33 @@
# br2-external-common standalone build wrapper
#
# Usage:
# make rpi_common_test_defconfig - Load a defconfig
# make - Build the image
# make menuconfig - Open configuration menu
# make savedefconfig - Save config back to the original defconfig
# make linux-rebuild - Rebuild a specific package
# make clean - Clean build artifacts
#
# Any valid Buildroot target works — it is passed through directly.
#
# The buildroot source is expected at ./buildroot (git submodule).
# The output directory is ./output (gitignored).
BUILDROOT_DIR := $(CURDIR)/buildroot
OUTPUT_DIR := $(CURDIR)/output
BR2_EXTERNAL := $(CURDIR)
CONFIG_EXISTS := $(wildcard $(OUTPUT_DIR)/.config)
.PHONY: all
all:
ifeq ($(CONFIG_EXISTS),)
@echo "No .config found. Load a defconfig first, e.g.:"
@echo " make rpi_common_test_defconfig"
@exit 1
endif
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR)
%:
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) O=$(OUTPUT_DIR) $@

356
README.md Normal file
View File

@@ -0,0 +1,356 @@
# 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:
```sh
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
```sh
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:
```sh
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
```sh
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:
```sh
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
```sh
mkdir br2-external-myproject
cd br2-external-myproject
git init
```
### Step 2: Add common as a submodule
```sh
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.
```makefile
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:
```sh
cp common/configs/rpi_common_test_defconfig configs/rpi_myproject_defconfig
```
Edit the defconfig to:
1. 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"
```
2. 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:
```makefile
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_DIR` points to `common/buildroot/` (nested submodule)
- `BR2_EXTERNAL` lists both trees, colon-separated: `common:project`
### Step 8: Create supporting directories
```sh
mkdir -p overlay/etc
mkdir -p package
mkdir -p board
mkdir -p configs
echo '/output/' > .gitignore
```
### Step 9: Commit and build
```sh
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:
```sh
# 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:
```sh
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:
```sh
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:
```sh
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
1. Create a directory under `package/` with the package name.
2. Add a `Config.in` with the Kconfig entry.
3. Add a `.mk` file with the Buildroot package recipe.
4. Source the new `Config.in` in the top-level `Config.in`.
5. Enable the package in `configs/rpi_common_test_defconfig`.
6. 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`).

View File

@@ -0,0 +1,53 @@
/* genimage.cfg - SD card image layout for Raspberry Pi
*
* Partition layout:
* - boot (FAT32, 64MB): kernel, device tree, bootloader files
* - rootfs (ext4, 256MB): root filesystem
*
* The final image is written to sdcard.img.
*
* Adjust partition sizes as needed for your project. Projects can
* override this file by providing their own genimage.cfg and setting
* GENIMAGE_CFG in their post-image script.
*/
image boot.vfat {
vfat {
files = {
"bcm2710-rpi-3-b.dtb",
"bcm2711-rpi-4-b.dtb",
"rpi-firmware/bootcode.bin",
"rpi-firmware/start.elf",
"rpi-firmware/fixup.dat",
"rpi-firmware/config.txt",
"rpi-firmware/cmdline.txt",
"Image"
}
}
size = 64M
}
image rootfs.ext4 {
ext4 {
label = "rootfs"
}
size = 256M
}
image sdcard.img {
hdimage {
}
partition boot {
partition-type = 0xC
bootable = "true"
image = "boot.vfat"
}
partition rootfs {
partition-type = 0x83
image = "rootfs.ext4"
}
}

View File

@@ -0,0 +1,12 @@
# /etc/network/interfaces - Common network configuration
#
# This file is part of the shared rootfs overlay and provides a
# sensible default network configuration for all Raspberry Pi projects.
# Projects can override this by placing their own version in their
# project-specific overlay (which is applied after this one).
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp

34
board/raspberrypi/post_build.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
# post_build.sh - Common post-build script for Raspberry Pi
#
# Called by Buildroot after assembling the target rootfs.
# Arguments:
# $1 = path to the target rootfs directory (e.g., output/target)
#
# Environment:
# BR2_EXTERNAL_RPI_COMMON_PATH = path to this external tree
#
# Use this script for:
# - Fixing file permissions
# - Creating symlinks
# - Generating config files that depend on build-time variables
# - Stripping unnecessary files from the rootfs
#
# Do NOT use this for:
# - Installing packages (use rootfs overlay or a package .mk instead)
# - Modifying files outside $1
set -e
TARGET_DIR="$1"
# Example: ensure /etc/hostname exists with a default value
if [ ! -f "${TARGET_DIR}/etc/hostname" ]; then
echo "rpi-common" > "${TARGET_DIR}/etc/hostname"
fi
# Example: remove unnecessary documentation to save space
rm -rf "${TARGET_DIR}/usr/share/man"
rm -rf "${TARGET_DIR}/usr/share/doc"
echo ">>> Common post-build script completed"

35
board/raspberrypi/post_image.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/sh
# post_image.sh - Common post-image script for Raspberry Pi
#
# Called by Buildroot after filesystem images (ext4, etc.) are generated.
# Arguments:
# $1 = path to the images directory (e.g., output/images)
#
# Environment:
# BR2_EXTERNAL_RPI_COMMON_PATH = path to this external tree
# BINARIES_DIR = same as $1
# BUILD_DIR = path to the build directory
#
# This script uses genimage to assemble the final SD card image
# from the boot files and root filesystem.
set -e
BOARD_DIR="${BR2_EXTERNAL_RPI_COMMON_PATH}/board/raspberrypi"
# Use project-specific genimage.cfg if it exists, otherwise use common one.
# Projects can override by setting GENIMAGE_CFG in their own post-image script.
GENIMAGE_CFG="${GENIMAGE_CFG:-${BOARD_DIR}/genimage.cfg}"
# genimage requires a temporary directory
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
rm -rf "${GENIMAGE_TMP}"
genimage \
--rootpath "${TARGET_DIR}" \
--tmppath "${GENIMAGE_TMP}" \
--inputpath "${BINARIES_DIR}" \
--outputpath "${BINARIES_DIR}" \
--config "${GENIMAGE_CFG}"
echo ">>> SD card image generated: ${BINARIES_DIR}/sdcard.img"

View File

@@ -0,0 +1,36 @@
# Architecture
BR2_aarch64=y
# Toolchain
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
# Kernel
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,stable_20231123)/linux-stable_20231123.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2711"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2711-rpi-4-b"
BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
# Bootloader
BR2_PACKAGE_RPI_FIRMWARE=y
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4=y
# Filesystem
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
# Host tools needed for image generation
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_DOSFSTOOLS=y
BR2_PACKAGE_HOST_MTOOLS=y
# Rootfs overlay and scripts from this BR2_EXTERNAL
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_RPI_COMMON_PATH)/board/raspberrypi/overlay"
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_RPI_COMMON_PATH)/board/raspberrypi/post_build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_RPI_COMMON_PATH)/board/raspberrypi/post_image.sh"
# Enable all common packages for testing
BR2_PACKAGE_MY_SHARED_LIB=y
BR2_PACKAGE_MY_COMMON_TOOL=y

2
external.desc Normal file
View File

@@ -0,0 +1,2 @@
name: RPI_COMMON
desc: Common Raspberry Pi board support, shared packages, and overlays

1
external.mk Normal file
View File

@@ -0,0 +1 @@
include $(sort $(wildcard $(BR2_EXTERNAL_RPI_COMMON_PATH)/package/*/*.mk))

View File

@@ -0,0 +1,10 @@
config BR2_PACKAGE_MY_COMMON_TOOL
bool "my-common-tool"
select BR2_PACKAGE_MY_SHARED_LIB
help
A command-line utility shared across multiple Raspberry Pi
projects. Depends on my-shared-lib.
Installs the 'my-common-tool' binary into /usr/bin on the target.
https://github.com/your-org/my-common-tool

View File

@@ -0,0 +1,22 @@
################################################################################
#
# my-common-tool
#
################################################################################
MY_COMMON_TOOL_VERSION = 1.0.0
MY_COMMON_TOOL_SITE = https://github.com/your-org/my-common-tool.git
MY_COMMON_TOOL_SITE_METHOD = git
MY_COMMON_TOOL_LICENSE = MIT
MY_COMMON_TOOL_LICENSE_FILES = LICENSE
MY_COMMON_TOOL_DEPENDENCIES = my-shared-lib
define MY_COMMON_TOOL_BUILD_CMDS
$(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D)
endef
define MY_COMMON_TOOL_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/my-common-tool $(TARGET_DIR)/usr/bin/my-common-tool
endef
$(eval $(generic-package))

View File

@@ -0,0 +1,9 @@
config BR2_PACKAGE_MY_SHARED_LIB
bool "my-shared-lib"
help
A shared library providing common functionality used across
multiple Raspberry Pi projects.
Installs libmyshared.so into /usr/lib on the target.
https://github.com/your-org/my-shared-lib

View File

@@ -0,0 +1,22 @@
################################################################################
#
# my-shared-lib
#
################################################################################
# IMPORTANT: Update this version and hash when upgrading the package.
# The hash file (my-shared-lib.hash) should also be updated accordingly.
MY_SHARED_LIB_VERSION = 1.0.0
MY_SHARED_LIB_SITE = https://github.com/your-org/my-shared-lib.git
MY_SHARED_LIB_SITE_METHOD = git
MY_SHARED_LIB_LICENSE = MIT
MY_SHARED_LIB_LICENSE_FILES = LICENSE
MY_SHARED_LIB_INSTALL_STAGING = YES
# CMake options passed to the package's build.
# Add any project-specific CMake definitions here.
MY_SHARED_LIB_CONF_OPTS = \
-DBUILD_TESTS=OFF \
-DBUILD_EXAMPLES=OFF
$(eval $(cmake-package))

0
patches/.gitkeep Normal file
View File