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/nnnThis 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.