Skip to content

Commit 43ed7eb

Browse files
committed
feat(userland): ported the CPython 3.12 interpreter
1 parent b0a6fe6 commit 43ed7eb

6 files changed

Lines changed: 410 additions & 1 deletion

File tree

userland/apps/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
APP_DIRS := init hello shell ls cat rm stat touch sleep true false clear ptytest date \
66
clockbench stlxdm stlxterm doom ping ifconfig nslookup arp udpecho tcpecho \
77
fetch polltest dropbear blackjack wordle hangman snake tetris \
8-
grep wc head threadtest uname kill cxxtest synctest
8+
grep wc head threadtest uname kill cxxtest synctest python
99
APP_COUNT := $(words $(APP_DIRS))
1010

1111
all:

userland/apps/python/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
src/
2+
build/
3+
dl/
4+
install/

userland/apps/python/Makefile

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
#
2+
# Python Interpreter - Stellux Build
3+
#
4+
# Builds a static CPython interpreter against the Stellux musl sysroot
5+
# and libstlx. Stages python + stdlib into userland/build/$(ARCH)/rootfs.
6+
#
7+
8+
APP_NAME := python
9+
ARCH ?= x86_64
10+
USERLAND_ROOT ?= ../..
11+
override USERLAND_ROOT := $(abspath $(USERLAND_ROOT))
12+
13+
PY_VER := 3.12.8
14+
PY_MAJOR_MINOR := 3.12
15+
PY_TARBALL := Python-$(PY_VER).tar.xz
16+
PY_URL := https://www.python.org/ftp/python/$(PY_VER)/$(PY_TARBALL)
17+
18+
SYSROOT := $(USERLAND_ROOT)/sysroot/$(ARCH)
19+
TARGET_TRIPLE := $(ARCH)-linux-musl
20+
21+
DL_DIR := dl
22+
SRC_ROOT := src
23+
SRC_DIR := $(SRC_ROOT)/Python-$(PY_VER)
24+
BUILD_DIR := build/$(ARCH)
25+
INSTALL_DIR := install/$(ARCH)
26+
27+
ROOTFS_DIR := $(USERLAND_ROOT)/build/$(ARCH)/rootfs
28+
29+
CC := clang
30+
HOST_PYTHON := python3
31+
32+
BUILTINS_LIB := $(shell $(CC) --target=$(TARGET_TRIPLE) --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null)
33+
34+
COMMON_CFLAGS := \
35+
--target=$(TARGET_TRIPLE) \
36+
--sysroot=$(SYSROOT) \
37+
-nostdlibinc \
38+
-isystem $(SYSROOT)/include \
39+
-std=c11 -O2 -g \
40+
-D_GNU_SOURCE \
41+
-D__STELLUX__ \
42+
-fno-stack-protector
43+
44+
COMMON_LDFLAGS := \
45+
-nostdlib \
46+
-fuse-ld=lld \
47+
--target=$(TARGET_TRIPLE) \
48+
--sysroot=$(SYSROOT) \
49+
--rtlib=compiler-rt \
50+
-static
51+
52+
STELLUX_LIBS := \
53+
$(SYSROOT)/lib/crt1.o \
54+
$(SYSROOT)/lib/crti.o \
55+
-L$(SYSROOT)/lib \
56+
-Wl,--start-group \
57+
-lstlx \
58+
-lc \
59+
-lm \
60+
$(BUILTINS_LIB) \
61+
-Wl,--end-group \
62+
$(SYSROOT)/lib/crtn.o
63+
64+
CONFIGURE_STAMP := $(BUILD_DIR)/.configured
65+
BUILD_STAMP := $(BUILD_DIR)/.built
66+
PATCH_STAMP := $(SRC_DIR)/.stellux-patched
67+
68+
.PHONY: all fetch extract patch configure build install verify clean distclean print-vars
69+
70+
all: install
71+
72+
print-vars:
73+
@echo "APP_NAME=$(APP_NAME)"
74+
@echo "ARCH=$(ARCH)"
75+
@echo "USERLAND_ROOT=$(USERLAND_ROOT)"
76+
@echo "SYSROOT=$(SYSROOT)"
77+
@echo "TARGET_TRIPLE=$(TARGET_TRIPLE)"
78+
@echo "SRC_DIR=$(SRC_DIR)"
79+
@echo "BUILD_DIR=$(BUILD_DIR)"
80+
@echo "INSTALL_DIR=$(INSTALL_DIR)"
81+
@echo "ROOTFS_DIR=$(ROOTFS_DIR)"
82+
@echo "BUILTINS_LIB=$(BUILTINS_LIB)"
83+
84+
fetch: $(DL_DIR)/$(PY_TARBALL)
85+
86+
$(DL_DIR)/$(PY_TARBALL):
87+
@mkdir -p $(DL_DIR)
88+
@echo "[FETCH] CPython $(PY_VER)"
89+
@curl -L "$(PY_URL)" -o "$@"
90+
91+
extract: fetch
92+
@if [ ! -d "$(SRC_DIR)" ]; then \
93+
mkdir -p $(SRC_ROOT); \
94+
echo "[EXTRACT] $(PY_TARBALL)"; \
95+
tar -C $(SRC_ROOT) -xf "$(DL_DIR)/$(PY_TARBALL)"; \
96+
fi
97+
98+
patch: extract $(PATCH_STAMP)
99+
100+
$(PATCH_STAMP):
101+
@echo "[PATCH] CPython for Stellux"
102+
@cd $(SRC_DIR) && for p in ../../patches/*.patch; do \
103+
if [ -f "$$p" ]; then \
104+
echo " applying $$p"; \
105+
patch --forward --batch -p1 < "$$p"; \
106+
fi; \
107+
done
108+
@cp Modules.Setup.local $(SRC_DIR)/Modules/Setup.local
109+
@touch $@
110+
111+
configure: $(CONFIGURE_STAMP)
112+
113+
$(CONFIGURE_STAMP): patch
114+
@mkdir -p $(BUILD_DIR)
115+
@echo "[CONF] CPython $(PY_VER) ($(ARCH))"
116+
@echo " SYSROOT=$(SYSROOT)"
117+
@echo " BUILTINS_LIB=$(BUILTINS_LIB)"
118+
@cd $(BUILD_DIR) && \
119+
CONFIG_SITE=$(CURDIR)/config.site \
120+
CC="$(CC)" \
121+
CFLAGS="$(COMMON_CFLAGS)" \
122+
LDFLAGS="$(COMMON_LDFLAGS)" \
123+
LIBS="$(STELLUX_LIBS)" \
124+
PKG_CONFIG=false \
125+
ac_cv_file__dev_ptmx=no \
126+
ac_cv_file__dev_ptc=no \
127+
../../$(SRC_DIR)/configure \
128+
--build=$$(../../$(SRC_DIR)/config.guess) \
129+
--host=$(TARGET_TRIPLE) \
130+
--prefix=/usr \
131+
--disable-shared \
132+
--disable-test-modules \
133+
--disable-ipv6 \
134+
--without-ensurepip \
135+
--with-build-python=$$(command -v $(HOST_PYTHON))
136+
@cp Modules.Setup.local $(BUILD_DIR)/Modules/Setup.local
137+
@touch $@
138+
139+
build: $(BUILD_STAMP)
140+
141+
$(BUILD_STAMP): configure
142+
@echo "[MAKE] CPython $(PY_VER) ($(ARCH))"
143+
@$(MAKE) -C $(BUILD_DIR) LINKFORSHARED=""
144+
@touch $@
145+
146+
install: build
147+
@echo "[INSTALL] CPython $(PY_VER)"
148+
@rm -rf $(INSTALL_DIR)
149+
150+
@if ! $(MAKE) -C $(BUILD_DIR) install DESTDIR=$(CURDIR)/$(INSTALL_DIR); then \
151+
echo "[WARN] full install failed; retrying static-friendly install targets"; \
152+
rm -rf $(INSTALL_DIR); \
153+
$(MAKE) -C $(BUILD_DIR) altbininstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \
154+
$(MAKE) -C $(BUILD_DIR) libinstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \
155+
$(MAKE) -C $(BUILD_DIR) inclinstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \
156+
fi
157+
158+
# Stellux has no dynamic loader.
159+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/lib-dynload
160+
@find $(INSTALL_DIR) -name '*.so' -delete
161+
162+
# Remove build/development artifacts not needed at runtime.
163+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/config-*
164+
@rm -rf $(INSTALL_DIR)/usr/include
165+
@rm -rf $(INSTALL_DIR)/usr/lib/pkgconfig
166+
@rm -rf $(INSTALL_DIR)/usr/share/man
167+
@rm -f $(INSTALL_DIR)/usr/lib/libpython*.a
168+
@rm -f $(INSTALL_DIR)/usr/lib/libpython*.so*
169+
@rm -f $(INSTALL_DIR)/usr/lib/python*.a
170+
171+
# Trim bulky/unneeded stdlib content for early bring-up.
172+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/test
173+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/idlelib
174+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/tkinter
175+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/turtledemo
176+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/ensurepip
177+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/venv
178+
@rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/lib2to3
179+
180+
# Remove helper scripts not needed in Stellux initrd.
181+
@rm -f $(INSTALL_DIR)/usr/bin/idle*
182+
@rm -f $(INSTALL_DIR)/usr/bin/pydoc*
183+
@rm -f $(INSTALL_DIR)/usr/bin/2to3*
184+
@rm -f $(INSTALL_DIR)/usr/bin/python*-config
185+
186+
# Remove bytecode/cache files.
187+
@find $(INSTALL_DIR) -name '__pycache__' -type d -prune -exec rm -rf {} +
188+
@find $(INSTALL_DIR) -name '*.pyc' -delete
189+
@find $(INSTALL_DIR) -name '*.pyo' -delete
190+
@find $(INSTALL_DIR) -name '*.a' -delete
191+
@find $(INSTALL_DIR) -name '*.o' -delete
192+
193+
# Optional: strip the runtime interpreter to reduce initrd size.
194+
@llvm-strip $(INSTALL_DIR)/usr/bin/python$(PY_MAJOR_MINOR) 2>/dev/null || \
195+
strip $(INSTALL_DIR)/usr/bin/python$(PY_MAJOR_MINOR) 2>/dev/null || true
196+
197+
# Stage as a rootfs overlay. Remove stale Python artifacts first.
198+
@rm -rf $(ROOTFS_DIR)/usr/bin/python*
199+
@rm -rf $(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR)
200+
@rm -f $(ROOTFS_DIR)/usr/lib/libpython*
201+
@rm -rf $(ROOTFS_DIR)/usr/include/python*
202+
@rm -rf $(ROOTFS_DIR)/usr/lib/pkgconfig/python*
203+
@rm -f $(ROOTFS_DIR)/bin/python3
204+
205+
@mkdir -p $(ROOTFS_DIR)
206+
@cp -a $(INSTALL_DIR)/usr $(ROOTFS_DIR)/
207+
208+
# Convenience command path.
209+
@mkdir -p $(ROOTFS_DIR)/bin
210+
@ln -sf /usr/bin/python$(PY_MAJOR_MINOR) $(ROOTFS_DIR)/bin/python3
211+
212+
@echo "[OK] Staged Python $(PY_VER) rootfs overlay for Stellux"
213+
@$(MAKE) --no-print-directory verify
214+
215+
verify:
216+
@echo "[VERIFY] built interpreter"
217+
@if [ -x "$(BUILD_DIR)/python" ]; then \
218+
file "$(BUILD_DIR)/python"; \
219+
readelf -l "$(BUILD_DIR)/python" | grep INTERP || echo "no PT_INTERP"; \
220+
else \
221+
echo "missing $(BUILD_DIR)/python"; \
222+
exit 1; \
223+
fi
224+
225+
@echo "[VERIFY] staged Python files"
226+
@test -x "$(ROOTFS_DIR)/usr/bin/python$(PY_MAJOR_MINOR)"
227+
@test -d "$(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/encodings"
228+
@test -L "$(ROOTFS_DIR)/bin/python3"
229+
230+
@echo "[VERIFY] no dynamic/shared/dev artifacts"
231+
@found="$$(find $(ROOTFS_DIR) \( -name '*.so' -o -name 'libpython*.a' -o -name 'libpython*.so*' \) -print 2>/dev/null)"; \
232+
if [ -n "$$found" ]; then \
233+
echo "$$found"; \
234+
echo "[FAIL] bad Python artifacts in rootfs staging"; \
235+
exit 1; \
236+
else \
237+
echo "ok"; \
238+
fi
239+
240+
clean:
241+
@rm -rf build install
242+
@rm -rf $(ROOTFS_DIR)/usr/bin/python*
243+
@rm -rf $(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR)
244+
@rm -f $(ROOTFS_DIR)/usr/lib/libpython*
245+
@rm -f $(ROOTFS_DIR)/bin/python3
246+
247+
distclean: clean
248+
@rm -rf src dl
249+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
*static*
2+
3+
array arraymodule.c
4+
_bisect _bisectmodule.c
5+
_csv _csv.c
6+
_heapq _heapqmodule.c
7+
_json _json.c
8+
_random _randommodule.c
9+
_struct _struct.c
10+
math mathmodule.c
11+
cmath cmathmodule.c
12+
fcntl fcntlmodule.c
13+
grp grpmodule.c
14+
mmap mmapmodule.c
15+
pwd pwdmodule.c
16+
resource resource.c
17+
select selectmodule.c
18+
_socket socketmodule.c
19+
termios termios.c
20+
unicodedata unicodedata.c
21+
22+
*disabled*
23+
24+
_asyncio
25+
_contextvars
26+
_codecs_cn
27+
_codecs_hk
28+
_codecs_iso2022
29+
_codecs_jp
30+
_codecs_kr
31+
_codecs_tw
32+
_crypt
33+
_datetime
34+
_decimal
35+
_elementtree
36+
_lsprof
37+
_md5
38+
_multiprocessing
39+
_opcode
40+
_posixshmem
41+
_posixsubprocess
42+
_queue
43+
_sha1
44+
_sha2
45+
_sha3
46+
_statistics
47+
_xxinterpchannels
48+
_xxsubinterpreters
49+
_zoneinfo
50+
audioop
51+
binascii
52+
ossaudiodev
53+
pyexpat
54+
spwd
55+
syslog
56+
57+
_bz2
58+
_ctypes
59+
_ctypes_test
60+
_curses
61+
_curses_panel
62+
_dbm
63+
_gdbm
64+
_hashlib
65+
_lzma
66+
_ssl
67+
_sqlite3
68+
_tkinter
69+
_uuid
70+
nis
71+
readline
72+
xxlimited
73+
xxlimited_35
74+
75+
_testbuffer
76+
_testcapi
77+
_testclinic
78+
_testimportmultiple
79+
_testinternalcapi
80+
_testmultiphase
81+
_xxtestfuzz
82+
xxsubtype
83+
zlib
84+

userland/apps/python/config.site

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Stellux CPython configure cache
2+
3+
# No dynamic loading or dynamic extension support
4+
ac_cv_func_dlopen=no
5+
ac_cv_lib_dl_dlopen=no
6+
ac_cv_header_dlfcn_h=no
7+
ac_cv_func_shl_load=no
8+
ac_cv_header_dl_h=no
9+
10+
# No external compression/database/crypto libs initially
11+
ac_cv_header_zlib_h=no
12+
ac_cv_lib_z_compress=no
13+
ac_cv_header_lzma_h=no
14+
ac_cv_lib_lzma_lzma_code=no
15+
ac_cv_header_bzlib_h=no
16+
ac_cv_lib_bz2_BZ2_bzCompress=no
17+
ac_cv_header_zstd_h=no
18+
ac_cv_lib_zstd_ZSTD_versionNumber=no
19+
ac_cv_header_sqlite3_h=no
20+
ac_cv_lib_sqlite3_sqlite3_open=no
21+
ac_cv_header_openssl_ssl_h=no
22+
ac_cv_lib_ssl_SSL_new=no
23+
ac_cv_lib_crypto_EVP_MD_fetch=no
24+
ac_cv_header_ffi_h=no
25+
ac_cv_lib_ffi_ffi_call=no
26+
27+
# Avoid readline/curses
28+
ac_cv_header_readline_readline_h=no
29+
ac_cv_lib_readline_readline=no
30+
ac_cv_header_curses_h=no
31+
ac_cv_lib_curses_initscr=no
32+
33+
# Stellux quirk: avoid CPython's runtime getaddrinfo IPv6 probe during cross/custom builds
34+
ac_cv_buggy_getaddrinfo=no

0 commit comments

Comments
 (0)