Up to Main Index Up to Annexed Works BUILDING GO FROM SOURCE ON A RASPBERRY PI Building Go from source on a Raspberry Pi, especially a Raspberry Pi Zero, can be a challenge. These are notes are from my experience building Go from source on machines with limited resources. These notes are for building a Go source distribution downloaded from https://golang.org and are not about compiling normal user Go code… The original Raspberry Pi Zero, and Zero W, are cheap and tiny computers with limited resources that are capable of running a full Linux distribution. They have a single core BCM2835 32-bit processor running at 1GHz with 512Mb RAM. The storage is usually limited to an SD card, although an SSD or thumb-drive can be attached via the single micro USB port using an OTG adapter. If Go can be built on these diminutive systems, then we should be able to build Go on any model of Raspberry Pi or similar single-board computer. For these notes a Raspberry Pi Zero W was used. The operating system used was an official Raspberry Pi OS image. The version of Go built was Go 1.20.4. The SDCard used was a 16Gb Class 10 A1 SanDisk. A previous installation of Go 1.17.13 was used to build Go 1.20.4. If there is no previous version of Go installed then download and build the latest Go 1.4 release first, which does not require Go to build. Then build Go 1.20.4. Additional information on building Go from source can be found on the official Go website: https://go.dev/doc/install/source Feel free to take and adapt these notes as you see fit. Feedback in the form of comments, improvements or errata is always welcome: diddymus@wolfmud.org ∞ ∞ ∞ The first step should be to setup the RAM reserved for graphics to be as small as possible. This frees up more memory for the operating system and Go build to use. In the /boot/config.txt file, the gpu_mem setting should be set to 16, take note of its current value so it can be restored after the build: gpu_mem=16 A reboot will be required for the change to take effect. Once rebooted, as many background services as possible should be stopped to free up additional memory. Which services are running on your Raspberry Pi will depend on what software has been installed. Logging in to the Raspberry Pi from the console or over SSH, instead of running a graphical interface, is highly recommended. This will free up more memory for the build. The more free memory the quicker the build will be. A small swap space will be provided by a memory backed zram device that compresses and decompresses its content automatically. Setup the swap space, as root, using: >swapoff -a >zramctl --find -a lz4 -s 32M /dev/zram0 >mkswap /dev/zram0 Setting up swapspace version 1, size = 32 MiB (33550336 bytes) no label, UUID=d43824c2-feab-4b48-b162-049d129dbac3 >swapon --priority 100 /dev/zram0 > Note that if the size of the zram device is too large, the build will spend more time swapping to the SDCard as less of the build can be kept in memory. Building Go will require more swap space than is available on the zram device alone. For additional swap space a temporary 1Gb swap file will be used. To create and mount a temporary swap file, as root, use: >dd if=/dev/zero of=/tmpswap bs=1M count=1024 2097152+0 records in 2097152+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 558.15 s, 1.9 MB/s >mkswap /tmpswap Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes) no label, UUID=45122e1d-9bcd-4bf4-81cb-0a5b3aec51ec >swapon /tmpswap > Check the zram and swap file are now being used: >swapon -s Filename Type Size Used Priority /dev/zram0 partition 32764 0 100 /tmpswap file 1048572 0 -2 > This allows frequent small swaps to memory with only the overflow going to the SDCard. This should speed up the build and help preserve the SDCard. A temporary directory will be needed for the build. As /tmp is normally mapped to tmpfs and memory backed, /tmp is unsuitable. Instead a temporary directory in the user’s home directory is used. As a normal user: >mkdir ~/tmp > The Go source code should be downloaded and unpacked into a directory named as per the release being built. In this case go1.20.4: >cd ~ >mkdir go1.20.4 >cd go1.20.4 >tar --strip-components=1 -zxf ~/downloads/go1.20.4.src.tar.gz > Note the first release of a Go version is named without a minor number, for example, go1.20.src.tar.gz, in which case the directory used would be go1.20.0 See the later discussion on symlinking for the reasoning for this. By default stacks are created with a size of 8Mb, however the limit can be lowered saving memory during the build. A setting of 1Mb seems to work well. To set, and then check, the initial stack limit, as a normal user: >ulimit -s 1024 >ulimit -s 1024 > To build Go, using the temporary ~/tmp directory, as a normal user: >cd ~/go1.20.4/src >TMPDIR=~/tmp ./all.bash : wait for 9½ hours… : > Once the build has completed, revert the change to /boot/config.txt and set gpu_mem back to its original value and reboot. The changes to swap will be lost and ulimit settings returned to normal. As root the /tmpswap file can also be removed. For myself, ~/golang is a symlink to a major Go version, in this case Go 1.20, and this is a symlink to the latest minor Go version, in this case Go 1.20.4: lrwxrwxrwx 1 me me 9 Nov 10 14:58 go1.17 -> go1.17.13 drwxr-xr-x 10 me me 4096 Dec 1 16:39 go1.17.13 lrwxrwxrwx 1 me me 6 Feb 7 14:14 /home/me/golang -> go1.20 lrwxrwxrwx 1 me me 8 May 2 20:34 go1.20 -> go1.20.4 drwxr-xr-x 10 me me 4096 May 2 20:11 go1.20.4 ~/golang/bin is added to the PATH environment variable in ~/.bashrc and uses the Go version ~/golang currently points to: export PATH=~/bin:$PATH:~/golang/bin This allows switching between Go major/minor versions easily by changing the symlinks. For example to switch switch from Go 1.20.4 to Go 1.17.13: >go version go version go1.20.4 linux/arm >rm golang >ln -s go1.17 golang >go version go version go1.17.13 linux/arm > For each new Go release the build is put into a go1.x.x and the go1.x symlink added or updated. The golang symlink is only updated for new go1.x releases, or if I need a specific version of Go for testing. These are the build times, including running all the tests, on different Raspberry Pi models and a desktop machine: System/OS/Memory Time Configuration ------------------- -------- ------------------------ RPi0 32-bit 512Mb: 09:23:28 tmpdir, ulimit, swapfile RPI3 32-bit 1Gb: 51:49 tmpdir, ulimit, swapfile RPi4 32-bit 4Gb: 24:03 tmpdir RPi4 64-bit 8Gb: 26:31 tmpdir Desktop 64-bit 8Gb: 11:29 The desktop used was an Intel i5-2400 quad core @3.1Ghz with 8Gb RAM. -- Diddymus Up to Main Index Up to Annexed Works