\( \newcommand\D{\mathrm{d}} \newcommand\E{\mathrm{e}} \newcommand\I{\mathrm{i}} \newcommand\bigOh{\mathcal{O}} \newcommand{\cat}[1]{\mathbf{#1}} \newcommand\curl{\vec{\nabla}\times} \newcommand{\CC}{\mathbb{C}} \newcommand{\NN}{\mathbb{N}} \newcommand{\QQ}{\mathbb{Q}} \newcommand{\RR}{\mathbb{R}} \newcommand{\ZZ}{\mathbb{Z}} \)
UP | HOME

Raspberry Pi

Table of Contents

1. Overview

I've got a Raspberry Pi 3 lying around, and I've been interested in Lisp Machines for a bit. Daniel Szmulewicz wrote a blog post on treating a Raspberry Pi as an ersatz Lisp Machine. Since my machine is on the older side, and has been lying around for a while (it still runs Debian Jessie), I thought I'd document my attempt to update it and install Lisp tools on it.

(Apparently I have a Raspberry Pi 2.)

2. Ssh into the Pi

We can ssh into Raspberry Pi by enabling ssh (the openssh-server seems to be installed but not yet enabled), then we can simply do ssh <user>@raspberrypi.local to

3. Debian Infrastructure

Running the update can be time-consuming. Basically I updated the /etc/apt/sources.list and /etc/apt/sources.list.d/raspi.list to use the stretch repositories, uninstalled a few un-needed (or unused) packages (scratch*, minecraft-pi, libreoffice*, sonic-pi), ran a sudo apt-get update && sudo apt-get upgrade -y && sudo apt clean followed by a sudo apt-get dist-upgrade -y && sudo apt-get clean. This took a few hours.

Then I ran sudo rpi-update to update the firmware.

3.1. Optimizing for my local computer

I noticed that, for GCC, the flag -Os optimizes for size. Since there's only so little room for things on the Pi, I decided to install apt-build and these go into /etc/apt/apt-build.conf, then I can use sudo apt-build install ... instead of apt-get.

3.2. Upgrading to Bullseye

I didn't want to start from scratch, so I simply did the following:

~$ cd /etc/apt/
/etc/apt$ sudo cp sources.list sources.list.bak
/etc/apt$ sudo nano sources.list

Then I made sources.list look like (replacing all instances of "buster" by "bullseye"):

# sources.list
deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi

I saved it, closed nano, then ran the commands:

/etc/apt$ sudo apt update
...
/etc/apt$ sudo apt upgrade -y
...
/etc/apt$ sudo apt dist-upgrade -y
...
/etc/apt$ sudo apt autoclean
...
/etc/apt$ sudo reboot

4. Installing Emacs

I pulled down Emacs from the git repository:

~/$ cd src
~/src/$ # for just one version without updating to another, run:
~/src/$ # git clone --depth 1 --branch emacs-27 https://git.savannah.gnu.org/git/emacs.git
~/src/$ # otherwise, run:
~/src/$ git clone https://git.savannah.gnu.org/git/emacs.git
...
~/src/$ cd emacs
~/src/emacs/$ sudo apt-get build-dep emacs

We need to install the GNU-Autotools:

~/src/emacs/$ sudo apt-get install autoconf automake

We can try installing the dependencies, but will also have to install the dev version of the libraries:

~/src/emacs/$ sudo apt-get build-dep emacs
...
~/src/emacs/$ sudo apt-get install libm17n-dev libgif-dev libxpm-dev libtiff5-dev
...
~/src/emacs/$ sudo apt-get install libpng-dev gnutls-dev texinfo libjansson-dev
...
~/src/emacs/$ sudo apt-get install build-essential libx11-dev libjpeg-dev libpng-dev libgif-dev libxaw-dev libncurses-dev libgnutls28-dev
...

Now for the configuration

~/src/emacs/$ ./autogen.sh
~/src/emacs/$ ./configure --with-x-toolkit=no --with-m17n-flt --with-modules CFLAGS="-mtune=native -mcpu=native -Os -marm"

If you configure with -Ofast you need to also include -fno-finite-math-only too (or else when you run make, you'll get an error saying Emacs won't compile with -ffinite-math-only).

4.1. Attempting Configuration

~/src/emacs/$ git clean -dxf
~/src/emacs/$ ./autogen.sh
~/src/emacs/$ ./configure --with-m17n-flt --with-modules --with-json --with-threads --with-included-regex --with-compress-install CFLAGS="-Ofast -mtune=native -mcpu=native -marm"

I also need to make sure I have libncurses-dev installed and, depending on the configuration choices:

  • --with-x-toolkit=motif requires libmotif-dev
  • --with-x-toolkit=lucid requires libxaw7-dev being installed
  • --with-xft requires installing libxft-dev

4.1.1. Installation

~/src/emacs/$ make
...
~/src/emacs/$ sudo make install
...
~/src/emacs/$

4.1.2. For Emacs 28

After tinkering around, Emacs 28 came out! Unfortunately, the above commands clone exactly the emacs-27 branch, and makes it impossible to change to the emacs-28 branch.

~/src/ $ git clone https://git.savannah.gnu.org/git/emacs.git
~/src/ $ cd emacs
~/src/emacs/ $ git checkout emacs-28
~/src/emacs/ $ sudo apt install libgccjit-10-dev libharfbuzz-dev
~/src/emacs/ $ ./configure --with-wide-int --with-x-toolkit=lucid --with-gnutls=ifavailable --with-m17n-flt --with-modules --with-json --with-threads --with-compress-install CFLAGS="-O3 -pipe -mtune=native -mcpu=native -marm"
...
~/src/emacs/ $ make
...
~/src/emacs/ $

I wanted to include the option --with-native-compilation but it creates segmentation faults. For this reason, I ended up leaving it off. It could be some issue with the version of the library, or something. (Note: if you are using GCC version 10, this will work. If you are using version X, you need to install libgccjit-X-dev.)

  • wide-int uses a 60-bit integer instead of a 32-bit integer
  • modules I'm not sure what it does (something something dynamic modules something something), but it's highly recommended
  • json for native JSON libraries
  • threads uses pthreads
  • compress-install
  • CFLAGS="-O3 -mtune=native -mcpu=native -marm" for additional optimizations

4.2. Improving Startup Time

I noticed the startup time was rather slow. The (emacs-init-time) reports it took 10.46182 seconds without optimization for my default init file. (My laptop with two Intel Core2 duos, at 2.80GHz, reports a 3.065432256 second init-time.)

Setting gc-cons-threshold to 10000000 improved performance by about 40%, (emacs-init-time) reduces to 6.671090814 seconds. Bumping it up to 108 barely improves performance, (emacs-init-time) reports 6.44 seconds.

I changed all the (require 'foo) calls to (use-package foo :ensure t :defer t), which improved startup time by about a couple of second (4.426073247 seconds).

This is all done with emacs compiled -Os; if I instead did -O3, redid the byte-compilation of init.el, I get startup time in 3.67300 seconds. If I further compiled with -Ofast, I get startup time in 3.713 seconds.

4.2.1. Emacs 28

For the configuration given above for Emacs 28, the startup is significantly faster. With the options given, but a blank .emacs file, I have (emacs-init-time) report "1.252132 seconds".

When my ./.emacs file just consists of (load-file "~./.emacs.d/init.el"), I have (emacs-init-time) report "1.221768 seconds".

When I byte-compile my init.el and my ./.emacs file just consists of (load-file "~./.emacs.d/init.elc"), I have (emacs-init-time) report "1.157587 seconds".

4.3. Emacs 29

For my Desktop, I tried:

$ ./configure --with-wide-int --with-x-toolkit=lucid --with-gnutls=ifavailable --with-m17n-flt --with-modules --with-json --with-threads --with-compress-install "CFLAGS=-O3 -pipe -mtune=native -march=native -fno-finite-math-only"

4.4. Checking Build Flags

If you have Emacs already, you can check what flags you enabled when you last ran ./configure by examining the variable system-configuration-options.

5. Installing Common Lisp

I'm not sure what happened, but somehow I had SBCL 1.4 installed on my Raspberry Pi already. I was suspicious of this, and remain so to date.

5.1. Clozure Common Lisp

One Common Lisp compiler which emerged from the '80s was Clozure Common Lisp. Well, it was forked from Macintosh Common Lisp, which ran on a computer with only a few Megabytes of RAM at the time. We have similar constraints for the Raspberry Pi today (at least, I do).

I followed Rainer's instructions .

~/src/$ git clone https://github.com/Clozure/ccl/
...
~/src/$ cd ccl/
~/src/ccl/$ git checkout v1.12-dev.1
~/src/ccl/$ cd lisp-kernel/linuxarm
~/src/ccl/lisp-kernel/linuxarm/$ make clean; make
...
~/src/ccl/lisp-kernel/linuxarm/$ cd ../..
~/src/ccl/$ ./scripts/get-binaries linuxarm
...
~/src/ccl/$ ./armcl

? (ccl:rebuild-ccl :full t)
...

There is a bug with optimizers.lisp which hangs on master branch. It should take less than a minute to finish optimizers.lisp, so if it's taking longer…it's probably a bug. (I have found the v1.12-dev.1, v1.12-dev.2, v1.12-dev.3, v1.12-dev.4 tags are capable of rebuilding as expected.)

The armcl binary is 633788 bytes initially, and the armcl.image is 22347792 bytes big. After rebuilding v1.12-dev.1, the binary is the same size, but the armcl.image is 17100816 bytes (and in v1.12-dev.4, 17158160 bytes).

5.1.1. Making armcl global

I also ran

~/src/$ sudo ln -s /home/alex/src/ccl/armcl /usr/local/bin/armcl

This let me run armcl for any user.

5.2. SBCL

Now, Raspberry Pi offers SBCL 2.1.9, which installs without problem. Wonderful! I don't need to stress over compiling CCL properly.

5.2.1. Compiling SBCL Problems

I run into a problem compiling SBCL from the RPi package, experiencing an error (as of git commit b430f314c, date Wed Apr 20 03:46:44 2022 +0300):

~/src/sbcl $ sh make.sh
...
cc -g -Wall -Wundef -Wsign-compare -Wpointer-arith -O3 -std=gnu99 -fno-pie -I.  -c -o os-common.o os-common.c
In file included from os-common.c:24:
genesis/symbol.h: In function 'symbol_package_id':
genesis/symbol.h:44:72: warning: right shift count >= width of type [-Wshift-count-overflow]
   44 | nline int symbol_package_id(struct symbol* s) { return s->name >> 48; }
      |                                                                ^~

In file included from os-common.c:26:
thread.h: In function 'tls_index_of':
thread.h:151:25: warning: right shift count >= width of type [-Wshift-count-overflow]
  151 |   return symbol->header >> 32;
      |                         ^~
In file included from os-common.c:85:
sys_mmap.inc: In function 'sbcl_mmap':
sys_mmap.inc:26:27: error: 'SYS_mmap' undeclared (first use in this function); did you mean 'SYS_mmap2'?
   26 |     return (void*)syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
      |                           ^~~~~~~~
      |                           SYS_mmap2
sys_mmap.inc:26:27: note: each undeclared identifier is reported only once for each function it appears in
In file included from target-os.h:32,
                 from os.h:59,
                 from globals.h:19,
                 from os-common.c:18:
os-common.c: In function 'os_context_pc':
target-arch-os.h:13:52: error: 'mcontext_t' has no member named 'pc'
   13 | #define OS_CONTEXT_PC(context) context->uc_mcontext.pc
      |                                                    ^
os-common.c:349:12: note: in expansion of macro 'OS_CONTEXT_PC'
  349 |     return OS_CONTEXT_PC(context);
      |            ^~~~~~~~~~~~~
os-common.c: In function 'set_os_context_pc':
target-arch-os.h:13:52: error: 'mcontext_t' has no member named 'pc'
   13 | #define OS_CONTEXT_PC(context) context->uc_mcontext.pc
      |                                                    ^
os-common.c:352:5: note: in expansion of macro 'OS_CONTEXT_PC'
  352 |     OS_CONTEXT_PC(context) = pc;
      |     ^~~~~~~~~~~~~
os-common.c: In function 'os_context_pc_addr':
target-arch-os.h:13:52: error: 'mcontext_t' has no member named 'pc'
   13 | #define OS_CONTEXT_PC(context) context->uc_mcontext.pc
      |                                                    ^
os-common.c:355:38: note: in expansion of macro 'OS_CONTEXT_PC'
  355 |     return (os_context_register_t*)&(OS_CONTEXT_PC(context));
      |                                      ^~~~~~~~~~~~~
In file included from os-common.c:85:
sys_mmap.inc: In function 'sbcl_mmap':
sys_mmap.inc:30:1: warning: control reaches end of non-void function [-Wreturn-type]
   30 | }
      | ^
os-common.c: In function 'os_context_pc':
os-common.c:350:1: warning: control reaches end of non-void function [-Wreturn-type]
  350 | }
      | ^
os-common.c: In function 'os_context_pc_addr':
os-common.c:356:1: warning: control reaches end of non-void function [-Wreturn-type]
  356 | }
      | ^
make: *** [<builtin>: os-common.o] Error 1
make: Leaving directory '/home/alex/src/sbcl/src/runtime'
~/src/sbcl $

I think this is because I have arm_64bit=1 in my /boot/config.txt? If I remove it, I run into other problems (SBCL cannot determine the CPU architecture properly).

5.3. Adding Quicklisp

We get quicklisp:

~/$ wget http://beta.quicklisp.org/quicklisp.lisp
...
~/$ armcl
? (load "quicklisp.lisp")
? (quicklisp-quickstart:install)

Then we append to (or create) the file ~/.ccl-init.lisp with the following content:

(defun load-quicklisp ()
  (let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init))))

CAUTION: this will not load quicklisp by default, but require you to call (load-quicklisp) when you need/want it. If you want it loaded by default, you could just add a (load-quicklisp) line to the ~/.ccl-init.lisp file.

6. LaTeX

  • Installing texlive-base will install TeX, pdfTeX, cweb, metapost, and a few other basic TeX packages.
  • texlive-latex-base installs LaTeX

7. Stumpwm

7.1. Dependencies

Trying to run sudo apt-get build-dep stumpwm will install a number of common lisp dependencies, which quicklisp would automatically handle.

8. Window Managers

8.2. FVWM

I have decided to install FVWM, which can be done with sudo apt-get install xserver-xorg xinit fvwm xterm

Whenever I log in, I have to manually start FVWM by the command startx.

As far as customizing FVWM, well, I have yet to do much in that department yet.

8.3. Feh wallpaper

I am using a script

#!/usr/local/bin/bash

sleep 10

while true; do
feh --no-fehbg -F -r --bg-max -z /home/alex/Pictures/Wallpaper && sleep 5 || exit
done

AddToFunc InitFunction

  • I exec home/alex.fvwm/bg.sh

AddToFunc RestartFunction

  • I exec home/alex.fvwm/bg.sh

8.4. URXVT Terminal

Instead of xterm, one could instead install rxvt-unicode which is very nift.

9. Temperature Checking

For my Raspberry Pi 2, I can check the temperature by running the command /opt/vc/bin/vcgencmd measure_temp. I've stuck this into a script:

#!/bin/bash

# ~/temperature.sh

/opt/vc/bin/vcgencmd measure_temp

10. Mizar

10.1. Pre-built Binaries Appear Broken

I couldn't get Mizar working on my Raspberry Pi 2, and it does not work on Raspberry Pi 4B either. Get the latest version here for Linux (ARM).

~/src/$ mkdir mizar
~/src/$ cd mizar
~/src/mizar/$ wget mizar-<version>-arm-linux.tar
...
~/src/mizar/$ tar -xvf mizar-...-linux.tar
...
~/src/mizar/$ sudo ./install.sh
...

When I try running, say, mizf on 32-bit mode, I get errors:

alex@raspberrypi:~/src/mizar-playground $ mizf text/char.miz
Illegal instruction
Illegal instruction
Illegal instruction
alex@raspberrypi:~/src/mizar-playground $

In 64-bit mode, I get errors:

alex@raspberrypi:~/src/mizar-playground $ mizf text/char
/usr/local/bin/mizf: 8: makeenv: Exec format error
/usr/local/bin/mizf: 13: errflag: Exec format error
/usr/local/bin/mizf: 14: addfmsg: Exec format erro

10.2. Building it from Scratch

Fortunately, Roland Coghetto has done heroic work to make it compile on Raspberry Pi. The basic instructions:

Step 1: install Free Pascal.

alex@raspberrypi:~$ sudo apt-get update
alex@raspberrypi:~$ sudo apt-get upgrade
alex@raspberrypi:~$ sudo apt-get install fpc

Step 2: install the Mizar library. We need to install the Mizar library, and to do that we just install the latest version of the Mizar system for, say, the Intel processor. This won't give us a workable binaries, but it installs the MML and documentation locally.

If you tried using the pre-built binaries, then you can skip this step.

alex@raspberrypi:~ $ cd src
alex@raspberrypi:~/src $ mkdir mizar
alex@raspberrypi:~/src $ cd mizar
alex@raspberrypi:~/src/mizar $ wget http://mizar.uwb.edu.pl/~softadm/pub/system/i386-linux/mizar-8.1.12_5.72.1435-i386-linux.tar
alex@raspberrypi:~/src/mizar $ tar xvf mizar-8.1.12_5.72.1435-i386-linux.tar
alex@raspberrypi:~/src/mizar $ sudo bash install.sh

Installation of Mizar System Version 8.1.12 (Linux/FPC) (MML 5.72.1435)
 
Enter the path for installing Mizar executables
[default is /usr/local/bin]
Unpacking to /usr/local/bin
 
Enter the path for installing Mizar shared files
[default is /usr/local/share/mizar]
Unpacking to /usr/local/share/mizar
 
It may take some time...
 
Enter the path for installing Mizar documentation
[default is /usr/local/doc/mizar]
Unpacking to /usr/local/doc/mizar
 
The installation process of the Mizar system is completed.
 
Note:
The Mizar system requires a variable MIZFILES
which should be set to /usr/local/share/mizar.
 
If /usr/local/bin is not in your PATH please add it before running Mizar.
 
With questions or comments contact mus@mizar.uwb.edu.pl

alex@raspberrypi:~/src/mizar $ cd ..
alex@raspberrypi:~/src $

Step 3: download and compile the Mizar source code. Now we download Roland Coghetto's modified version of the Mizar source code (the only changes are adding install instructions, the compile script, and adjusting two parameters in the code) and run the following commands:

alex@raspberrypi:~/src $ git clone https://github.com/CoghettoR/MizarSystem/
alex@raspberrypi:~/src $ cd MizarSystem
alex@raspberrypi:~/src/MizarSystem $ time sh compile_rpi.sh
alex@raspberrypi:~/src/MizarSystem $ cd bin
alex@raspberrypi:~/src/MizarSystem/bin $ sudo cp ./* /usr/local/bin/
alex@raspberrypi:~/src/MizarSystem $

Done! We can have built and installed Mizar locally. Time to celebrate!

11. Run 64-bit mode

To make Raspberry Pi 4 run in 64-bit mode, add the following line to the bottom of your /boot/config.txt:

arm_64bit=1

12. Other Links

Last Updated 2023-09-01 Fri 06:28.