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
requireslibmotif-dev
--with-x-toolkit=lucid
requireslibxaw7-dev
being installed--with-xft
requires installinglibxft-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 integermodules
I'm not sure what it does (something something dynamic modules something something), but it's highly recommendedjson
for native JSON librariesthreads
uses pthreadscompress-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
I may want to consider looking at other window managers (ahem, window shopping?).
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
- CCL on RPi (French)
- This Old Lisp
- CCL on Raspberry Pi, Rainer's tutorial/notes
- Christophe Rhodes on Lisp
- Lisp on Raspberry Pi, Part 2