Custom Linux build for Raspberry PI with Buildroot
It seems working in embedded means you’ll, sooner or later, use a Raspberry PI. At my current work place we use Raspberry PIs, connected to the hardware we’re developing for, as Github CI runners. Anytime we want to add a new runner we need to flash an SD card and manually install all the dependencies and tools.
What I’m looking for is an ability to generate Raspberry PI images, pre-installed with all the necessary (+ some of my favourite) tools. That can be achieved thanks to projects like Yocto or Buildroot. This post relates to the latter, which is considered to be simpler and easier to get started with.
After some experimentation, I managed to add the nnn - my favourite terminal file browser - to the build process.
First I’ve created the Makefile that tells Buildroot how to build nnn:
################################################################################
#
# nnn
#
################################################################################
NNN_VERSION = v4.6
# Buildroot guesses the NNN_SITE_METHOD from NNN_SITE contents.
NNN_SITE = https://github.com/jarun/nnn/releases/download/$(NNN_VERSION)
# nnn's Makefile uses $(PKG_CONFIG)
NNN_DEPENDENCIES = host-pkgconf
NNN_DEPENDENCIES += musl-fts
NNN_DEPENDENCIES += readline
NNN_DEPENDENCIES += ncurses
define NNN_BUILD_CMDS
$(TARGET_MAKE_ENV) $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D)
endef
define NNN_INSTALL_TARGET_CMDS
$(TARGET_MAKE_ENV) $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) DESTDIR="$(TARGET_DIR)" install
endef
$(eval $(generic-package))
This file has been saved as
package/nnn/nnn.mk
.
The first paragraph describes the version of the package and where to find it.
I’m using a release URL but you could use a Github repository URL - check
github
helper in the
Buildroot manual.
The
NNN_DEPENDENCIES
refer to packages already present in the
buildroot/package
directory.
Buildroot uses Kconfig for project configuration. That system needs to be aware of the the new package and its dependencies:
config BR2_PACKAGE_NNN
bool "nnn"
select BR2_TOOLCHAIN_BUILDROOT_WCHAR
select BR2_USE_WCHAR
select BR2_PACKAGE_READLINE
select BR2_PACKAGE_NCURSES
select BR2_PACKAGE_NCURSES_WCHAR
select BR2_PACKAGE_MUSL_FTS
help
https://github.com/jarun/nnn
This file has been saved as
package/nnn/Config.in
.
Notice I’m using
select
instruction here. Maybe
depends on
would be more fitting here.
Certain
BR2_PACKAGE_
options refer to dependencies specified in the
nnn.mk
, other enable
the wide character (a
char
type that might be bigger than 8-bit) support.
The
package/nnn/Config.in
has to be included in the
package/Config.in
- a file which
sources each package’s
Config.in
. It also groups packages in categories. I have appended
source "package/nnn/Config.in"
in the
Miscellaneous
category.
What’s left to do is to use a predefined config for Raspberry PI 4 and to build nnn.
make raspberrypi4_defconfig
make nnn
/home/user/buildroot/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/11.3.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: /tmp/ccodl1K7.o: in function `du_thread':
nnn.c:(.text+0x1768): undefined reference to `fts_open'
/home/user/buildroot/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/11.3.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: nnn.c:(.text+0x178c): undefined reference to `fts_read'
/home/user/buildroot/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/11.3.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: nnn.c:(.text+0x17bc): undefined reference to `fts_close'
Heartbreaking. This happens because nnn actually doesn’t only use its Makefile to build. It references a bash script in its Makefile, which installs musl-fts and links to it statically.
In order to fix it, I have modified the nnn’s Makefile such that it links to the musl-fts
dynamically. I have saved this change to a patch file, with
git diff > 0001_lfts.patch
.
diff --git a/Makefile b/Makefile
index 79042c33..14845237 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ CFLAGS += -std=c11 -Wall -Wextra -Wshadow
CFLAGS += $(CFLAGS_OPTIMIZATION)
CFLAGS += $(CFLAGS_CURSES)
-LDLIBS += $(LDLIBS_CURSES) -lpthread
+LDLIBS += $(LDLIBS_CURSES) -lpthread -lfts
# static compilation needs libgpm development package
ifeq ($(strip $(O_STATIC)),1)
This file has been saved as
package/nnn/0001_lfts.patch
. Buildroot picks up patches
automatically. This time the build step should succeed.
make nnn-dirclean
make nnn
You’ll actually see Buildroot picking up that patch and applying it.
Running
make
, without any target, makes Buildroot build an image for Raspberry PI 4,
with nnn pre-installed.
I might continue by adding my code editor of choice, Kakoune.