Skip to content

Building and customizing

maxnet edited this page Jun 25, 2017 · 13 revisions

Build instructions

How to build

Building the software is done on a regular computer running Linux.

First the build dependencies need to be installed.

  • If the Linux distribution used is Debian or Ubuntu this can be done with the command:
sudo apt-get update
sudo apt-get install git-core build-essential rsync libncurses-dev unzip python bc
  • Then download the build scripts from this repository:
git clone --depth 1 https://github.com/raspberrypi/scriptexecutor.git
  • Choose your architecture (compute model 1 or 3) by opening the file build.sh in a text editor and editing the variable TARGET=cmX

  • Start the build process with:

cd scriptexecutor
./build.sh

The first time the build.sh script is run, it will first build the toolchain (compiler, etc.) used to cross-compile for the target system, before it proceeds to build the image itself. Be aware that this can take a long time to complete.

After the build is complete the resulting files will be in the “output” directory. If using a custom compute module board design, you may need to add your own dt-blob.bin file to them.

The files can be booted on a compute module by connecting it to your computer with a USB cable and using the rpiboot utility (provided it is installed, see https://github.com/raspberrypi/usbboot for instructions)

sudo ./rpiboot -d output

Note that -when using a standard CM board design- once the Pi compute module has booted you need to remove the programming cable again, before it can use its USB port in host mode, and access its USB Ethernet adapter to download the script.

Setting which script is executed

Open output/cmdline.txt in a text editor to modify which script is executed. E.g. to tell the image to download the script from the HTTP server with IP-address 1.2.3.4 put in cmdline.txt:

script=http://1.2.3.4/name-of-script.sh

To tell the image to download the script from the NFS server with IP-addresses 1.2.3.4 use:

script=1.2.3.4:/name-of-nfs-share/name-of-script.sh

If using NFS the script has access to other files inside the same NFS share as well. The current working directory is set to where the share is mounted before the script is executed.

Drafting a script

You will need to write a simple shell script to perform the actions you want. All commands supported by the busybox utility can be used. For a list see: https://www.busybox.net/downloads/BusyBox.html

E.g. if your script is hosted on NFS, and you want to write the gzip compressed disk image myimage.img.gz -located in the same NFS share as the script- to eMMC use a script like this:

#!/bin/sh

set -e

gzip -dc myimage.img.gz | dd of=/dev/mmcblk0 conv=fsync bs=1M
echo Image written successfully

If the image is located on a HTTP server use a script like this:

#!/bin/sh

set -e

wget -O- http://1.2.3.4/myimage.img.gz | gzip -dc | dd of=/dev/mmcblk0 conv=fsync bs=1M
echo Image written successfully

If the commands provided by busybox are insufficient, or you prefer to use a different scripting language such as Python, it is possible to install extra software to the image. See the instructions in the section "Adding extra software through buildroot packages" below for more information.

Mounting additional NFS shares

If you need to mount additional NFS shares, you can do so like this:

mkdir /tmp/mymountpoint
mount -t nfs -o ro,nolock 1.2.3.4:/other-share /tmp/mymountpoint
[ .. commands that use files mounted at /tmp/mymountpoint .. ]
umount /tmp/mymountpoint

Specifying the nolock option is important, as there is no NFS client daemon software installed to manage locks by default. Only the basic NFS functionality provided by the kernel is available.

DHCP and scripts that never finish

Be aware that the image obtains an IP-address from a DHCP server. Normally after your script has completed it will release the DHCP lease held by the compute module back to the DHCP server, so the IP-address becomes available for the next user. However be aware that if you let your script never finish -e.g. if you let it loop blinking some leds at the end-, the DHCP lease will not be released, and your DHCP server may run out of available IP-addresses if provisioning a lot of compute modules in a short time.

It is not possible to release the DHCP lease earlier -before the end of your script- if NFS is used. So if this problem occurs, you may need to work around this by configuring your DHCP server to assign IP-addresses out of a larger IP range, or set a short lease time so that they expire automatically quickly.

Implementation notes

Directory structure

|-- buildroot-2017.02.tar.gz
|-- build.sh
|-- output
|   |-- cmdline.txt
|   `-- config.txt
|-- README.md
`-- scriptexecute
    |-- board
    |   |-- kernelconfig-recovery.armv6
    |   |-- kernelconfig-recovery.armv7
    |   |-- kernelconfig-scriptexecute.fragment
    |   |-- overlay
    |   |   `-- etc
    |   |       `-- init.d
    |   |           `-- S99scriptexec
    |-- Config.in
    |-- configs
    |   |-- scriptexecute_cm1_defconfig
    |   `-- scriptexecute_cm3_defconfig
    |-- external.desc
    |-- external.mk
    `-- package
        `-- rpi-firmware-custom
            |-- Config.in
            `-- rpi-firmware-custom.mk

Buildroot 2017.02 is used as build environment. With buildroot it is possible to modify the build scripts within the buildroot folder itself to suit your needs, which is easiest. Or it is possible to store customizations in a separate external directory. This is slightly more difficult to setup but comes with the advantage that the modifications are clearly separate from the original buildroot files. Making it easier for third-party developers to see what files were changed, and making upgrades to a later Buildroot edition more trivial.

This project uses the last method. The original buildroot files are inside buildroot-2017.02.tar.gz which is extracted to the buildroot-2017.02 folder upon first use of build.sh Our own configuration files are inside the scriptexecute directory.

The buildroot configuration describing things like which software packages are enabled is stored in scriptexecute/scriptexecute_cm3_defconfig (for CM3)

A minimal kernel configuration (copied from the NOOBS project) is available in scriptexecute/board/kernelconfig-recovery.armv7 for CM3 and recovery.armv6 for CM1.

The extra kernel options we want to have on top of the minimal kernel -such as NFS client support- are in scriptexecute/board/kernelconfig-scriptexecute.fragment

The advantage of having separate files for the minimal kernel configuration and the extra options is that it simplifies upgrading to a newer kernel version.

The files Config.in, external.mk, and package/* concern extra packages. In our case we only have one custom package called rpi-firmware-custom. It is actually just a copy of the rpi-firmware package that is bundled with buildroot itself, except that we modified it to download a later version of the Raspberry Pi boot firmware files (for USB boot functionality).

The main functionality is in the file scriptexecute/board/overlay/etc/init.d/S99scriptexec This is a sysv style start-up script that is responsible for waiting for the network interface eth0 to show up, obtain a DHCP lease, and downloading and starting the script.

Normally things like obtaining a DHCP lease would be handled by other standard network scripts, but we do it in our own script because we want to have a little more control. E.g. we like to wait for eth0 to appear no matter how long it takes, and not time-out.

Adding extra software through buildroot packages

You can add extra software to the image through buildoot packages

make -C buildroot-2017.02 menuconfig

Select the software you want under the “target packages” option. E.g. if you would like to install the Python interpreter to be able to run a Python script, you would select:

“Save” the configuration, “Exit” the menu, and build again:

./build.sh

If you are happy with the result, you can make the configuration change more permanent with:

make -C buildroot-2017.02 savedefconfig

This will update the defconfig file inside scriptexecute/configs

Adding extra kernel options

If your compute module board has extra hardware, and you want your script to be able to communicate with it, enabling extra kernel drivers may be needed.

make -C buildroot-2017.02 linux-menuconfig

Select the item out of the menu. "Save" and "Exit"

make -C buildroot-2017.02 linux-rebuild
./build.sh

This will update the configuration in the buildroot-2017.02/output/build/linux-rpi-4.4.y directory. To make changes more permanent and survive a full rebuild, open scriptexecute/board/kernelconfig-scriptexecute.fragment in a text editor and add the new options there as well. In the linux-menuconfig screen, you can see what the name of the option is (CONFIG_SOMETHING) by going to it with the arrows on your keyboard, and then using the "Help" option.

More information

More information about the buildroot infrastructure (that does most of the hard work) can be found at:

https://buildroot.org/downloads/manual/manual.html

http://free-electrons.com/doc/training/buildroot/buildroot-slides.pdf