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.