From 4fc111a061da846e847f5b1bfa820d7ff995fe69 Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:16:10 -0700 Subject: [PATCH 1/8] feat(syscall): implemented F_GETFD/F_SETFD commands in fcntl --- kernel/syscall/handlers/sys_fd.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/kernel/syscall/handlers/sys_fd.cpp b/kernel/syscall/handlers/sys_fd.cpp index d2b16a12..df4f4687 100644 --- a/kernel/syscall/handlers/sys_fd.cpp +++ b/kernel/syscall/handlers/sys_fd.cpp @@ -1161,8 +1161,13 @@ DEFINE_SYSCALL3(getdents64, fd, dirp, count) { } namespace { +constexpr uint64_t F_GETFD = 1; +constexpr uint64_t F_SETFD = 2; constexpr uint64_t F_GETFL = 3; constexpr uint64_t F_SETFL = 4; + +constexpr int64_t FD_CLOEXEC = 1; + constexpr uint32_t SETFL_MASK = fs::O_NONBLOCK | fs::O_APPEND; } // anonymous namespace @@ -1172,6 +1177,27 @@ DEFINE_SYSCALL3(fcntl, fd, cmd, arg) { return syscall::EIO; } + if (cmd == F_GETFD) { + uint32_t flags = 0; + int32_t rc = resource::get_handle_flags( + &task->handles, static_cast(fd), &flags); + if (rc != resource::HANDLE_OK) { + return syscall::EBADF; + } + return FD_CLOEXEC; + } + + if (cmd == F_SETFD) { + uint32_t flags = 0; + int32_t rc = resource::get_handle_flags( + &task->handles, static_cast(fd), &flags); + if (rc != resource::HANDLE_OK) { + return syscall::EBADF; + } + (void)arg; + return 0; + } + if (cmd == F_GETFL) { uint32_t flags = 0; int32_t rc = resource::get_handle_flags( From f0acc4eb5f0d260ae3bf218f039892fbe6523d17 Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:17:49 -0700 Subject: [PATCH 2/8] fix(terminal): fixed STLX_TCSETS_* and Linux tty ioctl number collision --- kernel/terminal/terminal.h | 6 ++++-- userland/apps/ptytest/src/ptytest.c | 2 +- userland/apps/shell/src/shell.c | 4 ++-- userland/apps/snake/src/snake.c | 4 ++-- userland/apps/stlxterm/src/stlxterm.c | 2 +- userland/apps/tetris/src/tetris.c | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/kernel/terminal/terminal.h b/kernel/terminal/terminal.h index d8b0f6c5..ece20600 100644 --- a/kernel/terminal/terminal.h +++ b/kernel/terminal/terminal.h @@ -11,8 +11,10 @@ namespace terminal { constexpr int32_t OK = 0; constexpr int32_t ERR = -1; -constexpr uint32_t STLX_TCSETS_RAW = 0x5401; -constexpr uint32_t STLX_TCSETS_COOKED = 0x5402; +// Stellux-internal line-discipline mode-switch ioctls. +// Encoded as _IO('s', N) so they do not collide with Linux's tty ioctl +constexpr uint32_t STLX_TCSETS_RAW = 0x7301; +constexpr uint32_t STLX_TCSETS_COOKED = 0x7302; /** * @brief Initialize the global console terminal. Creates the input ring diff --git a/userland/apps/ptytest/src/ptytest.c b/userland/apps/ptytest/src/ptytest.c index ce897a08..9bbcd2cd 100644 --- a/userland/apps/ptytest/src/ptytest.c +++ b/userland/apps/ptytest/src/ptytest.c @@ -5,7 +5,7 @@ #include #include -#define STLX_TCSETS_RAW 0x5401 +#define STLX_TCSETS_RAW 0x7301 int main(void) { setvbuf(stdout, NULL, _IONBF, 0); diff --git a/userland/apps/shell/src/shell.c b/userland/apps/shell/src/shell.c index 13eefae1..4961bdcf 100644 --- a/userland/apps/shell/src/shell.c +++ b/userland/apps/shell/src/shell.c @@ -11,8 +11,8 @@ #include "parse.h" #include "builtins.h" -#define STLX_TCSETS_RAW 0x5401 -#define STLX_TCSETS_COOKED 0x5402 +#define STLX_TCSETS_RAW 0x7301 +#define STLX_TCSETS_COOKED 0x7302 static void shell_err(const char* s) { write(1, s, strlen(s)); diff --git a/userland/apps/snake/src/snake.c b/userland/apps/snake/src/snake.c index e98236b6..9793c686 100644 --- a/userland/apps/snake/src/snake.c +++ b/userland/apps/snake/src/snake.c @@ -7,8 +7,8 @@ #include #include -#define STLX_TCSETS_RAW 0x5401 -#define STLX_TCSETS_COOKED 0x5402 +#define STLX_TCSETS_RAW 0x7301 +#define STLX_TCSETS_COOKED 0x7302 #define W 40 #define H 20 diff --git a/userland/apps/stlxterm/src/stlxterm.c b/userland/apps/stlxterm/src/stlxterm.c index b2ebffce..8187e321 100644 --- a/userland/apps/stlxterm/src/stlxterm.c +++ b/userland/apps/stlxterm/src/stlxterm.c @@ -14,7 +14,7 @@ #include "keymap.h" #include "term.h" -#define STLX_TCSETS_RAW 0x5401 +#define STLX_TCSETS_RAW 0x7301 #define STLXTERM_WIDTH 800 #define STLXTERM_HEIGHT 600 diff --git a/userland/apps/tetris/src/tetris.c b/userland/apps/tetris/src/tetris.c index 7146f0d6..0f69974e 100644 --- a/userland/apps/tetris/src/tetris.c +++ b/userland/apps/tetris/src/tetris.c @@ -7,8 +7,8 @@ #include #include -#define STLX_TCSETS_RAW 0x5401 -#define STLX_TCSETS_COOKED 0x5402 +#define STLX_TCSETS_RAW 0x7301 +#define STLX_TCSETS_COOKED 0x7302 #define BW 10 #define BH 20 From 745dc6fc7bed6081919f524d19794c5b6d11ebdd Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:20:28 -0700 Subject: [PATCH 3/8] feat(pty): implemented TCGETS/TCSETS/TIOCGWINSZ linux-compatible ioctl operations --- kernel/pty/pty.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/kernel/pty/pty.cpp b/kernel/pty/pty.cpp index 20c57825..ea66ab14 100644 --- a/kernel/pty/pty.cpp +++ b/kernel/pty/pty.cpp @@ -3,12 +3,40 @@ #include "common/ring_buffer.h" #include "fs/fstypes.h" #include "mm/heap.h" +#include "mm/uaccess.h" #include "dynpriv/dynpriv.h" #include "sync/poll.h" #include "sync/wait_queue.h" +#include "terminal/terminal.h" namespace pty { +constexpr uint32_t TCGETS = 0x5401; +constexpr uint32_t TCSETS = 0x5402; +constexpr uint32_t TCSETSW = 0x5403; +constexpr uint32_t TCSETSF = 0x5404; +constexpr uint32_t TIOCGWINSZ = 0x5413; +constexpr uint32_t TIOCSWINSZ = 0x5414; + +constexpr uint32_t LINUX_ECHO = 0x0008; +constexpr uint32_t LINUX_ICANON = 0x0002; + +struct linux_termios { + uint32_t c_iflag; + uint32_t c_oflag; + uint32_t c_cflag; + uint32_t c_lflag; + uint8_t c_line; + uint8_t c_cc[19]; +}; + +struct linux_winsize { + uint16_t ws_row; + uint16_t ws_col; + uint16_t ws_xpixel; + uint16_t ws_ypixel; +}; + __PRIVILEGED_BSS static uint32_t g_next_pty_id; __PRIVILEGED_CODE void pty_channel::ref_destroy(pty_channel* self) { @@ -179,15 +207,66 @@ static void pty_slave_close(resource::resource_object* obj) { obj->impl = nullptr; } +static int32_t do_tcgets(pty_channel* chan, uint64_t arg) { + linux_termios t = {}; + + if (chan->m_ld.mode != terminal::LD_MODE_RAW) { + t.c_lflag = LINUX_ICANON | LINUX_ECHO; + } + + int32_t rc = mm::uaccess::copy_to_user( + reinterpret_cast(arg), &t, sizeof(t)); + + return (rc == mm::uaccess::OK) ? resource::OK : resource::ERR_INVAL; +} + +static int32_t do_tcsets(pty_channel* chan, uint64_t arg) { + linux_termios t = {}; + int32_t rc = mm::uaccess::copy_from_user( + &t, reinterpret_cast(arg), sizeof(t)); + + if (rc != mm::uaccess::OK) { + return resource::ERR_INVAL; + } + + uint32_t mode = (t.c_lflag & LINUX_ICANON) + ? terminal::STLX_TCSETS_COOKED + : terminal::STLX_TCSETS_RAW; + + terminal::ld_set_mode(&chan->m_ld, mode); + return resource::OK; +} + +static int32_t do_tiocgwinsz(uint64_t arg) { + linux_winsize w = { 24, 80, 0, 0 }; + int32_t rc = mm::uaccess::copy_to_user( + reinterpret_cast(arg), &w, sizeof(w)); + + return (rc == mm::uaccess::OK) ? resource::OK : resource::ERR_INVAL; +} + +static int32_t pty_termios_ioctl(pty_channel* chan, uint32_t cmd, uint64_t arg) { + switch (cmd) { + case TCGETS: return do_tcgets(chan, arg); + case TCSETS: + case TCSETSW: + case TCSETSF: return do_tcsets(chan, arg); + case TIOCGWINSZ: return do_tiocgwinsz(arg); + case TIOCSWINSZ: return resource::OK; + case terminal::STLX_TCSETS_RAW: + case terminal::STLX_TCSETS_COOKED: return terminal::ld_set_mode(&chan->m_ld, cmd); + default: return resource::ERR_INVAL; + } +} + static int32_t pty_slave_ioctl( resource::resource_object* obj, uint32_t cmd, uint64_t arg ) { - (void)arg; if (!obj || !obj->impl) { return resource::ERR_INVAL; } auto* ep = static_cast(obj->impl); - return terminal::ld_set_mode(&ep->channel->m_ld, cmd); + return pty_termios_ioctl(ep->channel.ptr(), cmd, arg); } static uint32_t pty_master_poll( From edb039989bd6dd1aebb226003d0ae1c793f08e6d Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:21:26 -0700 Subject: [PATCH 4/8] chore(mm): bumped userland task stack from 32KiB to 512KiB (in support of upcoming python port) --- kernel/mm/vma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/mm/vma.h b/kernel/mm/vma.h index 262b7702..512a6d47 100644 --- a/kernel/mm/vma.h +++ b/kernel/mm/vma.h @@ -40,7 +40,7 @@ constexpr uint32_t VMA_FLAG_DEVICE = (1u << 5); constexpr uintptr_t MMAP_BASE_DEFAULT = 0x00000080000000ULL; constexpr uintptr_t USER_STACK_TOP = 0x00007FFFFFF00000ULL; -constexpr size_t USER_STACK_PAGES = 8; // 32 KiB +constexpr size_t USER_STACK_PAGES = 128; // 512 KiB constexpr size_t USER_STACK_GUARD_PAGES = 1; struct vma { From b0a6fe61b10fba6b1e0cf9f6c07f9c1792e63556 Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:22:10 -0700 Subject: [PATCH 5/8] feat(build): installed per-app rootfs overlays into initrd --- .gitignore | 1 + userland/Makefile | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 29c09927..0538856a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ userland/musl-* userland/llvm-project-* userland/build/ initrd/bin/* +initrd/usr/ !initrd/bin/.gitkeep # OS files diff --git a/userland/Makefile b/userland/Makefile index 30cfd0c0..6bb1247d 100644 --- a/userland/Makefile +++ b/userland/Makefile @@ -30,6 +30,8 @@ endif # Output directories BIN_DIR := $(USERLAND_ROOT)/build/$(ARCH)/bin INITRD_BIN := $(USERLAND_ROOT)/../initrd/bin +ROOTFS_DIR := $(USERLAND_ROOT)/build/$(ARCH)/rootfs +INITRD_ROOT := $(USERLAND_ROOT)/../initrd # Verbosity ifeq ($(V),1) @@ -59,23 +61,35 @@ endif install-summary: build @mkdir -p $(INITRD_BIN) ifeq ($(V),1) - @echo "Installing userland binaries to initrd..." + @echo "Installing userland binaries/rootfs to initrd..." @if [ -d "$(BIN_DIR)" ] && [ -n "$$(ls -A $(BIN_DIR) 2>/dev/null)" ]; then \ cp $(BIN_DIR)/* $(INITRD_BIN)/; \ - echo "Installed: $$(ls $(BIN_DIR)/)"; \ + echo "Installed binaries: $$(ls $(BIN_DIR)/)"; \ else \ echo "No binaries to install"; \ fi + @if [ -d "$(ROOTFS_DIR)" ] && [ -n "$$(ls -A $(ROOTFS_DIR) 2>/dev/null)" ]; then \ + cp -a $(ROOTFS_DIR)/. $(INITRD_ROOT)/; \ + echo "Installed rootfs overlay from $(ROOTFS_DIR)"; \ + else \ + echo "No rootfs overlay to install"; \ + fi else @if [ -d "$(BIN_DIR)" ] && [ -n "$$(ls -A $(BIN_DIR) 2>/dev/null)" ]; then \ cp $(BIN_DIR)/* $(INITRD_BIN)/; \ bincount=$$(ls -1 $(BIN_DIR)/ | wc -l); \ - libcount=$$(ls -1 $(SYSROOT)/lib/libstlx.a 2>/dev/null | wc -l); \ - if [ $$libcount -eq 1 ]; then libword="library"; else libword="libraries"; fi; \ - printf " $$libcount $$libword, $$bincount binaries installed to initrd/bin/\n"; \ else \ - echo " No binaries to install"; \ - fi + bincount=0; \ + fi; \ + if [ -d "$(ROOTFS_DIR)" ] && [ -n "$$(ls -A $(ROOTFS_DIR) 2>/dev/null)" ]; then \ + cp -a $(ROOTFS_DIR)/. $(INITRD_ROOT)/; \ + rootfsword=", rootfs overlay installed"; \ + else \ + rootfsword=""; \ + fi; \ + libcount=$$(ls -1 $(SYSROOT)/lib/libstlx.a 2>/dev/null | wc -l); \ + if [ $$libcount -eq 1 ]; then libword="library"; else libword="libraries"; fi; \ + printf " $$libcount $$libword, $$bincount binaries installed to initrd/bin/$$rootfsword\n" endif clean: From 43ed7eb022eb59553e6d4ea70460c92133d44e4a Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:26:29 -0700 Subject: [PATCH 6/8] feat(userland): ported the CPython 3.12 interpreter --- userland/apps/Makefile | 2 +- userland/apps/python/.gitignore | 4 + userland/apps/python/Makefile | 249 ++++++++++++++++++ userland/apps/python/Modules.Setup.local | 84 ++++++ userland/apps/python/config.site | 34 +++ ...001-posixmodule-guard-rtld-constants.patch | 38 +++ 6 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 userland/apps/python/.gitignore create mode 100644 userland/apps/python/Makefile create mode 100644 userland/apps/python/Modules.Setup.local create mode 100644 userland/apps/python/config.site create mode 100644 userland/apps/python/patches/0001-posixmodule-guard-rtld-constants.patch diff --git a/userland/apps/Makefile b/userland/apps/Makefile index e60102db..06c3fb73 100644 --- a/userland/apps/Makefile +++ b/userland/apps/Makefile @@ -5,7 +5,7 @@ APP_DIRS := init hello shell ls cat rm stat touch sleep true false clear ptytest date \ clockbench stlxdm stlxterm doom ping ifconfig nslookup arp udpecho tcpecho \ fetch polltest dropbear blackjack wordle hangman snake tetris \ - grep wc head threadtest uname kill cxxtest synctest + grep wc head threadtest uname kill cxxtest synctest python APP_COUNT := $(words $(APP_DIRS)) all: diff --git a/userland/apps/python/.gitignore b/userland/apps/python/.gitignore new file mode 100644 index 00000000..c53e82a9 --- /dev/null +++ b/userland/apps/python/.gitignore @@ -0,0 +1,4 @@ +src/ +build/ +dl/ +install/ \ No newline at end of file diff --git a/userland/apps/python/Makefile b/userland/apps/python/Makefile new file mode 100644 index 00000000..33f8053f --- /dev/null +++ b/userland/apps/python/Makefile @@ -0,0 +1,249 @@ +# +# Python Interpreter - Stellux Build +# +# Builds a static CPython interpreter against the Stellux musl sysroot +# and libstlx. Stages python + stdlib into userland/build/$(ARCH)/rootfs. +# + +APP_NAME := python +ARCH ?= x86_64 +USERLAND_ROOT ?= ../.. +override USERLAND_ROOT := $(abspath $(USERLAND_ROOT)) + +PY_VER := 3.12.8 +PY_MAJOR_MINOR := 3.12 +PY_TARBALL := Python-$(PY_VER).tar.xz +PY_URL := https://www.python.org/ftp/python/$(PY_VER)/$(PY_TARBALL) + +SYSROOT := $(USERLAND_ROOT)/sysroot/$(ARCH) +TARGET_TRIPLE := $(ARCH)-linux-musl + +DL_DIR := dl +SRC_ROOT := src +SRC_DIR := $(SRC_ROOT)/Python-$(PY_VER) +BUILD_DIR := build/$(ARCH) +INSTALL_DIR := install/$(ARCH) + +ROOTFS_DIR := $(USERLAND_ROOT)/build/$(ARCH)/rootfs + +CC := clang +HOST_PYTHON := python3 + +BUILTINS_LIB := $(shell $(CC) --target=$(TARGET_TRIPLE) --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null) + +COMMON_CFLAGS := \ + --target=$(TARGET_TRIPLE) \ + --sysroot=$(SYSROOT) \ + -nostdlibinc \ + -isystem $(SYSROOT)/include \ + -std=c11 -O2 -g \ + -D_GNU_SOURCE \ + -D__STELLUX__ \ + -fno-stack-protector + +COMMON_LDFLAGS := \ + -nostdlib \ + -fuse-ld=lld \ + --target=$(TARGET_TRIPLE) \ + --sysroot=$(SYSROOT) \ + --rtlib=compiler-rt \ + -static + +STELLUX_LIBS := \ + $(SYSROOT)/lib/crt1.o \ + $(SYSROOT)/lib/crti.o \ + -L$(SYSROOT)/lib \ + -Wl,--start-group \ + -lstlx \ + -lc \ + -lm \ + $(BUILTINS_LIB) \ + -Wl,--end-group \ + $(SYSROOT)/lib/crtn.o + +CONFIGURE_STAMP := $(BUILD_DIR)/.configured +BUILD_STAMP := $(BUILD_DIR)/.built +PATCH_STAMP := $(SRC_DIR)/.stellux-patched + +.PHONY: all fetch extract patch configure build install verify clean distclean print-vars + +all: install + +print-vars: + @echo "APP_NAME=$(APP_NAME)" + @echo "ARCH=$(ARCH)" + @echo "USERLAND_ROOT=$(USERLAND_ROOT)" + @echo "SYSROOT=$(SYSROOT)" + @echo "TARGET_TRIPLE=$(TARGET_TRIPLE)" + @echo "SRC_DIR=$(SRC_DIR)" + @echo "BUILD_DIR=$(BUILD_DIR)" + @echo "INSTALL_DIR=$(INSTALL_DIR)" + @echo "ROOTFS_DIR=$(ROOTFS_DIR)" + @echo "BUILTINS_LIB=$(BUILTINS_LIB)" + +fetch: $(DL_DIR)/$(PY_TARBALL) + +$(DL_DIR)/$(PY_TARBALL): + @mkdir -p $(DL_DIR) + @echo "[FETCH] CPython $(PY_VER)" + @curl -L "$(PY_URL)" -o "$@" + +extract: fetch + @if [ ! -d "$(SRC_DIR)" ]; then \ + mkdir -p $(SRC_ROOT); \ + echo "[EXTRACT] $(PY_TARBALL)"; \ + tar -C $(SRC_ROOT) -xf "$(DL_DIR)/$(PY_TARBALL)"; \ + fi + +patch: extract $(PATCH_STAMP) + +$(PATCH_STAMP): + @echo "[PATCH] CPython for Stellux" + @cd $(SRC_DIR) && for p in ../../patches/*.patch; do \ + if [ -f "$$p" ]; then \ + echo " applying $$p"; \ + patch --forward --batch -p1 < "$$p"; \ + fi; \ + done + @cp Modules.Setup.local $(SRC_DIR)/Modules/Setup.local + @touch $@ + +configure: $(CONFIGURE_STAMP) + +$(CONFIGURE_STAMP): patch + @mkdir -p $(BUILD_DIR) + @echo "[CONF] CPython $(PY_VER) ($(ARCH))" + @echo " SYSROOT=$(SYSROOT)" + @echo " BUILTINS_LIB=$(BUILTINS_LIB)" + @cd $(BUILD_DIR) && \ + CONFIG_SITE=$(CURDIR)/config.site \ + CC="$(CC)" \ + CFLAGS="$(COMMON_CFLAGS)" \ + LDFLAGS="$(COMMON_LDFLAGS)" \ + LIBS="$(STELLUX_LIBS)" \ + PKG_CONFIG=false \ + ac_cv_file__dev_ptmx=no \ + ac_cv_file__dev_ptc=no \ + ../../$(SRC_DIR)/configure \ + --build=$$(../../$(SRC_DIR)/config.guess) \ + --host=$(TARGET_TRIPLE) \ + --prefix=/usr \ + --disable-shared \ + --disable-test-modules \ + --disable-ipv6 \ + --without-ensurepip \ + --with-build-python=$$(command -v $(HOST_PYTHON)) + @cp Modules.Setup.local $(BUILD_DIR)/Modules/Setup.local + @touch $@ + +build: $(BUILD_STAMP) + +$(BUILD_STAMP): configure + @echo "[MAKE] CPython $(PY_VER) ($(ARCH))" + @$(MAKE) -C $(BUILD_DIR) LINKFORSHARED="" + @touch $@ + +install: build + @echo "[INSTALL] CPython $(PY_VER)" + @rm -rf $(INSTALL_DIR) + + @if ! $(MAKE) -C $(BUILD_DIR) install DESTDIR=$(CURDIR)/$(INSTALL_DIR); then \ + echo "[WARN] full install failed; retrying static-friendly install targets"; \ + rm -rf $(INSTALL_DIR); \ + $(MAKE) -C $(BUILD_DIR) altbininstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \ + $(MAKE) -C $(BUILD_DIR) libinstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \ + $(MAKE) -C $(BUILD_DIR) inclinstall DESTDIR=$(CURDIR)/$(INSTALL_DIR); \ + fi + + # Stellux has no dynamic loader. + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/lib-dynload + @find $(INSTALL_DIR) -name '*.so' -delete + + # Remove build/development artifacts not needed at runtime. + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/config-* + @rm -rf $(INSTALL_DIR)/usr/include + @rm -rf $(INSTALL_DIR)/usr/lib/pkgconfig + @rm -rf $(INSTALL_DIR)/usr/share/man + @rm -f $(INSTALL_DIR)/usr/lib/libpython*.a + @rm -f $(INSTALL_DIR)/usr/lib/libpython*.so* + @rm -f $(INSTALL_DIR)/usr/lib/python*.a + + # Trim bulky/unneeded stdlib content for early bring-up. + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/test + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/idlelib + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/tkinter + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/turtledemo + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/ensurepip + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/venv + @rm -rf $(INSTALL_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/lib2to3 + + # Remove helper scripts not needed in Stellux initrd. + @rm -f $(INSTALL_DIR)/usr/bin/idle* + @rm -f $(INSTALL_DIR)/usr/bin/pydoc* + @rm -f $(INSTALL_DIR)/usr/bin/2to3* + @rm -f $(INSTALL_DIR)/usr/bin/python*-config + + # Remove bytecode/cache files. + @find $(INSTALL_DIR) -name '__pycache__' -type d -prune -exec rm -rf {} + + @find $(INSTALL_DIR) -name '*.pyc' -delete + @find $(INSTALL_DIR) -name '*.pyo' -delete + @find $(INSTALL_DIR) -name '*.a' -delete + @find $(INSTALL_DIR) -name '*.o' -delete + + # Optional: strip the runtime interpreter to reduce initrd size. + @llvm-strip $(INSTALL_DIR)/usr/bin/python$(PY_MAJOR_MINOR) 2>/dev/null || \ + strip $(INSTALL_DIR)/usr/bin/python$(PY_MAJOR_MINOR) 2>/dev/null || true + + # Stage as a rootfs overlay. Remove stale Python artifacts first. + @rm -rf $(ROOTFS_DIR)/usr/bin/python* + @rm -rf $(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR) + @rm -f $(ROOTFS_DIR)/usr/lib/libpython* + @rm -rf $(ROOTFS_DIR)/usr/include/python* + @rm -rf $(ROOTFS_DIR)/usr/lib/pkgconfig/python* + @rm -f $(ROOTFS_DIR)/bin/python3 + + @mkdir -p $(ROOTFS_DIR) + @cp -a $(INSTALL_DIR)/usr $(ROOTFS_DIR)/ + + # Convenience command path. + @mkdir -p $(ROOTFS_DIR)/bin + @ln -sf /usr/bin/python$(PY_MAJOR_MINOR) $(ROOTFS_DIR)/bin/python3 + + @echo "[OK] Staged Python $(PY_VER) rootfs overlay for Stellux" + @$(MAKE) --no-print-directory verify + +verify: + @echo "[VERIFY] built interpreter" + @if [ -x "$(BUILD_DIR)/python" ]; then \ + file "$(BUILD_DIR)/python"; \ + readelf -l "$(BUILD_DIR)/python" | grep INTERP || echo "no PT_INTERP"; \ + else \ + echo "missing $(BUILD_DIR)/python"; \ + exit 1; \ + fi + + @echo "[VERIFY] staged Python files" + @test -x "$(ROOTFS_DIR)/usr/bin/python$(PY_MAJOR_MINOR)" + @test -d "$(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR)/encodings" + @test -L "$(ROOTFS_DIR)/bin/python3" + + @echo "[VERIFY] no dynamic/shared/dev artifacts" + @found="$$(find $(ROOTFS_DIR) \( -name '*.so' -o -name 'libpython*.a' -o -name 'libpython*.so*' \) -print 2>/dev/null)"; \ + if [ -n "$$found" ]; then \ + echo "$$found"; \ + echo "[FAIL] bad Python artifacts in rootfs staging"; \ + exit 1; \ + else \ + echo "ok"; \ + fi + +clean: + @rm -rf build install + @rm -rf $(ROOTFS_DIR)/usr/bin/python* + @rm -rf $(ROOTFS_DIR)/usr/lib/python$(PY_MAJOR_MINOR) + @rm -f $(ROOTFS_DIR)/usr/lib/libpython* + @rm -f $(ROOTFS_DIR)/bin/python3 + +distclean: clean + @rm -rf src dl + diff --git a/userland/apps/python/Modules.Setup.local b/userland/apps/python/Modules.Setup.local new file mode 100644 index 00000000..0a368bb2 --- /dev/null +++ b/userland/apps/python/Modules.Setup.local @@ -0,0 +1,84 @@ +*static* + +array arraymodule.c +_bisect _bisectmodule.c +_csv _csv.c +_heapq _heapqmodule.c +_json _json.c +_random _randommodule.c +_struct _struct.c +math mathmodule.c +cmath cmathmodule.c +fcntl fcntlmodule.c +grp grpmodule.c +mmap mmapmodule.c +pwd pwdmodule.c +resource resource.c +select selectmodule.c +_socket socketmodule.c +termios termios.c +unicodedata unicodedata.c + +*disabled* + +_asyncio +_contextvars +_codecs_cn +_codecs_hk +_codecs_iso2022 +_codecs_jp +_codecs_kr +_codecs_tw +_crypt +_datetime +_decimal +_elementtree +_lsprof +_md5 +_multiprocessing +_opcode +_posixshmem +_posixsubprocess +_queue +_sha1 +_sha2 +_sha3 +_statistics +_xxinterpchannels +_xxsubinterpreters +_zoneinfo +audioop +binascii +ossaudiodev +pyexpat +spwd +syslog + +_bz2 +_ctypes +_ctypes_test +_curses +_curses_panel +_dbm +_gdbm +_hashlib +_lzma +_ssl +_sqlite3 +_tkinter +_uuid +nis +readline +xxlimited +xxlimited_35 + +_testbuffer +_testcapi +_testclinic +_testimportmultiple +_testinternalcapi +_testmultiphase +_xxtestfuzz +xxsubtype +zlib + diff --git a/userland/apps/python/config.site b/userland/apps/python/config.site new file mode 100644 index 00000000..ed6d5341 --- /dev/null +++ b/userland/apps/python/config.site @@ -0,0 +1,34 @@ +# Stellux CPython configure cache + +# No dynamic loading or dynamic extension support +ac_cv_func_dlopen=no +ac_cv_lib_dl_dlopen=no +ac_cv_header_dlfcn_h=no +ac_cv_func_shl_load=no +ac_cv_header_dl_h=no + +# No external compression/database/crypto libs initially +ac_cv_header_zlib_h=no +ac_cv_lib_z_compress=no +ac_cv_header_lzma_h=no +ac_cv_lib_lzma_lzma_code=no +ac_cv_header_bzlib_h=no +ac_cv_lib_bz2_BZ2_bzCompress=no +ac_cv_header_zstd_h=no +ac_cv_lib_zstd_ZSTD_versionNumber=no +ac_cv_header_sqlite3_h=no +ac_cv_lib_sqlite3_sqlite3_open=no +ac_cv_header_openssl_ssl_h=no +ac_cv_lib_ssl_SSL_new=no +ac_cv_lib_crypto_EVP_MD_fetch=no +ac_cv_header_ffi_h=no +ac_cv_lib_ffi_ffi_call=no + +# Avoid readline/curses +ac_cv_header_readline_readline_h=no +ac_cv_lib_readline_readline=no +ac_cv_header_curses_h=no +ac_cv_lib_curses_initscr=no + +# Stellux quirk: avoid CPython's runtime getaddrinfo IPv6 probe during cross/custom builds +ac_cv_buggy_getaddrinfo=no diff --git a/userland/apps/python/patches/0001-posixmodule-guard-rtld-constants.patch b/userland/apps/python/patches/0001-posixmodule-guard-rtld-constants.patch new file mode 100644 index 00000000..1e862466 --- /dev/null +++ b/userland/apps/python/patches/0001-posixmodule-guard-rtld-constants.patch @@ -0,0 +1,38 @@ +--- a/Modules/posixmodule.c 2026-05-25 12:10:27.715181369 -0700 ++++ b/Modules/posixmodule.c 2026-05-25 12:10:27.734181409 -0700 +@@ -16617,23 +16617,35 @@ + #endif + + #if HAVE_DECL_RTLD_LAZY ++#ifdef RTLD_LAZY + if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_NOW ++#ifdef RTLD_NOW + if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_GLOBAL ++#ifdef RTLD_GLOBAL + if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_LOCAL ++#ifdef RTLD_LOCAL + if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_NODELETE ++#ifdef RTLD_NODELETE + if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_NOLOAD ++#ifdef RTLD_NOLOAD + if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1; + #endif ++#endif + #if HAVE_DECL_RTLD_DEEPBIND + if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1; + #endif From fb672273a05024f25b57be0ace8e812424dd0e47 Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:36:46 -0700 Subject: [PATCH 7/8] fix(syscall): honor per-handle FD_CLOEXEC in fcntl --- kernel/fs/fstypes.h | 1 + kernel/resource/handle_table.h | 3 +++ kernel/resource/resource.cpp | 7 +++++++ kernel/syscall/handlers/sys_fd.cpp | 32 +++++++++++++++++++++++++----- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/kernel/fs/fstypes.h b/kernel/fs/fstypes.h index 1e185211..e392bad3 100644 --- a/kernel/fs/fstypes.h +++ b/kernel/fs/fstypes.h @@ -26,6 +26,7 @@ constexpr uint32_t O_EXCL = 0x80; constexpr uint32_t O_TRUNC = 0x200; constexpr uint32_t O_APPEND = 0x400; constexpr uint32_t O_NONBLOCK = 0x800; +constexpr uint32_t O_CLOEXEC = 0x80000; constexpr uint32_t ACCESS_MODE_MASK = 0x3; diff --git a/kernel/resource/handle_table.h b/kernel/resource/handle_table.h index 62f0f43a..b0830fc5 100644 --- a/kernel/resource/handle_table.h +++ b/kernel/resource/handle_table.h @@ -10,6 +10,9 @@ struct resource_object; constexpr uint32_t MAX_TASK_HANDLES = 128; +// Private high bit in handle_entry::flags reserved for FD_CLOEXEC state +constexpr uint32_t RESOURCE_HANDLE_CLOEXEC = 0x80000000; + struct handle_entry { bool used; uint16_t generation; diff --git a/kernel/resource/resource.cpp b/kernel/resource/resource.cpp index 5418b3be..d8118114 100644 --- a/kernel/resource/resource.cpp +++ b/kernel/resource/resource.cpp @@ -113,6 +113,13 @@ __PRIVILEGED_CODE int32_t open( return (rc == HANDLE_ERR_NOSPC) ? ERR_TABLEFULL : ERR_IO; } + if (flags & fs::O_CLOEXEC) { + uint32_t handle_flags = 0; + get_handle_flags(&owner->handles, *out_handle, &handle_flags); + set_handle_flags(&owner->handles, *out_handle, + handle_flags | RESOURCE_HANDLE_CLOEXEC); + } + // Table now owns one reference. resource_release(obj); return OK; diff --git a/kernel/syscall/handlers/sys_fd.cpp b/kernel/syscall/handlers/sys_fd.cpp index df4f4687..bfa06606 100644 --- a/kernel/syscall/handlers/sys_fd.cpp +++ b/kernel/syscall/handlers/sys_fd.cpp @@ -1184,7 +1184,7 @@ DEFINE_SYSCALL3(fcntl, fd, cmd, arg) { if (rc != resource::HANDLE_OK) { return syscall::EBADF; } - return FD_CLOEXEC; + return (flags & resource::RESOURCE_HANDLE_CLOEXEC) ? FD_CLOEXEC : 0; } if (cmd == F_SETFD) { @@ -1194,7 +1194,18 @@ DEFINE_SYSCALL3(fcntl, fd, cmd, arg) { if (rc != resource::HANDLE_OK) { return syscall::EBADF; } - (void)arg; + + flags &= ~resource::RESOURCE_HANDLE_CLOEXEC; + if (arg & FD_CLOEXEC) { + flags |= resource::RESOURCE_HANDLE_CLOEXEC; + } + + rc = resource::set_handle_flags( + &task->handles, static_cast(fd), flags); + + if (rc != resource::HANDLE_OK) { + return syscall::EBADF; + } return 0; } @@ -1202,16 +1213,27 @@ DEFINE_SYSCALL3(fcntl, fd, cmd, arg) { uint32_t flags = 0; int32_t rc = resource::get_handle_flags( &task->handles, static_cast(fd), &flags); + if (rc != resource::HANDLE_OK) { return syscall::EBADF; } - return static_cast(flags); + + return static_cast(flags & ~resource::RESOURCE_HANDLE_CLOEXEC); } if (cmd == F_SETFL) { - uint32_t flags = static_cast(arg) & SETFL_MASK; - int32_t rc = resource::set_handle_flags( + uint32_t flags = 0; + int32_t rc = resource::get_handle_flags( + &task->handles, static_cast(fd), &flags); + + if (rc != resource::HANDLE_OK) { + return syscall::EBADF; + } + + flags = (flags & ~SETFL_MASK) | (static_cast(arg) & SETFL_MASK); + rc = resource::set_handle_flags( &task->handles, static_cast(fd), flags); + if (rc != resource::HANDLE_OK) { return syscall::EBADF; } From f6de95bdde8ac305544b24def2c9ce2f10193f67 Mon Sep 17 00:00:00 2001 From: FlareCoding Date: Mon, 25 May 2026 15:54:56 -0700 Subject: [PATCH 8/8] feat(toolchain): build compiler-rt builtins for both architectures --- .github/workflows/kernel-unit-tests.yml | 26 ++++++ Makefile | 114 +++++++++++++++++++++--- userland/apps/python/Makefile | 18 +++- userland/mk/toolchain.mk | 16 ++-- 4 files changed, 154 insertions(+), 20 deletions(-) diff --git a/.github/workflows/kernel-unit-tests.yml b/.github/workflows/kernel-unit-tests.yml index 8cc6c4d7..fdd8dbe7 100644 --- a/.github/workflows/kernel-unit-tests.yml +++ b/.github/workflows/kernel-unit-tests.yml @@ -109,6 +109,19 @@ jobs: if: steps.libcxx-cache.outputs.cache-hit != 'true' run: make libcxx + - name: Cache compiler-rt builtins + uses: actions/cache@v4 + id: compiler-rt-cache + with: + path: | + userland/sysroot/x86_64/lib/libclang_rt.builtins-x86_64.a + userland/sysroot/aarch64/lib/libclang_rt.builtins-aarch64.a + key: compiler-rt-builtins-18.1.8 + + - name: Build compiler-rt builtins + if: steps.compiler-rt-cache.outputs.cache-hit != 'true' + run: make compiler-rt + - name: Build kernel run: | make kernel ARCH=${{ matrix.arch }} \ @@ -191,6 +204,19 @@ jobs: if: steps.libcxx-cache.outputs.cache-hit != 'true' run: make libcxx + - name: Cache compiler-rt builtins + uses: actions/cache@v4 + id: compiler-rt-cache + with: + path: | + userland/sysroot/x86_64/lib/libclang_rt.builtins-x86_64.a + userland/sysroot/aarch64/lib/libclang_rt.builtins-aarch64.a + key: compiler-rt-builtins-18.1.8 + + - name: Build compiler-rt builtins + if: steps.compiler-rt-cache.outputs.cache-hit != 'true' + run: make compiler-rt + - name: Run unit tests run: make test ARCH=${{ matrix.arch }} 2>&1 | tee test-log-${{ matrix.arch }}.txt diff --git a/Makefile b/Makefile index a6da5702..3574ee24 100644 --- a/Makefile +++ b/Makefile @@ -648,6 +648,80 @@ libcxx: @echo "" @echo "libc++ $(LLVM_VERSION) ready for both architectures." +# Build the compiler-rt builtins runtime for both supported architectures and +# install it into the per-arch sysroot as a flat archive +# (libclang_rt.builtins-.a alongside libc.a, libstlx.a, etc.). This frees +# downstream apps (notably the static CPython link) from depending on the host +# toolchain shipping cross-arch builtins, which Ubuntu's libclang-rt-dev does +# not provide for aarch64. +compiler-rt: + @echo "Building compiler-rt builtins $(LLVM_VERSION) for x86_64 and aarch64..." + @test -f userland/sysroot/x86_64/lib/libc.a || \ + (echo "ERROR: musl sysroot not found. Run 'make musl' first." && exit 1) + @test -f userland/sysroot/aarch64/lib/libc.a || \ + (echo "ERROR: musl sysroot not found. Run 'make musl' first." && exit 1) + @mkdir -p userland + @test -f $(LLVM_TARBALL) || \ + (echo "Downloading LLVM $(LLVM_VERSION) source (~130MB)..." && \ + curl -L -o $(LLVM_TARBALL) $(LLVM_URL)) + @test -d $(LLVM_DIR) || \ + (echo "Extracting..." && \ + cd userland && tar xf llvm-project-$(LLVM_VERSION).src.tar.xz) + @echo "" + @echo "Building compiler-rt builtins for x86_64..." + @mkdir -p $(LLVM_DIR)/build-compiler-rt-x86_64 + cd $(LLVM_DIR)/build-compiler-rt-x86_64 && cmake -G "Unix Makefiles" ../compiler-rt \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_ASM_COMPILER=clang \ + -DCMAKE_C_COMPILER_TARGET=x86_64-linux-musl \ + -DCMAKE_ASM_COMPILER_TARGET=x86_64-linux-musl \ + -DCMAKE_SYSROOT=$(abspath userland/sysroot/x86_64) \ + -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \ + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \ + -DCOMPILER_RT_BUILD_BUILTINS=ON \ + -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ + -DCOMPILER_RT_BUILD_XRAY=OFF \ + -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \ + -DCOMPILER_RT_BUILD_PROFILE=OFF \ + -DCOMPILER_RT_BUILD_MEMPROF=OFF \ + -DCOMPILER_RT_BUILD_ORC=OFF \ + -DCOMPILER_RT_INCLUDE_TESTS=OFF \ + '-DCMAKE_C_FLAGS=--target=x86_64-linux-musl --sysroot=$(abspath userland/sysroot/x86_64) -nostdlibinc -isystem $(abspath userland/sysroot/x86_64)/include' \ + '-DCMAKE_ASM_FLAGS=--target=x86_64-linux-musl --sysroot=$(abspath userland/sysroot/x86_64) -nostdlibinc -isystem $(abspath userland/sysroot/x86_64)/include' \ + > /dev/null + $(MAKE) -C $(LLVM_DIR)/build-compiler-rt-x86_64 -j$$(nproc) builtins > /dev/null + @cp "$$(find $(LLVM_DIR)/build-compiler-rt-x86_64 -name 'libclang_rt.builtins*.a' -print -quit)" \ + userland/sysroot/x86_64/lib/libclang_rt.builtins-x86_64.a + @echo "compiler-rt builtins x86_64 installed to userland/sysroot/x86_64/lib/" + @echo "" + @echo "Building compiler-rt builtins for aarch64..." + @mkdir -p $(LLVM_DIR)/build-compiler-rt-aarch64 + cd $(LLVM_DIR)/build-compiler-rt-aarch64 && cmake -G "Unix Makefiles" ../compiler-rt \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_ASM_COMPILER=clang \ + -DCMAKE_C_COMPILER_TARGET=aarch64-linux-musl \ + -DCMAKE_ASM_COMPILER_TARGET=aarch64-linux-musl \ + -DCMAKE_SYSROOT=$(abspath userland/sysroot/aarch64) \ + -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \ + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \ + -DCOMPILER_RT_BUILD_BUILTINS=ON \ + -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ + -DCOMPILER_RT_BUILD_XRAY=OFF \ + -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \ + -DCOMPILER_RT_BUILD_PROFILE=OFF \ + -DCOMPILER_RT_BUILD_MEMPROF=OFF \ + -DCOMPILER_RT_BUILD_ORC=OFF \ + -DCOMPILER_RT_INCLUDE_TESTS=OFF \ + '-DCMAKE_C_FLAGS=--target=aarch64-linux-musl --sysroot=$(abspath userland/sysroot/aarch64) -nostdlibinc -isystem $(abspath userland/sysroot/aarch64)/include' \ + '-DCMAKE_ASM_FLAGS=--target=aarch64-linux-musl --sysroot=$(abspath userland/sysroot/aarch64) -nostdlibinc -isystem $(abspath userland/sysroot/aarch64)/include' \ + > /dev/null + $(MAKE) -C $(LLVM_DIR)/build-compiler-rt-aarch64 -j$$(nproc) builtins > /dev/null + @cp "$$(find $(LLVM_DIR)/build-compiler-rt-aarch64 -name 'libclang_rt.builtins*.a' -print -quit)" \ + userland/sysroot/aarch64/lib/libclang_rt.builtins-aarch64.a + @echo "compiler-rt builtins aarch64 installed to userland/sysroot/aarch64/lib/" + @echo "" + @echo "compiler-rt builtins $(LLVM_VERSION) ready for both architectures." + limine: @echo "Downloading Limine ($(LIMINE_BRANCH))..." @mkdir -p $(BOOT_DIR) @@ -728,24 +802,34 @@ toolchain-check: @printf "%-24s" "libc++ (aarch64):" && \ (test -f userland/sysroot/aarch64/lib/libc++.a && echo "OK" || echo "NOT FOUND - run 'make libcxx'") @printf "%-24s" "builtins (x86_64):" && \ - (BRT=$$(clang --target=x86_64-linux-musl --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null); \ - if [ -f "$$BRT" ]; then \ - echo "$$BRT"; \ - elif which x86_64-linux-gnu-gcc > /dev/null 2>&1; then \ - BGCC=$$(x86_64-linux-gnu-gcc -print-libgcc-file-name 2>/dev/null); \ - [ -f "$$BGCC" ] && echo "$$BGCC" || echo "NOT FOUND"; \ + (SR=userland/sysroot/x86_64/lib/libclang_rt.builtins-x86_64.a; \ + if [ -f "$$SR" ]; then \ + echo "$$SR"; \ else \ - echo "NOT FOUND"; \ + BRT=$$(clang --target=x86_64-linux-musl --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null); \ + if [ -f "$$BRT" ]; then \ + echo "$$BRT"; \ + elif which x86_64-linux-gnu-gcc > /dev/null 2>&1; then \ + BGCC=$$(x86_64-linux-gnu-gcc -print-libgcc-file-name 2>/dev/null); \ + [ -f "$$BGCC" ] && echo "$$BGCC" || echo "NOT FOUND - run 'make compiler-rt'"; \ + else \ + echo "NOT FOUND - run 'make compiler-rt'"; \ + fi; \ fi) @printf "%-24s" "builtins (aarch64):" && \ - (BRT=$$(clang --target=aarch64-linux-musl --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null); \ - if [ -f "$$BRT" ]; then \ - echo "$$BRT"; \ - elif which aarch64-linux-gnu-gcc > /dev/null 2>&1; then \ - BGCC=$$(aarch64-linux-gnu-gcc -print-libgcc-file-name 2>/dev/null); \ - [ -f "$$BGCC" ] && echo "$$BGCC" || echo "NOT FOUND"; \ + (SR=userland/sysroot/aarch64/lib/libclang_rt.builtins-aarch64.a; \ + if [ -f "$$SR" ]; then \ + echo "$$SR"; \ else \ - echo "NOT FOUND"; \ + BRT=$$(clang --target=aarch64-linux-musl --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null); \ + if [ -f "$$BRT" ]; then \ + echo "$$BRT"; \ + elif which aarch64-linux-gnu-gcc > /dev/null 2>&1; then \ + BGCC=$$(aarch64-linux-gnu-gcc -print-libgcc-file-name 2>/dev/null); \ + [ -f "$$BGCC" ] && echo "$$BGCC" || echo "NOT FOUND - run 'make compiler-rt'"; \ + else \ + echo "NOT FOUND - run 'make compiler-rt'"; \ + fi; \ fi) @echo "" @echo "If anything is NOT FOUND, run 'make deps', 'make limine', 'make musl', 'make libcxx', and/or 'make rpi4-firmware'" @@ -762,6 +846,7 @@ help: @echo " make limine Download Limine bootloader" @echo " make musl Build musl libc for both architectures" @echo " make libcxx Build libc++ for C++ userland support" + @echo " make compiler-rt Build compiler-rt builtins (required for cross-arch static linking)" @echo " make rpi4-firmware Download RPi4 UEFI firmware" @echo " make doom-wad Download DOOM1.WAD shareware" @echo " make toolchain-check Verify tools are installed" @@ -796,6 +881,7 @@ help: @echo " 2. make limine" @echo " 3. make musl" @echo " 4. make libcxx" + @echo " 5. make compiler-rt" @echo "" @echo "Examples:" @echo " make kernel ARCH=x86_64" diff --git a/userland/apps/python/Makefile b/userland/apps/python/Makefile index 33f8053f..a47bdf74 100644 --- a/userland/apps/python/Makefile +++ b/userland/apps/python/Makefile @@ -29,7 +29,23 @@ ROOTFS_DIR := $(USERLAND_ROOT)/build/$(ARCH)/rootfs CC := clang HOST_PYTHON := python3 -BUILTINS_LIB := $(shell $(CC) --target=$(TARGET_TRIPLE) --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null) +# Runtime builtins discovery: prefer the sysroot-bundled compiler-rt (built by +# 'make compiler-rt' at repo root), then the host's system compiler-rt, then +# the target GCC libgcc archive. Mirrors userland/mk/toolchain.mk so that +# every userland app sees the same builtins. +SYSROOT_BUILTINS := $(SYSROOT)/lib/libclang_rt.builtins-$(ARCH).a +COMPILER_RT_BUILTINS := $(shell $(CC) --target=$(TARGET_TRIPLE) --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null) +GCC_BUILTINS := $(shell $(ARCH)-linux-gnu-gcc -print-libgcc-file-name 2>/dev/null) + +ifneq ($(wildcard $(SYSROOT_BUILTINS)),) + BUILTINS_LIB := $(SYSROOT_BUILTINS) +else ifneq ($(wildcard $(COMPILER_RT_BUILTINS)),) + BUILTINS_LIB := $(COMPILER_RT_BUILTINS) +else ifneq ($(wildcard $(GCC_BUILTINS)),) + BUILTINS_LIB := $(GCC_BUILTINS) +else + $(error Missing runtime builtins for ARCH=$(ARCH). Run 'make compiler-rt' or install dependencies with 'make deps') +endif COMMON_CFLAGS := \ --target=$(TARGET_TRIPLE) \ diff --git a/userland/mk/toolchain.mk b/userland/mk/toolchain.mk index 0bd8873f..3427e794 100644 --- a/userland/mk/toolchain.mk +++ b/userland/mk/toolchain.mk @@ -43,17 +43,23 @@ CXXFLAGS_COMMON := \ -fno-stack-protector # Runtime builtins are required for compiler helper symbols referenced by musl -# (notably on aarch64 long-double printf paths). Prefer compiler-rt when -# available; otherwise fall back to the target GCC libgcc archive. +# (notably on aarch64 long-double printf paths). Preference order: the +# sysroot-bundled compiler-rt built by 'make compiler-rt' (deterministic and +# cross-arch capable), then the host's system compiler-rt (works for x86_64 on +# typical Linux distros), then the target GCC libgcc archive as a final +# fallback. +SYSROOT_BUILTINS := $(SYSROOT)/lib/libclang_rt.builtins-$(ARCH).a COMPILER_RT_BUILTINS := $(shell $(CC) --target=$(TARGET_TRIPLE) --rtlib=compiler-rt -print-libgcc-file-name 2>/dev/null) -GCC_BUILTINS := $(shell $(GCC_TRIPLE)-gcc -print-libgcc-file-name 2>/dev/null) +GCC_BUILTINS := $(shell $(GCC_TRIPLE)-gcc -print-libgcc-file-name 2>/dev/null) -ifneq ($(wildcard $(COMPILER_RT_BUILTINS)),) +ifneq ($(wildcard $(SYSROOT_BUILTINS)),) + BUILTINS_LIB := $(SYSROOT_BUILTINS) +else ifneq ($(wildcard $(COMPILER_RT_BUILTINS)),) BUILTINS_LIB := $(COMPILER_RT_BUILTINS) else ifneq ($(wildcard $(GCC_BUILTINS)),) BUILTINS_LIB := $(GCC_BUILTINS) else - $(error Missing runtime builtins for ARCH=$(ARCH). Install dependencies with 'make deps') + $(error Missing runtime builtins for ARCH=$(ARCH). Run 'make compiler-rt' or install dependencies with 'make deps') endif # Verbosity (inherited from top-level V=1)