Home - notro/rpi-build GitHub Wiki

Discontinued
2015-02-11
I haven't got the time to maintain this anymore. If anyone want's to pick it up, please do.

rpi-build is a tool to build, install and release Linux kernels for the Raspberry Pi.

This can be done on the Raspberry Pi itself, or on another build machine.
rpi-update is used to install the resulting kernel.
The resulting firmware can be installed directly from the build directory, or from github like the official Raspberry Pi kernel.

Install

sudo wget https://raw.githubusercontent.com/notro/rpi-build/master/rpi-build -O /usr/bin/rpi-build && sudo chmod +x /usr/bin/rpi-build

# the first run checks dependencies and installs all files
$ rpi-build

Missing dependencies:
- bc
- ncurses library (used by make menuconfig)
- sshpass

sudo apt-get --yes install bc libncurses5-dev sshpass
Install dependencies? [Y/n]
[...]
The following NEW packages will be installed:
  bc libncurses5-dev libtinfo-dev sshpass
[...]
Installing rpi-build to /home/pi/rpi-build:
[...]

Use

$ rpi-build [option tasks] release target

The libraries are a good place to see how to make packages

Examples

Output and logs are filtered to highlight important commands.

Build and install Linux 3.15 from kernel.org on the Raspberry Pi itself.

This takes ~3.5 hours

I'm not sure if video works though. I used a serial console. There is USB and networking support now.
(more)

$ rpi-build use[stdlib] linux install
Workdir: /home/pi/workdir
mkdir: created directory `/home/pi/workdir'
mkdir: created directory `/home/pi/rpi-build/downloads'
(in /home/pi/rpi-build/stdlib)
KERNEL_ORG_VERSION = 3.15
Release: linux
Package: issue106
Package: raspberrypi_tools
Package: raspberrypi_firmware
Package: uboot_bcm2835
Package: uboot_arm
Package: kernelorg_linux
wget --progress=dot:mega -O '/home/pi/rpi-build/downloads/raspberrypi-firmware-b0fc17c2368ec1db930fa8c62ee1c2b8e0b87706.tar.gz' 'https://github.com/raspberrypi/firmware/archive/b0fc17c2368ec1db930fa8c62ee1c2b8e0b87706.tar.gz'
wget --progress=dot:mega -O '/home/pi/rpi-build/downloads/git.denx.de--p-u-boot-u-boot-arm.git-0a26e1d6c394aacbf1153977b7348d1dff85db3f.tar.bz2' 'http://git.denx.de/?p=u-boot/u-boot-arm.git;a=snapshot;h=0a26e1d6c394aacbf1153977b7348d1dff85db3f;sf=tbz2'
wget --progress=dot:mega -O '/home/pi/rpi-build/downloads/linux-3.15.tar.xz' 'https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.15.tar.xz'
Target 'fetch' done

tar -x --checkpoint=100 --checkpoint-action=dot -C /home/pi/workdir -f /home/pi/rpi-build/downloads/raspberrypi-firmware-b0fc17c2368ec1db930fa8c62ee1c2b8e0b87706.tar.gz
tar -x --checkpoint=100 --checkpoint-action=dot -C /home/pi/workdir -f /home/pi/rpi-build/downloads/git.denx.de--p-u-boot-u-boot-arm.git-0a26e1d6c394aacbf1153977b7348d1dff85db3f.tar.bz2
tar -x --checkpoint=100 --checkpoint-action=dot -C /home/pi/workdir -f /home/pi/rpi-build/downloads/linux-3.15.tar.xz
Target 'unpack' done

Linux kernel version: 3.15
Target 'patch' done

cd /home/pi/workdir/linux && ARCH=arm  make bcm2835_defconfig
cp /home/pi/workdir/linux/.config /home/pi/workdir/linux/.config.defconfig
cd /home/pi/workdir/linux && scripts/config --enable CONFIG_IKCONFIG
cd /home/pi/workdir/linux && scripts/config --enable CONFIG_IKCONFIG_PROC
cd /home/pi/workdir/linux && yes "" | ARCH=arm  make oldconfig
cd /home/pi/workdir/linux && scripts/config --enable PROC_DEVICETREE
cd /home/pi/workdir/linux && yes "" | ARCH=arm  make oldconfig
Target 'config' done

cd /home/pi/workdir/linux && ARCH=arm  make -j2
cd /home/pi/workdir/u-boot &&  ./MAKEALL --continue rpi_b
/home/pi/workdir/u-boot/tools/mkimage -T script -d /home/pi/workdir/boot.scr /home/pi/workdir/boot.scr.uimg
Target 'kbuild' done

mkdir /home/pi/workdir/modules
Loadable kernel module support is disabled
mkdir -p /home/pi/workdir/modules/lib/modules
touch /home/pi/workdir/modules/lib/modules/dummy
cd /home/pi/workdir/linux && ARCH=arm  make INSTALL_MOD_PATH=/home/pi/workdir/modules firmware_install
Target 'kmodules' done

Target 'external' done

rm -rf /home/pi/workdir/out
mkdir -p /home/pi/workdir/out
Target 'build' done

sudo UPDATE_SELF=0 SKIP_BACKUP=1 SKIP_REPODELETE=1 SKIP_DOWNLOAD=1 FW_REPOLOCAL=/home/pi/workdir/out rpi-update '2014-06-11 20:14:20 +0000'
 *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
 *** Running pre-install script
     Work around rpi-update issue #106
 *** Updating firmware
 *** Updating kernel modules
 *** Updating VideoCore libraries
 *** Using HardFP libraries
 *** Updating SDK
 *** Running ldconfig
 *** Storing current firmware revision
 *** Running post-install script
     /lib/firmware
 *** Deleting downloaded files
 *** Syncing changes to disk
 *** If no errors appeared, your firmware was successfully updated to 2014-06-11 20:14:20 +0000
 *** A reboot is needed to activate the new firmware
Target 'install' done

$ sudo reboot
$ uname -a
Linux raspberrypi 3.15.0 #1 Wed Jun 11 20:03:03 UTC 2014 armv6l GNU/Linux

The result is in workdir/out

Default rpi Linux with builtin IPV6 on the Raspberry Pi itself.

Install the default rpi Linux with IPv6 support built into the kernel proper (kernel.img)

It will download the kernel source that matches the latest raspberrypi/firmware release.

Start menuconfig and change: Networking support --> Networking options --> The IPv6 protocol : Press y which makes the M a star, then Exit

$ rpi-build use[stdlib] rpi_linux menuconfig

Show the configuration changes

$ rpi-build use[stdlib] rpi_linux diffconfig
 IPV6 m -> y

Build and install (this takes ~11 hours)

$ rpi-build use[stdlib] rpi_linux install
$ sudo reboot
$ uname -a
Linux raspberrypi 3.12.21+ #1 PREEMPT Thu Jun 12 09:18:29 UTC 2014 armv6l GNU/Linux
$ ping6 -c1 ::1 | grep from
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.177 ms

IPv6 kernel built on Ubuntu 12.04

Task: Release a kernel based on the offical one with IPv6 built into the kernel proper.

Building takes ~40mins on my old quad core machine.

Install ruby: sudo apt-get install ruby1.9.1
Install rpi-build and run it to install dependencies.
Configure git:

git config --global user.name "your name"
git config --global user.email "your email"

Create a github repo with a README so it can be cloned (Initialize this repository with a README).
Used in this example: https://github.com/notro/rpi-build-test

Create a release directory

mkdir ipv6; cd ipv6

Clone the firmware repo (the name 'rpi-firmware' let's rpi-build pick it up automatically as FW_REPO)

git clone https://github.com/notro/rpi-build-test rpi-firmware

Create file: Rakefile

require 'stdlib/rpi-linux'

package :ipv6 do
  # use late variable expansion, because 'KERNEL_RELEASE' is set during the build target
  Readme.desc { "Linux kernel release #{VAR['KERNEL_RELEASE']} with builtin IPv6 support for the Raspberry Pi." }
  # IPV6 builtin
  config 'IPV6', :enable
end

release :ipv6_linux => [:rpi_linux_common, :ipv6] do
  Readme.body = """
Changelog
---------
No changes, first release.
"""
  # used by the commit target
  # single empty line between subject and body (if a body is needed).
  # Formatting suggestion: http://stackoverflow.com/questions/2290016/git-commit-messages-50-72-formatting
  ENV['COMMIT_MESSAGE'] = """Linux kernel with builtin IPv6 support

Based on the offical kernel.
"""
end

Build

$ rpi-build log ipv6_linux build
Temporary logfile: /tmp/rpi-build20140603-7377-ebrpf5.log

$ head workdir/build.log
Start: 2014-06-12 15:23:04 +0200

Commandline arguments: log ipv6_linux build

Workdir: /home/pi/ipv6/workdir

$ tail workdir/build.log
Target 'build' done

End: 2014-06-12 15:59:53 +0200

Then we test the kernel before we release it:

$ rpi-build ipv6_linux install SSHIP=<ip address of Raspberry Pi>

cd /home/pi/ipv6/workdir/out; tar -zcf /home/pi/ipv6/workdir/archive.tar.gz *
Target 'archive' done

sshpass -e ssh -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no  [email protected] "rm -rf rpi-build-archive; mkdir rpi-build-archive"
cat /home/pi/ipv6/workdir/archive.tar.gz | sshpass -e ssh -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no  [email protected] "cd rpi-build-archive; tar zxvf -"
Target 'transfer' done

sshpass -e ssh -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no  [email protected] "stat --printf=%Y /usr/bin/rpi-update"
sshpass -e ssh -o LogLevel=quiet -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no  [email protected] "sudo UPDATE_SELF=0 SKIP_BACKUP=1 SKIP_REPODELETE=0 SKIP_DOWNLOAD=1 FW_REPOLOCAL=rpi-build-archive rpi-update '2014-06-12 13:41:53 +0200' 1>&2"
 *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
 *** Running pre-install script
     Work around rpi-update issue #106
 *** Updating firmware
 *** Updating kernel modules
 *** depmod 3.12.21+
 *** Updating VideoCore libraries
 *** Using HardFP libraries
 *** Updating SDK
 *** Running ldconfig
 *** Storing current firmware revision
 *** Running post-install script
     /lib/firmware
 *** Deleting downloaded files
 *** Syncing changes to disk
 *** If no errors appeared, your firmware was successfully updated to 2014-06-12 13:41:53 +0200
 *** A reboot is needed to activate the new firmware
Target 'install' done

On the Pi:

$ cat /boot/.firmware_revision
2014-06-12 16:09:13 +0200
$ sudo reboot
$ uname -a
Linux raspberrypi 3.12.21+ #1 PREEMPT Thu Jun 12 15:56:02 CEST 2014 armv6l GNU/Linux

Release it

$ rpi-build ipv6_linux commit
Workdir: /home/pi/ipv6/workdir
Target 'readme' done

rm -rf /home/pi/ipv6/rpi-firmware/*
cp -a /home/pi/ipv6/workdir/out/* /home/pi/ipv6/rpi-firmware
rm -rf /home/pi/ipv6/rpi-firmware/modules/*/{source,build}
cp /home/pi/ipv6/workdir/build.log /home/pi/ipv6/rpi-firmware
cd /home/pi/ipv6/rpi-firmware && git checkout -q master
cd /home/pi/ipv6/rpi-firmware && git add .
cd /home/pi/ipv6/rpi-firmware && git commit -a -m "Linux kernel with builtin IPv6 support

Based on the offical kernel.
"
Target 'commit' done

$ rpi-build ipv6_linux push
Workdir: /home/pi/ipv6/workdir

cd /home/pi/ipv6/rpi-firmware && git checkout -q master
cd /home/pi/ipv6/rpi-firmware && git rev-parse --abbrev-ref HEAD
cd /home/pi/ipv6/rpi-firmware && git push origin master
Username for 'https://github.com': notro
Password for 'https://[email protected]':
To https://github.com/notro/rpi-build-test
   459cda3..9e2d5cd  master -> master
Target 'push' done

$ cd rpi-firmware
$ git status
# On branch master
nothing to commit (working directory clean)
$ git log
commit 9e2d5cd1eefaf0673fde1ae0204f1af5fd1a7df9
Author: notro <[email protected]>
Date:   Thu Jun 12 16:11:45 2014 +0200

    Linux kernel with builtin IPv6 support

    Based on the offical kernel.

commit 459cda3d5607b237ebbb4daf8438824a42f8d396
Author: notro <[email protected]>
Date:   Thu Jun 12 15:13:33 2014 +0200

    Initial commit

Then as a last test on the Pi:

$ sudo REPO_URI=https://github.com/notro/rpi-build-test rpi-update
$ cat /boot/.firmware_revision
9e2d5cd1eefaf0673fde1ae0204f1af5fd1a7df9
$ sudo reboot
$ uname -a
Linux raspberrypi 3.12.21+ #1 PREEMPT Thu Jun 12 15:56:02 CEST 2014 armv6l GNU/Linux

IPv6 kernel version 3.15 on the 'latest' branch

Here we build on the previous example and add a 'latest' branch to our firmware repo.

Add to Rakefile

release :ipv6_linux_latest => [:rpi_linux_common, :ipv6] do
  VAR['RASPBERRYPI_LINUX_BRANCH'] = raspberrypi_linux_latest
  info "RASPBERRYPI_LINUX_BRANCH = #{ENV['RASPBERRYPI_LINUX_BRANCH']}"
  # notro/rpi-build-test branch
  VAR['FW_BRANCH'] = 'latest'

  Readme.body = """
Changelog
---------
No changes, first release.
"""
  # use late variable expansion, KERNEL_RELEASE is not set yet
  VAR.default('COMMIT_MESSAGE') { """Linux kernel with builtin IPv6 support

Based on the offical kernel #{VAR['KERNEL_RELEASE']}
""" }
end

Clean (delete workdir), build and commit

$ rpi-build log ipv6_linux_latest commit clean

RASPBERRYPI_LINUX_BRANCH = rpi-3.15.y

Push

$ rpi-build ipv6_linux_latest push
cd /home/pi/ipv6/rpi-firmware && git push origin latest
Username for 'https://github.com': notro
Password for 'https://[email protected]':
To https://github.com/notro/rpi-build-test
 * [new branch]      latest -> latest
Target 'push' done

$ cd rpi-firmware
$ git branch
* latest
  master
$ git log -1
commit 793e1819ebe37b6e13dc24b7cdedf8e0e897ae2e
Author: notro <[email protected]>
Date:   Thu Jun 12 16:53:32 2014 +0200

    Linux kernel with builtin IPv6 support

    Based on the offical kernel 3.15.0+

Install on the Pi

$ sudo REPO_URI=https://github.com/notro/rpi-build-test BRANCH=latest rpi-update
$ cat /boot/.firmware_revision
793e1819ebe37b6e13dc24b7cdedf8e0e897ae2e
$ sudo reboot
$ uname -a
Linux raspberrypi 3.15.0+ #1 PREEMPT Thu Jun 12 16:50:44 CEST 2014 armv6l GNU/Linux

Show diff use

In this example I will show how to use the diff target.

Rakefile

require 'stdlib/rpi-linux'

release :hello_linux => :rpi_linux_common do
  # This can be used instead of the diffprep task
  # ENV['DIFFPREP'] = 'linux'

  # When doing a lot of building, I don't want to unpack tools everytime, so I have unpacked it elsewhere
  ENV['CROSS_COMPILE'] = '/home/pi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-'

  target :patch do
    insert_before workdir('linux/arch/arm/mach-bcm2708/bcm2708.c'), '	vc_cma_early_init();', <<'EOM'
	printk("Hello from %s()\n", __func__);
EOM
  end
end

Fetch, unpack, patch and prepare for diff

$ rpi-build hello_linux diffprep patch

Add to workdir/linux/arch/arm/mach-bcm2708/bcm2708.c in bcm2708_init_led()

	printk("Hello from %s()\n", __func__);

diff against 'unpack'

$ rpi-build hello_linux diff

Show

$ cat workdir/linux-unpack.patch
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 95a47fa..5fb7a9e 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -778,6 +778,7 @@ void __init bcm2708_init(void)
        int i;

 #if defined(CONFIG_BCM_VC_CMA)
+       printk("Hello from %s()\n", __func__);
        vc_cma_early_init();
 #endif
        printk("bcm2708.uart_clock = %d\n", uart_clock);
@@ -983,6 +984,7 @@ static struct platform_device bcm2708_led_device = {

 static void __init bcm2708_init_led(void)
 {
+       printk("Hello from %s()\n", __func__);
   bcm2708_leds[0].gpio = disk_led_gpio;
   bcm2708_leds[0].active_low = disk_led_active_low;
   platform_device_register(&bcm2708_led_device);

diff against 'patch'

$ rpi-build hello_linux diff[patch]

Show

$ cat workdir/linux-patch.patch
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 99f511d..5fb7a9e 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -984,6 +984,7 @@ static struct platform_device bcm2708_led_device = {

 static void __init bcm2708_init_led(void)
 {
+       printk("Hello from %s()\n", __func__);
   bcm2708_leds[0].gpio = disk_led_gpio;
   bcm2708_leds[0].active_low = disk_led_active_low;
   platform_device_register(&bcm2708_led_device);

Install

$ rpi-build hello_linux install SSHIP=<ip>

Result

$ dmesg | grep Hello
[    0.031375] Hello from bcm2708_init()
[    0.031980] Hello from bcm2708_init_led()