Using a RaspberryPi is fun and easy! Just like with any adventure heroes and heroines follow their paths to glory and fight minor beasts with foreign names like Nginx and Hugo. However sometimes they come across beasts that make up nightmares. One of those bears the name 'Crosscompile'.
Storytelling aside, crosscompiling always filled me with fear because it seemed to be so complicated and error prone. Introduce Go! Go seems to make crosscompiling really really easy. While setting up some infrastructure I thought that I should give some hosted GitHub contender a shot. Immediately I looked up what GitLab had to offer and was disappointed that the internet basically says that its Free tier is somewhat crippled and that the software is resouce hungry in general. Not good for a Pi. Digging further Gogs and its fork Gitea came up next. Gitea's feature comparison site made it look better compared to Gogs so that's what I settle with for now.
Gitea was forked of Gogs in 2016 and both are written in Go. Having a single binary wrapping up all the core code and its dependencies is a wind of fresh air to me after years of complex Java, Python and PHP projects. The package repositories of my Raspbian Buster offer a Go 1.11 (current as of writing: 1.13) package and no gitea so I chose to install both manually. The Go distribution offered here works pretty much out of the box when following the install instructions. Gitea's current version is 1.10.0 and they provide binaries for alot of architectures including ARMv5 and ARMv6. My Raspberry Pi is ARMv7 but Gitea stopped providing binaries for that with Release 1.8.0. Luckily ARMv7 is backwards compatible so I can run the ARMv6 binary. I tried to run it, just to be greeted with a Segmentation fault immediately... Trying previous releases didn't work neither. I found a GitHub Issue #3271 which sounds familiar with my situation but I didn't feel patience enough to follow that path.
I downloaded the Gitea source as described in the Installation from source reference and tried to build it directly on the Pi. Things started to look good when there were no immediate errors and the compile process did its work for a couple of minutes keeping me up-to-date with some status output. I tracked the resource consumption: CPU load pretty high, RAM had a couple megabytes free. Nothing to worry about. After a few minutes AFK I returned to my session to discover that my terminal froze up. I pinged the Pi and it happily answered within a millisecond, no lost packets in minutes. Knowing the scarce resources of that board I said to myself that I should give it some time while monitoring the pings. Maybe it'd finish compile... It didn't.
Disappointed by the Pi's repeated failures to compile real-world projects I looked for new ways to fight the beast. Initially I thought of setting up a compile cluster run by distcc consisting of my laptops, my desktop machine and the Pi. The other option is crosscompiling the sources on a amd64 machine to ARMv7. Coincidentally setting up a compile cluster includes setting up the required crosscompile toolchains foreach combination of architecture between master and slaves, therefore a toolchain from amd64 to ARMv7...
Still being impatient I cancelled the distcc experiment and search for instructions how to crosscompile a Go binary and I stumbled over a handful articles which looked quite good in general. Most of them looked like this:
$ env GOOS=${TARGET_OS} GOARCH=${TARGET_ARCHITECTURE} make generate buildThat's it. A single build invocation with two environment variables set resulting in a binary which is perfectly able to run on the specified architecture!
Gitea however did not play along nicely when I tried to apply the above to my build of Gitea 1.10.0 for ARMv7 on a amd64 machine:
GO111MODULE=on go generate -mod=vendor [[lots of packages to build, omitted for readibility]]
fork/exec /tmp/go-build227287077/b001/exe/main: exec format error
modules/options/options.go:7: running "go": exit status 1
fork/exec /tmp/go-build183690092/b001/exe/main: exec format error
modules/public/public.go:21: running "go": exit status 1
fork/exec /tmp/go-build772474565/b001/exe/main: exec format error
modules/templates/templates.go:7: running "go": exit status 1
Makefile:102: recipe for target 'generate' failed
make: *** [generate] Error 1Searching the internet again for instructions how to apply extra crosscompile-fairy-dust to Gitea resulted in #7149 issue. Kudos to sapk for providing the correct information.
The Gitea source needs to be massaged via go generate without the crosscompilation environment variables first. Next we can build the binary for the target architecture.
$ make generate
$ env GOOS=linux GOARCH=arm GOARM=7 TAGS="bindata" make build$ file ./gitea
./gitea: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=h9RD9VL6olgt11cIx9Zu/p6AnFAzcl0jeK_YVt595/wp57ui5pSk9xMq4SLCiY/dWlUM83_sURlHvHilueb, stripped