Skip to content

Commit 340a9aa

Browse files
committed
interpreters/python: Add Python's port to NuttX
This is the NuttX's port of Python (cpython)! Initial support of Python includes building the Python's static library and the `python` (Programs/python.c) application. Python's modules are stored in `pyc` (byte-code file) and loaded as needed from flash.
1 parent 6600a5f commit 340a9aa

17 files changed

+1354
-0
lines changed

interpreters/python/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*.zip
2+
/build/
3+
/install/
4+
/Python/
5+
/romfs_cpython_modules.h
6+
/romfs_cpython_modules.img

interpreters/python/Kconfig

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#
2+
# For a description of the syntax of this configuration file,
3+
# see the file kconfig-language.txt in the NuttX tools repository.
4+
#
5+
6+
config INTERPRETER_CPYTHON
7+
tristate "CPython"
8+
depends on LIB_ZLIB
9+
depends on EXPERIMENTAL
10+
default n
11+
---help---
12+
Enable the CPython port to NuttX. This is a port of the Python
13+
interpreter to NuttX. Initially, it is tweaked to work with the
14+
RISC-V QEMU virtual board (`rv-virt`).
15+
16+
if INTERPRETER_CPYTHON
17+
18+
config INTERPRETER_CPYTHON_VERSION
19+
string "Python Version"
20+
default "3.13.0"
21+
22+
config INTERPRETER_CPYTHON_STACKSIZE
23+
int "CPython stack size"
24+
default 307200
25+
---help---
26+
This is the stack size allocated when the CPython task runs.
27+
28+
config INTERPRETER_CPYTHON_PRIORITY
29+
int "CPython task priority"
30+
default 150
31+
---help---
32+
This is the priority of the CPython task.
33+
34+
config INTERPRETER_CPYTHON_PROGNAME
35+
string "CPython name"
36+
default "python"
37+
---help---
38+
This is the name of the program that will be used from the nsh.
39+
40+
config INTERPRETER_CPYTHON_MOUNT_MODULES_STACKSIZE
41+
int "CPython's Modules Mount stack size"
42+
default 4096
43+
---help---
44+
This is the stack size allocated when the CPython's Modules Mount task runs.
45+
46+
config INTERPRETER_CPYTHON_MOUNT_MODULES_PRIORITY
47+
int "CPython's Modules Mount task priority"
48+
default 150
49+
---help---
50+
This is the priority of the CPython's Modules Mount task.
51+
52+
config INTERPRETER_CPYTHON_MOUNT_MODULES_PROGNAME
53+
string "CPython's Modules Mount app name"
54+
default "mount_modules"
55+
---help---
56+
This is the name of the program that will be used from the nsh.
57+
58+
endif

interpreters/python/Make.defs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
############################################################################
2+
# apps/interpreters/python/Make.defs
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
ifneq ($(CONFIG_INTERPRETER_CPYTHON),)
22+
23+
EXTRA_LIBPATHS += -L$(APPDIR)/interpreters/python/install/target
24+
EXTRA_LIBS += -lpython3.13
25+
26+
CONFIGURED_APPS += $(APPDIR)/interpreters/python
27+
endif

interpreters/python/Makefile

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
############################################################################
2+
# apps/interpreters/python/Makefile
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
include $(APPDIR)/Make.defs
22+
23+
CPYTHON_URL ?= "https://github.com/python/cpython/archive"
24+
CPYTHON_VERSION = $(patsubst "%",%,$(strip $(CONFIG_INTERPRETER_CPYTHON_VERSION)))
25+
CPYTHON_ZIP = v$(CPYTHON_VERSION).zip
26+
27+
CPYTHON_UNPACKNAME = Python
28+
UNPACK ?= unzip -q -o
29+
30+
MACHDEP=nuttx
31+
CONFIG_SITE=${CURDIR}/config.site
32+
CPYTHON_PATH=$(CURDIR)/$(CPYTHON_UNPACKNAME)
33+
34+
BUILDIR=$(CURDIR)/build
35+
INSTALLDIR=$(CURDIR)/install
36+
HOSTBUILD=$(BUILDIR)/host
37+
HOSTINSTALL=$(INSTALLDIR)/host
38+
HOSTPYTHON=$(HOSTINSTALL)/bin/python3
39+
TARGETBUILD=$(BUILDIR)/target
40+
TARGETINSTALL=$(INSTALLDIR)/target
41+
TARGETLIBPYTHON=$(TARGETINSTALL)/libpython3.13.a
42+
TARGETMODULESPACK=$(TARGETBUILD)/lib/python313.zip
43+
TARGETMODULES=$(TARGETINSTALL)/lib/
44+
45+
DEPPATH += --dep-path $(CPYTHON_UNPACKNAME)$(DELIM)Programs
46+
VPATH += :$(CPYTHON_UNPACKNAME)$(DELIM)Programs
47+
48+
$(CPYTHON_ZIP):
49+
@echo "Downloading: $(CPYTHON_URL)/$(CPYTHON_ZIP)"
50+
$(Q) $(call DOWNLOAD,$(CPYTHON_URL),$(CPYTHON_ZIP))
51+
52+
$(CPYTHON_UNPACKNAME): $(CPYTHON_ZIP)
53+
@echo "Unpacking: $(CPYTHON_ZIP) -> $(CPYTHON_UNPACKNAME)"
54+
$(Q) $(UNPACK) $(CPYTHON_ZIP)
55+
$(Q) mv cpython-$(CPYTHON_VERSION) $(CPYTHON_UNPACKNAME)
56+
@echo "Patching $(CPYTHON_UNPACKNAME)"
57+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0001-workaround-newlib-resource.h-limitations.patch
58+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0002-fix-various-uint32_t-unsigned-int-type-mismatch-issu.patch
59+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0003-reuse-wasm_assets.py-for-generating-an-archive-of-py.patch
60+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0004-recognize-nuttx-as-a-supported-OS.patch
61+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0005-gh-122907-Fix-Builds-Without-HAVE_DYNAMIC_LOADING-Se.patch
62+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0006-change-var-name-to-avoid-conflict-with-nuttx-unused_.patch
63+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0007-undef-atexit_register.patch
64+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0008-declare-struct-timeval.patch
65+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0009-include-nuttx-sys-select-header-to-define-FD_SETSIZE.patch
66+
$(Q) patch -p1 -d $(CPYTHON_UNPACKNAME) < patch$(DELIM)0010-check-for-the-d_ino-member-of-the-structure-dirent.patch
67+
68+
$(HOSTPYTHON):
69+
mkdir -p $(HOSTBUILD)
70+
mkdir -p $(HOSTINSTALL)
71+
$(Q) ( \
72+
cd $(HOSTBUILD) && $(CPYTHON_PATH)/configure \
73+
--with-pydebug \
74+
--prefix=$(HOSTINSTALL) \
75+
)
76+
$(MAKE) -C $(HOSTBUILD) install
77+
78+
$(TARGETBUILD)/Makefile: $(HOSTPYTHON)
79+
$(Q) mkdir -p $(TARGETBUILD)/Modules
80+
$(Q) mkdir -p $(TARGETMODULES)/python3.13
81+
$(Q) ( cp Setup.local $(TARGETBUILD)/Modules/Setup.local )
82+
$(Q) ( ls -la $(TARGETBUILD)/Modules/Setup.local )
83+
$(Q) ( \
84+
cd $(TARGETBUILD); \
85+
CFLAGS="$(CFLAGS)"; \
86+
ARCH=$(CONFIG_ARCH); \
87+
ARCH_CHIP=$(CONFIG_ARCH_CHIP); \
88+
echo "ARCH: $${ARCH}"; \
89+
echo "ARCH_CHIP: $${ARCH_CHIP}"; \
90+
ARCH="$${ARCH//-/}"; \
91+
ARCH_CHIP="$${ARCH_CHIP//-/}"; \
92+
echo "ARCH: $${ARCH}"; \
93+
echo "ARCH_CHIP: $${ARCH_CHIP}"; \
94+
CFLAGS="$$(echo "$${CFLAGS}" | sed 's/-Os //')" \
95+
CC="$(CC)" \
96+
CXX="$(CXX)" \
97+
AR="$(AR)" \
98+
ARFLAGS=" " \
99+
MACHDEP="$(MACHDEP)" \
100+
OPT="-g -O0 -Wall" \
101+
CONFIG_SITE="$(CONFIG_SITE)" \
102+
$(CPYTHON_PATH)/configure \
103+
--prefix=${TARGETINSTALL} \
104+
--disable-shared \
105+
--host=$${ARCH}-$${ARCH_CHIP}-nuttx \
106+
--build=$(shell $(CPYTHON_PATH)/config.guess) \
107+
--with-build-python=${HOSTPYTHON} \
108+
--without-mimalloc \
109+
--without-pymalloc \
110+
--disable-test-modules \
111+
)
112+
113+
$(TARGETLIBPYTHON): $(TARGETBUILD)/Makefile
114+
$(MAKE) -C $(TARGETBUILD) regen-frozen
115+
$(MAKE) -C $(TARGETBUILD) libpython3.13.a wasm_stdlib
116+
$(Q) ( cp $(TARGETBUILD)/libpython3.13.a $(TARGETLIBPYTHON) )
117+
$(Q) $(UNPACK) $(TARGETMODULESPACK) -d $(TARGETMODULES)/python3.13
118+
119+
CFLAGS += ${INCDIR_PREFIX}$(CPYTHON_PATH)$(DELIM)Include
120+
CFLAGS += ${INCDIR_PREFIX}$(CPYTHON_PATH)$(DELIM)Test
121+
CFLAGS += ${INCDIR_PREFIX}$(CPYTHON_PATH)$(DELIM)Include$(DELIM)internal
122+
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)$(DELIM)system
123+
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)$(DELIM)system$(DELIM)zlib$(DELIM)zlib
124+
CFLAGS += ${INCDIR_PREFIX}$(TARGETBUILD)
125+
126+
MODULE = $(CONFIG_INTERPRETER_CPYTHON)
127+
128+
PROGNAME += $(CONFIG_INTERPRETER_CPYTHON_PROGNAME)
129+
PRIORITY += $(CONFIG_INTERPRETER_CPYTHON_PRIORITY)
130+
STACKSIZE += $(CONFIG_INTERPRETER_CPYTHON_STACKSIZE)
131+
132+
MAINSRC += python.c
133+
134+
PROGNAME += $(CONFIG_INTERPRETER_CPYTHON_MOUNT_MODULES_PROGNAME)
135+
PRIORITY += $(CONFIG_INTERPRETER_CPYTHON_MOUNT_MODULES_PRIORITY)
136+
STACKSIZE += $(CONFIG_INTERPRETER_CPYTHON_MOUNT_MODULES_STACKSIZE)
137+
138+
MAINSRC += mount_modules.c
139+
140+
checkgenromfs:
141+
@genromfs -h 1>/dev/null 2>&1 || { \
142+
echo "Host executable genromfs not available in PATH"; \
143+
echo "You may need to download in from https://romfs.sourceforge.net/"; \
144+
exit 1; \
145+
}
146+
147+
romfs_cpython_modules.img : $(TARGETLIBPYTHON) checkgenromfs
148+
@genromfs -f $@ -d $(TARGETMODULES) -V "ROMFS_Test" || { echo "genromfs failed" ; exit 1 ; }
149+
150+
romfs_cpython_modules.h : romfs_cpython_modules.img
151+
@xxd -i $< >$@ || { echo "xxd of $< failed" ; exit 1 ; }
152+
153+
context:: $(CPYTHON_UNPACKNAME)
154+
155+
depend:: romfs_cpython_modules.h
156+
157+
distclean::
158+
$(call DELDIR, $(BUILDIR))
159+
$(call DELDIR, $(INSTALLDIR))
160+
$(call DELDIR, $(CPYTHON_UNPACKNAME))
161+
$(call DELFILE, $(CPYTHON_ZIP))
162+
$(call DELFILE, romfs_cpython_modules.img)
163+
$(call DELFILE, romfs_cpython_modules.h)
164+
165+
include $(APPDIR)/Application.mk

interpreters/python/Setup.local

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# This file gets copied into the Modules/ folder when building
2+
# newlib configurations which do not support dynamic library
3+
# loading.
4+
5+
*disabled*
6+
_asyncio
7+
_blake2
8+
_bz2
9+
_codecs_cn
10+
_codecs_hk
11+
_codecs_iso2022
12+
_codecs_jp
13+
_codecs_kr
14+
_codecs_tw
15+
_ctypes
16+
_decimal
17+
_elementtree
18+
_hashlib
19+
_heapq
20+
_interpchannels
21+
_interpqueues
22+
_lsprof
23+
_lzma
24+
_md5
25+
_multibytecodec
26+
_sha1
27+
_sha2
28+
_sha2
29+
_sha3
30+
_sha3
31+
_socket
32+
_sqlite3
33+
_ssl
34+
_statistics
35+
_testbuffer
36+
_testcapi
37+
_testclinic
38+
_testclinic_limited
39+
_testexternalinspection
40+
_testinternalcapi
41+
_testlimitedcapi
42+
_uuid
43+
_xxtestfuzz
44+
_zoneinfo
45+
mmap
46+
pwd
47+
pyexpat
48+
readline
49+
resource
50+
xxsubtype

interpreters/python/config.site

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export ac_cv_file__dev_ptmx="no"
2+
export ac_cv_file__dev_ptc="no"
3+
export ac_cv_buggy_getaddrinfo="no"
4+
export ac_cv_func_getaddrinfo="yes"
5+
export ac_cv_pthread_is_default="yes"
6+
export ac_cv_func_acosh="yes"
7+
export ac_cv_func_asinh="yes"
8+
export ac_cv_func_atanh="yes"
9+
export ac_cv_func_erf="yes"
10+
export ac_cv_func_erfc="yes"
11+
export ac_cv_func_expm1="yes"
12+
export ac_cv_func_log1p="yes"
13+
export ac_cv_func_log2="yes"
14+
export ac_cv_func_clock_gettime="yes"
15+
export ac_cv_header_sys_syscall_h="no"
16+
export ac_cv_func_timegm="yes"
17+
export ac_cv_func_clock="yes"
18+
export ac_cv_func_fork="yes"
19+
export ac_cv_func_waitpid="yes"
20+
export ac_cv_func_pipe="yes"
21+
export MODULE_BUILDTYPE="static"

0 commit comments

Comments
 (0)