Makefile
The src/Makefile is how PicoLisp builds itself. When I first studied it (2016–17) it was the pil32 Makefile: gcc -m32 compiling main.c, gc.c and the rest. Today’s pil21 Makefile (26.9, dated 13mar26) is reproduced in full below, and it tells a very different story.
What the pil21 build does
flowchart LR L["src/*.l (PicoLisp)"] -- "pil lib/llvm.l" --> IR["base.ll (LLVM IR)"] IR -- "opt -O2" --> BC[base.bc] C["lib.c + pico.h"] -- "clang -emit-llvm" --> LBC[lib.bc] BC --> LINK["llvm-link -> picolisp.bc"] LBC --> LINK LINK -- "llc + clang" --> BIN[bin/picolisp]
- PicoLisp compiles PicoLisp.
$(PIL) lib/llvm.l lib/ex.l main.l -bye > base.llruns the LLVM front end (src/lib/llvm.l) over the interpreter’s sources and writes LLVM IR. - Bootstrapping. The tarball ships the generated
.llfiles. The line$(shell $(PIL) -bye 2>/dev/null || touch *.ll)checks whether a working../pilexists yet. If it doesn’t, it marks the.llfiles as up to date, so the very first build needs only LLVM, not PicoLisp. opt -O2optimises the IR.lib.c(the small C helper layer, see pico.h) is compiled to bitcode with clang,llvm-linkjoins both, andllcplusclangproduce the nativebin/picolisp, linked with readline and libffi.- The same route builds
lib/ext.soandlib/ht.so. Plain C tools follow:bin/httpGateandbin/ssl(with-lssl -lcrypto),bin/balance, andlib/sysdefs(fromsysdefs.c, which records the OS’s struct sizes and constants fornative). make sobuilds PicoLisp as a shared library (lib/picolisp.so) for embedding.- There are separate
Makefile.macosandMakefile.openbsd. The LLVM version is detected withllvm-config; versions 15–16 get-opaque-pointers.
Using it
sudo apt install binutils make clang llvm libreadline-dev libffi-dev libssl-dev pkg-config
cd pil21/src
make # everything
make clean # remove *.ll *.bc *.s (careful: you then need a working pil to rebuild)
Compare the two Makefiles and you can see the whole history of PicoLisp: from hand-written C, to a home-made assembler (pil64), to letting LLVM do the machine-specific work so that PicoLisp runs anywhere LLVM does.
The pil21 Makefile (26.9)
# 13mar26 Software Lab. Alexander Burger
.SILENT:
CC = clang
PIL = ../pil
ASM = opt -O2
LLC = llc
LINK = llvm-link
SHARED = -shared
STRIP = strip
$(shell $(PIL) -bye 2>/dev/null || touch *.ll)
LLVM = $(shell llvm-config --version | cut -d. -f1)
ifeq ($(shell test $(LLVM) -ge 15 -a $(LLVM) -lt 17; echo $$?), 0)
ASM += -opaque-pointers
endif
OS = $(shell uname)
CPU = $(shell uname -m)
BIN = ../bin
LIB = ../lib
INC = lib/llvm.l vers.l defs.l glob.l dec.l
SRC = main.l gc.l big.l sym.l io.l db.l apply.l flow.l subr.l
all: $(LIB)/sysdefs $(BIN)/picolisp $(LIB)/ext.so $(LIB)/ht.so $(BIN)/balance $(BIN)/ssl $(BIN)/httpGate
so: $(LIB)/picolisp.so
# System definitions
$(LIB)/sysdefs: sysdefs.c
$(CC) -w -D_OS='"$(OS)"' -D_CPU='"$(CPU)"' sysdefs.c && ./a.out > $(LIB)/sysdefs && rm ./a.out
# Base system
$(BIN)/picolisp: picolisp.bc
mkdir -p $(BIN)
$(LLC) picolisp.bc -relocation-model=pic -o picolisp.s
$(CC) picolisp.s -o $(BIN)/picolisp -rdynamic -lc -lutil -lm -ldl `pkg-config --libs readline libffi`
$(STRIP) $(BIN)/picolisp
picolisp.bc: base.bc lib.bc
$(LINK) -o picolisp.bc base.bc lib.bc
base.bc: base.ll
$(ASM) -o base.bc base.ll
base.ll: $(INC) $(SRC) lib/ex.l
$(PIL) lib/llvm.l lib/ex.l main.l -bye > base.ll
mv base.map $(LIB)/map
lib.bc: pico.h lib.c
$(CC) -O3 -w -c -o lib.bc -D_OS='"$(OS)"' -D_CPU='"$(CPU)"' `pkg-config --cflags libffi` -emit-llvm lib.c
# Base system as shared library
$(LIB)/picolisp.so: picolisp.so.bc
$(LLC) picolisp.so.bc -relocation-model=pic -o picolisp.so.s
$(CC) picolisp.so.s -o $(LIB)/picolisp.so $(SHARED)
$(STRIP) $(LIB)/picolisp.so
picolisp.so.bc: base.so.bc lib.so.bc
$(LINK) -o picolisp.so.bc base.so.bc lib.so.bc
base.so.bc: base.so.ll
$(ASM) -o base.so.bc base.so.ll
base.so.ll: $(INC) $(SRC) lib/so.l
$(PIL) lib/llvm.l -quiche lib/so.l main.l -bye > base.so.ll
rm base.map
lib.so.bc: pico.h lib.so.c
$(CC) -O3 -w -c -fPIC -o lib.so.bc -D_OS='"$(OS)"' -D_CPU='"$(CPU)"' `pkg-config --cflags libffi` -emit-llvm lib.so.c
# Extension libraries
$(LIB)/ext.so: ext.bc
$(LLC) ext.bc -relocation-model=pic -o ext.s
$(CC) ext.s -o $(LIB)/ext.so $(SHARED)
$(STRIP) $(LIB)/ext.so
ext.bc: ext.ll
$(ASM) -o ext.bc ext.ll
ext.ll: $(INC) ext.l
$(PIL) lib/llvm.l ext.l -bye > ext.ll
$(LIB)/ht.so: ht.bc
$(LLC) ht.bc -relocation-model=pic -o ht.s
$(CC) ht.s -o $(LIB)/ht.so $(SHARED)
$(STRIP) $(LIB)/ht.so
ht.bc: ht.ll
$(ASM) -o ht.bc ht.ll
ht.ll: $(INC) ht.l
$(PIL) lib/llvm.l ht.l -bye > ht.ll
# Tools
$(BIN)/balance: balance.c
$(CC) -O3 -w -o $(BIN)/balance balance.c
$(STRIP) $(BIN)/balance
# Gate
$(BIN)/ssl: ssl.c
$(CC) -O3 -w -o $(BIN)/ssl ssl.c -lssl -lcrypto
$(STRIP) $(BIN)/ssl
$(BIN)/httpGate: httpGate.c
$(CC) -O3 -w -o $(BIN)/httpGate httpGate.c -lssl -lcrypto
$(STRIP) $(BIN)/httpGate
# Clean up
clean:
rm -f *.ll *.bc *.s
clean2: clean
rm -f $(LIB)/sysdefs $(BIN)/balance $(BIN)/ssl $(BIN)/httpGate
