├── .gitignore ├── 3.5.2 ├── Makefile ├── Setup.local ├── checksums ├── config.site └── patches │ ├── add-emscripten-host.patch │ └── disable-set_inheritable.patch ├── 3.6.13 ├── Makefile ├── Setup.local ├── checksums ├── config.site └── patches │ ├── disable-set_inheritable.patch │ ├── object.patch │ └── pylifecycle.patch ├── 3.6.4 ├── Makefile ├── Setup.local ├── checksums ├── config.site └── patches │ ├── add-emscripten-host.patch │ └── disable-set_inheritable.patch ├── LICENSE ├── README.md ├── examples ├── 01-print │ ├── Makefile │ ├── README.md │ ├── index.html │ ├── lib_files │ └── main.c ├── 02-run-simple-string │ ├── Makefile │ ├── README.md │ ├── index.html │ ├── lib_files │ └── main.c ├── 03-python-app │ ├── Makefile │ ├── README.md │ ├── app │ │ ├── __init__.py │ │ └── __main__.py │ ├── index.html │ ├── lib_files │ └── main.c ├── 04-cython-extension │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── app │ │ ├── __init__.py │ │ └── __main__.py │ ├── index.html │ ├── js.pyx │ ├── lib_files │ └── main.c ├── 05-opengl │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── app │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── loop.h │ │ ├── sdl2.pyx │ │ ├── sdl2.pyxbld │ │ └── sdl2_defs.pxd │ ├── index.html │ ├── lib_files │ └── main.c ├── 06-cython-packages │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── app │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── a.pyx │ │ ├── b.pyx │ │ ├── c.pyx │ │ └── d.pyx │ ├── index.html │ ├── js.pyx │ ├── lib_files │ └── main.c └── common.mk └── utils ├── make_cython_builtins.py └── patch_cython_module.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | downloads 3 | installs 4 | 5 | examples/**/*.o 6 | examples/**/*.js 7 | examples/**/*.data 8 | examples/**/*.wasm 9 | examples/**/*.zip 10 | examples/**/root 11 | -------------------------------------------------------------------------------- /3.5.2/Makefile: -------------------------------------------------------------------------------- 1 | PYVERSION=3.5.2 2 | PYMINOR=$(basename $(PYVERSION)) 3 | 4 | ROOT=$(abspath ..) 5 | 6 | HOSTINSTALL=$(ROOT)/build/$(PYVERSION)/host 7 | HOSTBUILD=$(HOSTINSTALL)/Python-$(PYVERSION) 8 | HOSTPYTHON=$(HOSTINSTALL)/bin/python3$(EXE) 9 | HOSTPGEN=$(HOSTINSTALL)/bin/pgen$(EXE) 10 | 11 | BUILD=$(ROOT)/build/$(PYVERSION)/Python-$(PYVERSION) 12 | INSTALL=$(ROOT)/installs/python-$(PYVERSION) 13 | TARBALL=$(ROOT)/downloads/Python-$(PYVERSION).tgz 14 | URL=https://www.python.org/ftp/python/$(PYVERSION)/Python-$(PYVERSION).tgz 15 | LIB=libpython$(PYMINOR).a 16 | 17 | 18 | all: install 19 | 20 | 21 | install: $(BUILD)/$(LIB) 22 | ( \ 23 | cd $(BUILD); \ 24 | sed -i -e 's/libinstall:.*/libinstall:/' Makefile; \ 25 | emmake make HOSTPYTHON=$(HOSTPYTHON) PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes inclinstall libinstall $(LIB) && \ 26 | cp $(LIB) $(INSTALL)/lib/ && \ 27 | cp $(HOSTINSTALL)/lib/python$(PYMINOR)/_sysconfigdata.py $(INSTALL)/lib/python$(PYMINOR)/ \ 28 | ) 29 | 30 | 31 | clean: 32 | -rm -fr $(HOSTINSTALL) 33 | -rm -fr $(BUILD) 34 | 35 | 36 | $(TARBALL): 37 | [ -d ../downloads ] || mkdir ../downloads 38 | wget -q -O $@ $(URL) 39 | md5sum --quiet --check checksums || (rm $@; false) 40 | 41 | 42 | $(HOSTPYTHON) $(HOSTPGEN): $(TARBALL) 43 | mkdir -p $(HOSTINSTALL) 44 | [ -d $(HOSTBUILD) ] || tar -C $(HOSTINSTALL) -xf $(TARBALL) 45 | ( \ 46 | cd $(HOSTBUILD); \ 47 | ./configure --prefix=$(HOSTINSTALL) && \ 48 | make install && \ 49 | cp Parser/pgen$(EXE) $(HOSTINSTALL)/bin/ && \ 50 | make distclean \ 51 | ) 52 | 53 | 54 | $(BUILD)/.patched: $(TARBALL) 55 | [ -d $(BUILD) ] || (mkdir -p $(dir $(BUILD)); tar -C $(dir $(BUILD)) -xf $(TARBALL)) 56 | cat patches/*.patch | (cd $(BUILD) ; patch -p1) 57 | touch $@ 58 | 59 | 60 | $(BUILD)/Makefile: $(BUILD)/.patched 61 | cp config.site $(BUILD)/ 62 | ( \ 63 | cd $(BUILD); \ 64 | CONFIG_SITE=./config.site READELF=true emconfigure ./configure --without-threads --without-pymalloc --disable-shared --disable-ipv6 --without-gcc --host=asmjs-unknown-emscripten --build=$(shell $(BUILD)/config.guess) --prefix=$(INSTALL) ; \ 65 | ) 66 | 67 | 68 | $(BUILD)/$(LIB): $(BUILD)/Makefile $(HOSTPYTHON) $(HOSTPGEN) Setup.local 69 | cp Setup.local $(BUILD)/Modules/ 70 | ( \ 71 | cd $(BUILD)/Modules/zlib; \ 72 | emconfigure ./configure --static \ 73 | ) 74 | ( \ 75 | cd $(BUILD); \ 76 | emmake make HOSTPYTHON=$(HOSTPYTHON) HOSTPGEN=$(HOSTPGEN) CROSS_COMPILE=yes $(LIB) \ 77 | ) 78 | -------------------------------------------------------------------------------- /3.5.2/Setup.local: -------------------------------------------------------------------------------- 1 | # This file gets copied into the Modules/ folder when building 2 | # newlib configurations which do not support dynamic library 3 | # loading. 4 | 5 | *static* 6 | 7 | array arraymodule.c # array objects 8 | cmath cmathmodule.c _math.c # -lm # complex math library functions 9 | math mathmodule.c _math.c # -lm # math library functions, e.g. sin() 10 | _struct _struct.c # binary structure packing/unpacking 11 | time timemodule.c # -lm # time operations and variables 12 | _operator _operator.c # operator.add() and similar goodies 13 | _random _randommodule.c # Random number generator 14 | _collections _collectionsmodule.c # Container types 15 | _functools _functoolsmodule.c # Tools for working with functions and callable objects 16 | itertools itertoolsmodule.c # Functions creating iterators for efficient looping 17 | _bisect _bisectmodule.c # Bisection algorithms 18 | 19 | _json _json.c 20 | 21 | binascii binascii.c 22 | 23 | zlib zlibmodule.c -IModules/zlib zlib/adler32.c zlib/crc32.c zlib/deflate.c zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c zlib/zutil.c zlib/compress.c zlib/uncompr.c zlib/gzclose.c zlib/gzlib.c zlib/gzread.c zlib/gzwrite.c 24 | 25 | _sha1 sha1module.c 26 | _sha256 sha256module.c 27 | _sha512 sha512module.c 28 | _md5 md5module.c 29 | 30 | #future_builtins future_builtins.c 31 | -------------------------------------------------------------------------------- /3.5.2/checksums: -------------------------------------------------------------------------------- 1 | 3fe8434643a78630c61c6464fe2e7e72 ../downloads/Python-3.5.2.tgz 2 | -------------------------------------------------------------------------------- /3.5.2/config.site: -------------------------------------------------------------------------------- 1 | ac_cv_file__dev_ptmx=no 2 | ac_cv_file__dev_ptc=no 3 | -------------------------------------------------------------------------------- /3.5.2/patches/add-emscripten-host.patch: -------------------------------------------------------------------------------- 1 | diff --git a/configure b/configure 2 | index 8cf777e..263719f 100755 3 | --- a/configure 4 | +++ b/configure 5 | @@ -3202,6 +3202,9 @@ then 6 | *-*-cygwin*) 7 | ac_sys_system=Cygwin 8 | ;; 9 | + asmjs-*-*) 10 | + ac_sys_system=Emscripten 11 | + ;; 12 | *) 13 | # for now, limit cross builds to known configurations 14 | MACHDEP="unknown" 15 | @@ -3248,6 +3251,9 @@ if test "$cross_compiling" = yes; then 16 | *-*-cygwin*) 17 | _host_cpu= 18 | ;; 19 | + asmjs-*-*) 20 | + _host_cpu= 21 | + ;; 22 | *) 23 | # for now, limit cross builds to known configurations 24 | MACHDEP="unknown" 25 | diff --git a/configure.ac b/configure.ac 26 | index 78fe3c7..d7665b4 100644 27 | --- a/configure.ac 28 | +++ b/configure.ac 29 | @@ -322,6 +322,9 @@ then 30 | *-*-cygwin*) 31 | ac_sys_system=Cygwin 32 | ;; 33 | + asmjs-*-*) 34 | + ac_sys_system=Emscripten 35 | + ;; 36 | *) 37 | # for now, limit cross builds to known configurations 38 | MACHDEP="unknown" 39 | @@ -368,6 +371,9 @@ if test "$cross_compiling" = yes; then 40 | *-*-cygwin*) 41 | _host_cpu= 42 | ;; 43 | + asmjs-*-*) 44 | + _host_cpu= 45 | + ;; 46 | *) 47 | # for now, limit cross builds to known configurations 48 | MACHDEP="unknown" 49 | diff --git a/config.sub b/config.sub 50 | index d654d03..0d8236f 100755 51 | --- a/config.sub 52 | +++ b/config.sub 53 | @@ -119,7 +119,8 @@ case $maybe_os in 54 | linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ 55 | knetbsd*-gnu* | netbsd*-gnu* | \ 56 | kopensolaris*-gnu* | \ 57 | - storm-chaos* | os2-emx* | rtmk-nova*) 58 | + storm-chaos* | os2-emx* | rtmk-nova* | \ 59 | + emscripten) 60 | os=-$maybe_os 61 | basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` 62 | ;; 63 | @@ -254,6 +255,7 @@ case $basic_machine in 64 | | am33_2.0 \ 65 | | arc | arceb \ 66 | | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ 67 | + | asmjs \ 68 | | avr | avr32 \ 69 | | be32 | be64 \ 70 | | bfin \ 71 | @@ -1510,6 +1512,8 @@ case $os in 72 | -dicos*) 73 | os=-dicos 74 | ;; 75 | + -emscripten) 76 | + ;; 77 | -nacl*) 78 | ;; 79 | -none) 80 | -------------------------------------------------------------------------------- /3.5.2/patches/disable-set_inheritable.patch: -------------------------------------------------------------------------------- 1 | *** a/Python/fileutils.c 2016-10-25 02:01:16.270148214 +0100 2 | --- b/Python/fileutils.c 2016-10-25 02:01:27.086148626 +0100 3 | *************** 4 | *** 785,790 **** 5 | --- 785,793 ---- 6 | static int 7 | set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) 8 | { 9 | + #ifdef EMSCRIPTEN 10 | + return 0; 11 | + #else 12 | #ifdef MS_WINDOWS 13 | HANDLE handle; 14 | DWORD flags; 15 | *************** 16 | *** 897,902 **** 17 | --- 900,906 ---- 18 | } 19 | return 0; 20 | #endif 21 | + #endif 22 | } 23 | 24 | /* Make the file descriptor non-inheritable. 25 | -------------------------------------------------------------------------------- /3.6.13/Makefile: -------------------------------------------------------------------------------- 1 | PYVERSION=3.6.13 2 | PYMINOR=$(basename $(PYVERSION)) 3 | 4 | ROOT=$(abspath ..) 5 | 6 | HOSTINSTALL=$(ROOT)/build/$(PYVERSION)/host 7 | HOSTBUILD=$(HOSTINSTALL)/Python-$(PYVERSION) 8 | HOSTPYTHON=$(HOSTINSTALL)/bin/python3$(EXE) 9 | 10 | BUILD=$(ROOT)/build/$(PYVERSION)/Python-$(PYVERSION) 11 | INSTALL=$(ROOT)/installs/python-$(PYVERSION) 12 | TARBALL=$(ROOT)/downloads/Python-$(PYVERSION).tgz 13 | URL=https://www.python.org/ftp/python/$(PYVERSION)/Python-$(PYVERSION).tgz 14 | LIB=libpython$(PYMINOR).a 15 | 16 | 17 | all: install 18 | 19 | 20 | install: $(BUILD)/$(LIB) 21 | ( \ 22 | cd $(BUILD); \ 23 | sed -i -e 's/libinstall:.*/libinstall:/' Makefile; \ 24 | emmake make HOSTPYTHON=$(HOSTPYTHON) PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes inclinstall libinstall $(LIB) && \ 25 | cp $(LIB) $(INSTALL)/lib/ && \ 26 | cp $(HOSTINSTALL)/lib/python$(PYMINOR)/_sysconfigdata*.py $(INSTALL)/lib/python$(PYMINOR)/_sysconfigdata.py \ 27 | ) 28 | 29 | 30 | clean: 31 | -rm -fr $(HOSTINSTALL) 32 | -rm -fr $(BUILD) 33 | 34 | 35 | $(TARBALL): 36 | [ -d ../downloads ] || mkdir ../downloads 37 | wget -q -O $@ $(URL) 38 | md5sum --quiet --check checksums || (rm $@; false) 39 | 40 | 41 | $(HOSTPYTHON): $(TARBALL) 42 | mkdir -p $(HOSTINSTALL) 43 | [ -d $(HOSTBUILD) ] || tar -C $(HOSTINSTALL) -xf $(TARBALL) 44 | ( cd $(HOSTBUILD); ./configure --prefix=$(HOSTINSTALL) ) 45 | $(MAKE) -C $(HOSTBUILD) install 46 | $(MAKE) -C $(HOSTBUILD) distclean 47 | 48 | 49 | $(BUILD)/.patched: $(TARBALL) 50 | [ -d $(BUILD) ] || (mkdir -p $(dir $(BUILD)); tar -C $(dir $(BUILD)) -xf $(TARBALL)) 51 | cat patches/*.patch | (cd $(BUILD) ; patch -p1) 52 | touch $@ 53 | 54 | 55 | $(BUILD)/Makefile: $(BUILD)/.patched 56 | cp config.site $(BUILD)/ 57 | ( \ 58 | cd $(BUILD); \ 59 | CONFIG_SITE=./config.site READELF=true emconfigure ./configure --without-threads --without-pymalloc --disable-shared --disable-ipv6 --without-gcc --build=$(shell $(BUILD)/config.guess) --prefix=$(INSTALL) ; \ 60 | ) 61 | 62 | 63 | $(BUILD)/$(LIB): $(BUILD)/Makefile $(HOSTPYTHON) Setup.local 64 | cp Setup.local $(BUILD)/Modules/ 65 | ( \ 66 | cd $(BUILD)/Modules/zlib; \ 67 | emconfigure ./configure --static \ 68 | ) 69 | ( \ 70 | cd $(BUILD); \ 71 | emmake make HOSTPYTHON=$(HOSTPYTHON) CROSS_COMPILE=yes $(LIB) \ 72 | ) 73 | -------------------------------------------------------------------------------- /3.6.13/Setup.local: -------------------------------------------------------------------------------- 1 | # This file gets copied into the Modules/ folder when building 2 | # newlib configurations which do not support dynamic library 3 | # loading. 4 | 5 | *static* 6 | 7 | array arraymodule.c # array objects 8 | cmath cmathmodule.c _math.c # -lm # complex math library functions 9 | math mathmodule.c _math.c # -lm # math library functions, e.g. sin() 10 | _struct _struct.c # binary structure packing/unpacking 11 | time timemodule.c # -lm # time operations and variables 12 | _operator _operator.c # operator.add() and similar goodies 13 | _random _randommodule.c # Random number generator 14 | _collections _collectionsmodule.c # Container types 15 | _functools _functoolsmodule.c # Tools for working with functions and callable objects 16 | itertools itertoolsmodule.c # Functions creating iterators for efficient looping 17 | _bisect _bisectmodule.c # Bisection algorithms 18 | 19 | _json _json.c 20 | 21 | binascii binascii.c 22 | 23 | zlib zlibmodule.c -IModules/zlib zlib/adler32.c zlib/crc32.c zlib/deflate.c zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c zlib/zutil.c zlib/compress.c zlib/uncompr.c zlib/gzclose.c zlib/gzlib.c zlib/gzread.c zlib/gzwrite.c 24 | 25 | _sha1 sha1module.c 26 | _sha256 sha256module.c 27 | _sha512 sha512module.c 28 | _md5 md5module.c 29 | 30 | #future_builtins future_builtins.c 31 | -------------------------------------------------------------------------------- /3.6.13/checksums: -------------------------------------------------------------------------------- 1 | 92fcbf417c691d42c47a3d82f9c255fd ../downloads/Python-3.6.13.tgz 2 | -------------------------------------------------------------------------------- /3.6.13/config.site: -------------------------------------------------------------------------------- 1 | ac_cv_file__dev_ptmx=no 2 | ac_cv_file__dev_ptc=no 3 | -------------------------------------------------------------------------------- /3.6.13/patches/disable-set_inheritable.patch: -------------------------------------------------------------------------------- 1 | *** a/Python/fileutils.c 2016-10-25 02:01:16.270148214 +0100 2 | --- b/Python/fileutils.c 2016-10-25 02:01:27.086148626 +0100 3 | *************** 4 | *** 785,790 **** 5 | --- 785,793 ---- 6 | static int 7 | set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) 8 | { 9 | + #ifdef EMSCRIPTEN 10 | + return 0; 11 | + #else 12 | #ifdef MS_WINDOWS 13 | HANDLE handle; 14 | DWORD flags; 15 | *************** 16 | *** 897,902 **** 17 | --- 900,906 ---- 18 | } 19 | return 0; 20 | #endif 21 | + #endif 22 | } 23 | 24 | /* Make the file descriptor non-inheritable. 25 | -------------------------------------------------------------------------------- /3.6.13/patches/object.patch: -------------------------------------------------------------------------------- 1 | *** a/Objects/object.c 2021-02-16 01:30:33.000000000 +0000 2 | --- b/Objects/object.c 2021-03-05 17:49:26.170625042 +0000 3 | *************** 4 | *** 464,482 **** 5 | --- 464,488 ---- 6 | return; 7 | } 8 | 9 | + #ifdef WITH_THREAD 10 | PyGILState_STATE gil; 11 | + #endif // WITH_THREAD 12 | PyObject *error_type, *error_value, *error_traceback; 13 | 14 | fprintf(stderr, "object : "); 15 | fflush(stderr); 16 | + #ifdef WITH_THREAD 17 | gil = PyGILState_Ensure(); 18 | + #endif // WITH_THREAD 19 | 20 | PyErr_Fetch(&error_type, &error_value, &error_traceback); 21 | (void)PyObject_Print(op, stderr, 0); 22 | fflush(stderr); 23 | PyErr_Restore(error_type, error_value, error_traceback); 24 | 25 | + #ifdef WITH_THREAD 26 | PyGILState_Release(gil); 27 | + #endif // WITH_THREAD 28 | /* XXX(twouters) cast refcount to long until %zd is 29 | universally available */ 30 | fprintf(stderr, "\n" 31 | -------------------------------------------------------------------------------- /3.6.13/patches/pylifecycle.patch: -------------------------------------------------------------------------------- 1 | *** a/Python/pylifecycle.c 2021-02-16 01:30:33.000000000 +0000 2 | --- b/Python/pylifecycle.c 2021-03-05 18:34:24.910724024 +0000 3 | *************** 4 | *** 229,234 **** 5 | --- 229,236 ---- 6 | char codepage[100]; 7 | PyOS_snprintf(codepage, sizeof(codepage), "cp%d", GetACP()); 8 | return get_codec_name(codepage); 9 | + #elif defined(__EMSCRIPTEN__) 10 | + return get_codec_name("UTF-8"); 11 | #elif defined(HAVE_LANGINFO_H) && defined(CODESET) 12 | char* codeset = nl_langinfo(CODESET); 13 | if (!codeset || codeset[0] == '\0') { 14 | *************** 15 | *** 998,1003 **** 16 | --- 1000,1006 ---- 17 | if (Py_FileSystemDefaultEncoding == NULL) 18 | { 19 | Py_FileSystemDefaultEncoding = get_locale_encoding(); 20 | + Py_FileSystemDefaultEncoding = "utf-8"; 21 | if (Py_FileSystemDefaultEncoding == NULL) 22 | Py_FatalError("Py_Initialize: Unable to get the locale encoding"); 23 | 24 | *************** 25 | *** 1422,1427 **** 26 | --- 1425,1431 ---- 27 | fprintf(stderr, "Fatal Python error: %s\n", msg); 28 | fflush(stderr); /* it helps in Windows debug build */ 29 | 30 | + #ifdef WITH_THREAD 31 | /* Check if the current thread has a Python thread state 32 | and holds the GIL */ 33 | PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); 34 | *************** 35 | *** 1437,1442 **** 36 | --- 1441,1449 ---- 37 | which has no Python thread state. */ 38 | } 39 | int has_tstate_and_gil = (tss_tstate != NULL); 40 | + #else // WITH_THREAD 41 | + int has_tstate_and_gil = 0; 42 | + #endif // WITH_THREAD 43 | 44 | if (has_tstate_and_gil) { 45 | -------------------------------------------------------------------------------- /3.6.4/Makefile: -------------------------------------------------------------------------------- 1 | PYVERSION=3.6.4 2 | PYMINOR=$(basename $(PYVERSION)) 3 | 4 | ROOT=$(abspath ..) 5 | 6 | HOSTINSTALL=$(ROOT)/build/$(PYVERSION)/host 7 | HOSTBUILD=$(HOSTINSTALL)/Python-$(PYVERSION) 8 | HOSTPYTHON=$(HOSTINSTALL)/bin/python3$(EXE) 9 | HOSTPGEN=$(HOSTINSTALL)/bin/pgen$(EXE) 10 | 11 | BUILD=$(ROOT)/build/$(PYVERSION)/Python-$(PYVERSION) 12 | INSTALL=$(ROOT)/installs/python-$(PYVERSION) 13 | TARBALL=$(ROOT)/downloads/Python-$(PYVERSION).tgz 14 | URL=https://www.python.org/ftp/python/$(PYVERSION)/Python-$(PYVERSION).tgz 15 | LIB=libpython$(PYMINOR).a 16 | 17 | 18 | all: install 19 | 20 | 21 | install: $(BUILD)/$(LIB) 22 | ( \ 23 | cd $(BUILD); \ 24 | sed -i -e 's/libinstall:.*/libinstall:/' Makefile; \ 25 | emmake make HOSTPYTHON=$(HOSTPYTHON) PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes inclinstall libinstall $(LIB) && \ 26 | cp $(LIB) $(INSTALL)/lib/ && \ 27 | cp $(HOSTINSTALL)/lib/python$(PYMINOR)/`$(HOSTPYTHON) -c "import sysconfig; print(sysconfig._get_sysconfigdata_name())"`.py $(INSTALL)/lib/python$(PYMINOR)/_sysconfigdata__emscripten_x86_64-linux-gnu.py \ 28 | ) 29 | 30 | 31 | clean: 32 | -rm -fr $(HOSTINSTALL) 33 | -rm -fr $(BUILD) 34 | 35 | 36 | $(TARBALL): 37 | [ -d ../downloads ] || mkdir ../downloads 38 | wget -q -O $@ $(URL) 39 | md5sum --quiet --check checksums || (rm $@; false) 40 | 41 | 42 | $(HOSTPYTHON) $(HOSTPGEN): $(TARBALL) 43 | mkdir -p $(HOSTINSTALL) 44 | [ -d $(HOSTBUILD) ] || tar -C $(HOSTINSTALL) -xf $(TARBALL) 45 | ( \ 46 | cd $(HOSTBUILD); \ 47 | ./configure --prefix=$(HOSTINSTALL) && \ 48 | make regen-grammar && \ 49 | make install && \ 50 | cp Parser/pgen$(EXE) $(HOSTINSTALL)/bin/ && \ 51 | make distclean \ 52 | ) 53 | 54 | 55 | $(BUILD)/.patched: $(TARBALL) 56 | [ -d $(BUILD) ] || (mkdir -p $(dir $(BUILD)); tar -C $(dir $(BUILD)) -xf $(TARBALL)) 57 | cat patches/*.patch | (cd $(BUILD) ; patch -p1) 58 | touch $@ 59 | 60 | 61 | $(BUILD)/Makefile: $(BUILD)/.patched 62 | cp config.site $(BUILD)/ 63 | ( \ 64 | cd $(BUILD); \ 65 | CONFIG_SITE=./config.site READELF=true emconfigure ./configure --without-threads --without-pymalloc --disable-shared --disable-ipv6 --without-gcc --host=asmjs-unknown-emscripten --build=$(shell $(BUILD)/config.guess) --prefix=$(INSTALL) ; \ 66 | ) 67 | 68 | 69 | $(BUILD)/$(LIB): $(BUILD)/Makefile $(HOSTPYTHON) $(HOSTPGEN) Setup.local 70 | cp Setup.local $(BUILD)/Modules/ 71 | ( \ 72 | cd $(BUILD)/Modules/zlib; \ 73 | emconfigure ./configure --static \ 74 | ) 75 | ( \ 76 | cd $(BUILD); \ 77 | emmake make HOSTPYTHON=$(HOSTPYTHON) HOSTPGEN=$(HOSTPGEN) CROSS_COMPILE=yes $(LIB) \ 78 | ) 79 | -------------------------------------------------------------------------------- /3.6.4/Setup.local: -------------------------------------------------------------------------------- 1 | # This file gets copied into the Modules/ folder when building 2 | # newlib configurations which do not support dynamic library 3 | # loading. 4 | 5 | *static* 6 | 7 | array arraymodule.c # array objects 8 | cmath cmathmodule.c _math.c # -lm # complex math library functions 9 | math mathmodule.c _math.c # -lm # math library functions, e.g. sin() 10 | _struct _struct.c # binary structure packing/unpacking 11 | time timemodule.c # -lm # time operations and variables 12 | _operator _operator.c # operator.add() and similar goodies 13 | _random _randommodule.c # Random number generator 14 | _collections _collectionsmodule.c # Container types 15 | _functools _functoolsmodule.c # Tools for working with functions and callable objects 16 | itertools itertoolsmodule.c # Functions creating iterators for efficient looping 17 | _bisect _bisectmodule.c # Bisection algorithms 18 | 19 | _json _json.c 20 | 21 | binascii binascii.c 22 | 23 | zlib zlibmodule.c -IModules/zlib zlib/adler32.c zlib/crc32.c zlib/deflate.c zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c zlib/zutil.c zlib/compress.c zlib/uncompr.c zlib/gzclose.c zlib/gzlib.c zlib/gzread.c zlib/gzwrite.c 24 | 25 | _sha1 sha1module.c 26 | _sha256 sha256module.c 27 | _sha512 sha512module.c 28 | _md5 md5module.c 29 | 30 | #future_builtins future_builtins.c 31 | -------------------------------------------------------------------------------- /3.6.4/checksums: -------------------------------------------------------------------------------- 1 | 9de6494314ea199e3633211696735f65 ../downloads/Python-3.6.4.tgz 2 | -------------------------------------------------------------------------------- /3.6.4/config.site: -------------------------------------------------------------------------------- 1 | ac_cv_file__dev_ptmx=no 2 | ac_cv_file__dev_ptc=no 3 | -------------------------------------------------------------------------------- /3.6.4/patches/add-emscripten-host.patch: -------------------------------------------------------------------------------- 1 | diff --git a/configure b/configure 2 | index 8cf777e..263719f 100755 3 | --- a/configure 4 | +++ b/configure 5 | @@ -3202,6 +3202,9 @@ then 6 | *-*-cygwin*) 7 | ac_sys_system=Cygwin 8 | ;; 9 | + asmjs-*-*) 10 | + ac_sys_system=Emscripten 11 | + ;; 12 | *) 13 | # for now, limit cross builds to known configurations 14 | MACHDEP="unknown" 15 | @@ -3248,6 +3251,9 @@ if test "$cross_compiling" = yes; then 16 | *-*-cygwin*) 17 | _host_cpu= 18 | ;; 19 | + asmjs-*-*) 20 | + _host_cpu= 21 | + ;; 22 | *) 23 | # for now, limit cross builds to known configurations 24 | MACHDEP="unknown" 25 | diff --git a/configure.ac b/configure.ac 26 | index 78fe3c7..d7665b4 100644 27 | --- a/configure.ac 28 | +++ b/configure.ac 29 | @@ -322,6 +322,9 @@ then 30 | *-*-cygwin*) 31 | ac_sys_system=Cygwin 32 | ;; 33 | + asmjs-*-*) 34 | + ac_sys_system=Emscripten 35 | + ;; 36 | *) 37 | # for now, limit cross builds to known configurations 38 | MACHDEP="unknown" 39 | @@ -368,6 +371,9 @@ if test "$cross_compiling" = yes; then 40 | *-*-cygwin*) 41 | _host_cpu= 42 | ;; 43 | + asmjs-*-*) 44 | + _host_cpu= 45 | + ;; 46 | *) 47 | # for now, limit cross builds to known configurations 48 | MACHDEP="unknown" 49 | diff --git a/config.sub b/config.sub 50 | index d654d03..0d8236f 100755 51 | --- a/config.sub 52 | +++ b/config.sub 53 | @@ -119,7 +119,8 @@ case $maybe_os in 54 | linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ 55 | knetbsd*-gnu* | netbsd*-gnu* | \ 56 | kopensolaris*-gnu* | cloudabi*-eabi* | \ 57 | - storm-chaos* | os2-emx* | rtmk-nova*) 58 | + storm-chaos* | os2-emx* | rtmk-nova* | \ 59 | + emscripten) 60 | os=-$maybe_os 61 | basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` 62 | ;; 63 | @@ -254,6 +255,7 @@ case $basic_machine in 64 | | am33_2.0 \ 65 | | arc | arceb \ 66 | | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ 67 | + | asmjs \ 68 | | avr | avr32 \ 69 | | be32 | be64 \ 70 | | bfin \ 71 | @@ -1510,6 +1512,8 @@ case $os in 72 | -dicos*) 73 | os=-dicos 74 | ;; 75 | + -emscripten) 76 | + ;; 77 | -nacl*) 78 | ;; 79 | -none) 80 | -------------------------------------------------------------------------------- /3.6.4/patches/disable-set_inheritable.patch: -------------------------------------------------------------------------------- 1 | *** a/Python/fileutils.c 2016-10-25 02:01:16.270148214 +0100 2 | --- b/Python/fileutils.c 2016-10-25 02:01:27.086148626 +0100 3 | *************** 4 | *** 785,790 **** 5 | --- 785,793 ---- 6 | static int 7 | set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) 8 | { 9 | + #ifdef EMSCRIPTEN 10 | + return 0; 11 | + #else 12 | #ifdef MS_WINDOWS 13 | HANDLE handle; 14 | DWORD flags; 15 | *************** 16 | *** 897,902 **** 17 | --- 900,906 ---- 18 | } 19 | return 0; 20 | #endif 21 | + #endif 22 | } 23 | 24 | /* Make the file descriptor non-inheritable. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Patches to the Python source code and build system are covered by the same 2 | license as Python itself - the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2. 3 | 4 | Everything else is made available under the MIT license: 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2016 Jim Bailey 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python in the browser 2 | 3 | The aim of this project is to make Python usable in the browser. This is done 4 | using the standard Python implementation (CPython) compiled with emscripten to 5 | generate an Web Assembly library. 6 | 7 | The benefits of this approach are: 8 | 9 | * This gives access to a full Python implementation. 10 | * Wasm can be pretty fast, so the interpreter is still quite useful. 11 | * It supports existing extension modules. 12 | * It supports Cython for speeding up the code and binding to C/C++. 13 | 14 | If you have a Python application using SDL (1 or 2) and maybe OpenGLES 2 then 15 | this project could help you deliver it via the browser. 16 | 17 | # Prerequesits 18 | 19 | The build requires a complete development toolchain for the build system. This 20 | is used to build the portions of Python required for bootstrapping the complete 21 | Python build. 22 | 23 | Emscripten is also required for the cross compilation. Emsdk 2.0.1 has been 24 | tested, and there are known issues with 2.0.2 - 2.0.14. 25 | 26 | Some of the examples use Cython which can be installed with pip. Versions 27 | 0.20.1 and above have been used successfully. 28 | 29 | # Credits 30 | 31 | Many of the patches and instructions are derived from the excellent work of 32 | Marat Dukhan on the [EmCPython](https://github.com/PeachPy/EmCPython) project. 33 | 34 | # Python Versions 35 | 36 | ## 3.6.13 37 | -------------------------------------------------------------------------------- /examples/01-print/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | 4 | all: python.js 5 | 6 | 7 | python.js: main.o root 8 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 9 | 10 | 11 | clean: 12 | -rm -fr root 13 | -rm python.js python.data 14 | -rm *.o 15 | -------------------------------------------------------------------------------- /examples/01-print/README.md: -------------------------------------------------------------------------------- 1 | # Printing from Python to the browser console 2 | 3 | This example includes a typical main() entry point that initializes the Python 4 | interpreter. It then runs a single line of Python code, printing a message. 5 | This message should appear on the browser's console (part of the development 6 | tools that come with many browsers). 7 | 8 | # Building 9 | 10 | Run ```make```. 11 | 12 | # Running 13 | 14 | Run ```make serve``` to start a web server on local port 8062 (this requires 15 | Python) and then visit the test page 16 | [http://localhost:8062/](http://localhost:8062/). 17 | 18 | It will take a while to start up as only limited attempts have been made at 19 | reducing the initial file system. Once it has started go to the developer 20 | console and you should see some output. 21 | -------------------------------------------------------------------------------- /examples/01-print/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Please check the developer console, it should contain a 8 | message from Python. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/01-print/lib_files: -------------------------------------------------------------------------------- 1 | lib/python3.6/encodings/__init__.py 2 | lib/python3.6/codecs.py 3 | lib/python3.6/encodings 4 | lib/python3.6/encodings/aliases.py 5 | lib/python3.6/encodings/utf_8.py 6 | lib/python3.6/encodings/latin_1.py 7 | lib/python3.6/io.py 8 | lib/python3.6/abc.py 9 | lib/python3.6/_weakrefset.py 10 | lib/python3.6/site.py 11 | lib/python3.6/os.py 12 | lib/python3.6/stat.py 13 | lib/python3.6/posixpath.py 14 | lib/python3.6/genericpath.py 15 | lib/python3.6/_collections_abc.py 16 | lib/python3.6/_sitebuiltins.py 17 | lib/python3.6/sysconfig.py 18 | lib/python3.6/_sysconfigdata.py 19 | -------------------------------------------------------------------------------- /examples/01-print/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | EMSCRIPTEN_KEEPALIVE 8 | int main(int argc, char** argv) { 9 | setenv("PYTHONHOME", "/", 0); 10 | setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0); 11 | 12 | Py_InitializeEx(0); 13 | PyRun_SimpleString("print('Success - Python has printed to the browser console.')"); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/02-run-simple-string/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | LDFLAGS += -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' 4 | LDFLAGS += -s EXPORTED_FUNCTIONS='["_main","_PyRun_SimpleString"]' 5 | 6 | all: python.js 7 | 8 | 9 | python.js: main.o root 10 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 11 | 12 | 13 | clean: 14 | -rm -fr root 15 | -rm python.js python.data 16 | -rm *.o 17 | -------------------------------------------------------------------------------- /examples/02-run-simple-string/README.md: -------------------------------------------------------------------------------- 1 | # Printing from Python to the browser console 2 | 3 | This example includes a typical main() entry point that initializes the Python 4 | interpreter. It also exports PyRun_SimpleString() making it available to 5 | Javascript. The code in index.html binds this function as pyexec() and then 6 | gives an example of using it. 7 | 8 | # Building 9 | 10 | Run ```make```. 11 | 12 | # Running 13 | 14 | Run ```make serve``` to start a web server on local port 8062 (this requires 15 | Python) and then visit the test page 16 | [http://localhost:8062/](http://localhost:8062/). 17 | 18 | # The root filesystem 19 | 20 | This example includes a minimal root filesystem for Python instead of the full 21 | one used in example 1. This is to show how small an application could be. 22 | The root folder could be replaced with example 1's and rebuilt for a batteries 23 | included experience. 24 | 25 | The list of modules was generated by starting off with a full root folder 26 | and then running: 27 | 28 | ```pyexec("import sys ; print('\\n'.join(m.__file__ 29 | for m in sys.modules.values() if hasattr(m, '__file__')))")``` 30 | -------------------------------------------------------------------------------- /examples/02-run-simple-string/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Please check the developer console, it should contain a 8 | message from Python. 9 | 10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/02-run-simple-string/lib_files: -------------------------------------------------------------------------------- 1 | lib/python3.6/posixpath.py 2 | lib/python3.6/sysconfig.py 3 | lib/python3.6/genericpath.py 4 | lib/python3.6/_weakrefset.py 5 | lib/python3.6/encodings/__init__.py 6 | lib/python3.6/stat.py 7 | lib/python3.6/io.py 8 | lib/python3.6/codecs.py 9 | lib/python3.6/site.py 10 | lib/python3.6/encodings/latin_1.py 11 | lib/python3.6/encodings/utf_8.py 12 | lib/python3.6/_sitebuiltins.py 13 | lib/python3.6/posixpath.py 14 | lib/python3.6/_collections_abc.py 15 | lib/python3.6/abc.py 16 | lib/python3.6/encodings/aliases.py 17 | lib/python3.6/_sysconfigdata.py 18 | lib/python3.6/os.py 19 | -------------------------------------------------------------------------------- /examples/02-run-simple-string/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | int main(int argc, char** argv) { 8 | setenv("PYTHONHOME", "/", 0); 9 | setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0); 10 | 11 | Py_InitializeEx(0); 12 | 13 | emscripten_exit_with_live_runtime(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/03-python-app/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | 4 | all: python.js app.zip 5 | 6 | 7 | python.js: main.o root 8 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 9 | 10 | 11 | app.zip: app 12 | zip -r $@ $< 13 | 14 | 15 | clean: 16 | -rm -fr root 17 | -rm python.js python.data app.zip 18 | -rm *.o 19 | -------------------------------------------------------------------------------- /examples/03-python-app/README.md: -------------------------------------------------------------------------------- 1 | # Serving a pure Python application 2 | 3 | This example demonstrates how a Python application can be run without having to 4 | recompile/relink the main Python files for every update. This can be very 5 | helpful during development as the linking step is very slow. 6 | 7 | The Makefile still produces the these two files: 8 | 9 | * python.asm.js - Python compiled to asm.js 10 | * python.asm.data - A root filesystem required to initialize Python 11 | 12 | The Makefile also bundles everything in the app/ directory into a third file 13 | called app.zip. The main program fetches app.zip from the server and adds it to 14 | Python's path, then executes it like a module. This is equivalent to running 15 | ```python -m app``` on the command line. 16 | 17 | Because zipping up the app directory is typically much faster than linking this 18 | process helps reduce the development cycle. 19 | 20 | # Building 21 | 22 | Run ```make```. 23 | 24 | # Running 25 | 26 | Run ```make serve``` to start a web server on local port 8062 (this requires 27 | Python) and then visit the test page 28 | [http://localhost:8062/](http://localhost:8062/). -------------------------------------------------------------------------------- /examples/03-python-app/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgym/cpython-emscripten/009ba956d0791d89e4000df06c611a40f4408ad8/examples/03-python-app/app/__init__.py -------------------------------------------------------------------------------- /examples/03-python-app/app/__main__.py: -------------------------------------------------------------------------------- 1 | print("Success - the app is running: {}".format(__file__)); 2 | -------------------------------------------------------------------------------- /examples/03-python-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Please check the developer console, it should contain a 8 | message from Python. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/03-python-app/lib_files: -------------------------------------------------------------------------------- 1 | lib/python3.6/_collections_abc.py 2 | lib/python3.6/_dummy_thread.py 3 | lib/python3.6/_sitebuiltins.py 4 | lib/python3.6/_sysconfigdata.py 5 | lib/python3.6/_weakrefset.py 6 | lib/python3.6/abc.py 7 | lib/python3.6/codecs.py 8 | lib/python3.6/collections/__init__.py 9 | lib/python3.6/collections/abc.py 10 | lib/python3.6/contextlib.py 11 | lib/python3.6/encodings/__init__.py 12 | lib/python3.6/encodings/aliases.py 13 | lib/python3.6/encodings/cp437.py 14 | lib/python3.6/encodings/latin_1.py 15 | lib/python3.6/encodings/utf_8.py 16 | lib/python3.6/functools.py 17 | lib/python3.6/genericpath.py 18 | lib/python3.6/heapq.py 19 | lib/python3.6/importlib/__init__.py 20 | lib/python3.6/importlib/_bootstrap.py 21 | lib/python3.6/importlib/_bootstrap_external.py 22 | lib/python3.6/importlib/abc.py 23 | lib/python3.6/importlib/machinery.py 24 | lib/python3.6/importlib/util.py 25 | lib/python3.6/io.py 26 | lib/python3.6/keyword.py 27 | lib/python3.6/operator.py 28 | lib/python3.6/os.py 29 | lib/python3.6/pkgutil.py 30 | lib/python3.6/posixpath.py 31 | lib/python3.6/reprlib.py 32 | lib/python3.6/runpy.py 33 | lib/python3.6/site.py 34 | lib/python3.6/stat.py 35 | lib/python3.6/sysconfig.py 36 | lib/python3.6/types.py 37 | lib/python3.6/warnings.py 38 | lib/python3.6/weakref.py 39 | -------------------------------------------------------------------------------- /examples/03-python-app/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | static void onload(const char *filename) { 9 | printf("Loaded %s.\n", filename); 10 | PyRun_SimpleString("import sys ; sys.path.insert(0, '/app.zip')"); 11 | PyRun_SimpleString("import runpy ; runpy.run_module('app')"); 12 | } 13 | 14 | 15 | static void onloaderror(const char *filename) { 16 | printf("Failed to load %s, aborting.\n", filename); 17 | PyRun_SimpleString("print('fail')"); 18 | } 19 | 20 | 21 | int main(int argc, char** argv) { 22 | setenv("PYTHONHOME", "/", 0); 23 | setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0); 24 | 25 | Py_InitializeEx(0); 26 | 27 | // Fetch app.zip from the server. 28 | emscripten_async_wget("app.zip", "/app.zip", onload, onloaderror); 29 | 30 | emscripten_exit_with_live_runtime(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /examples/04-cython-extension/.gitignore: -------------------------------------------------------------------------------- 1 | js.c 2 | -------------------------------------------------------------------------------- /examples/04-cython-extension/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | 4 | all: python.js app.zip 5 | 6 | 7 | python.js: main.o js.o root 8 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 9 | 10 | 11 | %.c: %.pyx 12 | cython $< 13 | 14 | 15 | app.zip: app 16 | rm -f $@ 17 | zip -r $@ $< 18 | 19 | 20 | clean: 21 | -rm -fr root 22 | -rm python.js python.data app.zip 23 | -rm *.o 24 | -------------------------------------------------------------------------------- /examples/04-cython-extension/README.md: -------------------------------------------------------------------------------- 1 | # Compiling, linking and using Cython modules 2 | 3 | This example uses a Cython module to expose the emscripten_run_script() 4 | function. 5 | 6 | The Cython file is compiled to a c file which is compiled and linked in with 7 | the interpreter. 8 | 9 | The c file has an init function that must be called before it can be imported. 10 | The main file calls this init function after initializing the Python 11 | interpreter. 12 | 13 | # Building 14 | 15 | Run ```make```. 16 | 17 | # Running 18 | 19 | Run ```make serve``` to start a web server on local port 8062 (this requires 20 | Python) and then visit the test page 21 | [http://localhost:8062/](http://localhost:8062/). 22 | -------------------------------------------------------------------------------- /examples/04-cython-extension/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgym/cpython-emscripten/009ba956d0791d89e4000df06c611a40f4408ad8/examples/04-cython-extension/app/__init__.py -------------------------------------------------------------------------------- /examples/04-cython-extension/app/__main__.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import js 4 | 5 | 6 | message = "Success - the app is running: {}".format(__file__) 7 | code = ''' 8 | let node = document.createElement('br'); 9 | document.body.appendChild(node); 10 | 11 | node = document.createTextNode({}); 12 | document.body.appendChild(node); 13 | '''.format(json.dumps(message)) 14 | js.run(bytes(code, 'utf8')) 15 | -------------------------------------------------------------------------------- /examples/04-cython-extension/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | The app should display a message below: 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/04-cython-extension/js.pyx: -------------------------------------------------------------------------------- 1 | cdef extern from "emscripten.h": 2 | void emscripten_run_script(const char *) 3 | 4 | 5 | def run(code): 6 | emscripten_run_script(code) 7 | -------------------------------------------------------------------------------- /examples/04-cython-extension/lib_files: -------------------------------------------------------------------------------- 1 | lib/python3.6/_collections_abc.py 2 | lib/python3.6/_dummy_thread.py 3 | lib/python3.6/_sitebuiltins.py 4 | lib/python3.6/_sysconfigdata.py 5 | lib/python3.6/_weakrefset.py 6 | lib/python3.6/abc.py 7 | lib/python3.6/codecs.py 8 | lib/python3.6/collections/__init__.py 9 | lib/python3.6/collections/abc.py 10 | lib/python3.6/contextlib.py 11 | lib/python3.6/copyreg.py 12 | lib/python3.6/encodings/__init__.py 13 | lib/python3.6/encodings/aliases.py 14 | lib/python3.6/encodings/cp437.py 15 | lib/python3.6/encodings/latin_1.py 16 | lib/python3.6/encodings/utf_8.py 17 | lib/python3.6/enum.py 18 | lib/python3.6/functools.py 19 | lib/python3.6/genericpath.py 20 | lib/python3.6/heapq.py 21 | lib/python3.6/importlib/__init__.py 22 | lib/python3.6/importlib/_bootstrap.py 23 | lib/python3.6/importlib/_bootstrap_external.py 24 | lib/python3.6/importlib/abc.py 25 | lib/python3.6/importlib/machinery.py 26 | lib/python3.6/importlib/util.py 27 | lib/python3.6/io.py 28 | lib/python3.6/json/decoder.py 29 | lib/python3.6/json/encoder.py 30 | lib/python3.6/json/__init__.py 31 | lib/python3.6/json/scanner.py 32 | lib/python3.6/keyword.py 33 | lib/python3.6/operator.py 34 | lib/python3.6/os.py 35 | lib/python3.6/pkgutil.py 36 | lib/python3.6/posixpath.py 37 | lib/python3.6/re.py 38 | lib/python3.6/reprlib.py 39 | lib/python3.6/runpy.py 40 | lib/python3.6/site.py 41 | lib/python3.6/sre_compile.py 42 | lib/python3.6/sre_constants.py 43 | lib/python3.6/sre_parse.py 44 | lib/python3.6/stat.py 45 | lib/python3.6/sysconfig.py 46 | lib/python3.6/types.py 47 | lib/python3.6/warnings.py 48 | lib/python3.6/weakref.py 49 | -------------------------------------------------------------------------------- /examples/04-cython-extension/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | #if PY_MAJOR_VERSION < 3 9 | PyMODINIT_FUNC initjs(void); 10 | #else 11 | PyMODINIT_FUNC PyInit_js(void); 12 | #endif 13 | 14 | 15 | static void onload(const char *filename) { 16 | printf("Loaded %s.\n", filename); 17 | PyRun_SimpleString("import sys ; sys.path.insert(0, '/app.zip')"); 18 | PyRun_SimpleString("import runpy ; runpy.run_module('app')"); 19 | } 20 | 21 | 22 | static void onloaderror(const char *filename) { 23 | printf("Failed to load %s, aborting.\n", filename); 24 | PyRun_SimpleString("print('fail')"); 25 | } 26 | 27 | 28 | int main(int argc, char** argv) { 29 | setenv("PYTHONHOME", "/", 0); 30 | setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0); 31 | 32 | Py_InitializeEx(0); 33 | #if PY_MAJOR_VERSION < 3 34 | initjs(); 35 | #else 36 | PyInit_js(); 37 | #endif 38 | 39 | // Fetch app.zip from the server. 40 | emscripten_async_wget("app.zip", "/app.zip", onload, onloaderror); 41 | 42 | emscripten_exit_with_live_runtime(); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /examples/05-opengl/.gitignore: -------------------------------------------------------------------------------- 1 | app/sdl2.c 2 | app/sdl2.pyxbldc 3 | -------------------------------------------------------------------------------- /examples/05-opengl/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | CFLAGS += -s USE_SDL=2 4 | LDFLAGS += -s USE_SDL=2 --closure 0 5 | 6 | 7 | all: python.js app.zip 8 | 9 | 10 | python.js: main.o app/sdl2.o root 11 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 12 | 13 | 14 | app.zip: app 15 | rm -f $@ 16 | zip -r $@ app/*.py 17 | 18 | 19 | clean: 20 | -rm -fr root 21 | -rm python.js python.data app.zip 22 | -rm *.o 23 | 24 | 25 | %.c: %.pyx 26 | cython $< 27 | -------------------------------------------------------------------------------- /examples/05-opengl/README.md: -------------------------------------------------------------------------------- 1 | # SDL2 and OpenGLESv2 2 | 3 | This example uses enscripten's SDL2 support to render to a canvas using 4 | OpenGL calls. 5 | 6 | Only a minimal set of bindings have been written, complete Cython bindings 7 | can probably be found in other projects, e.g. 8 | [sdl2_cython](https://pypi.python.org/pypi/sdl2_cython/). 9 | 10 | One important aspect of this example is that it was developed and tested on 11 | a native host first. The app can be run on a Linux desktop machine as long 12 | as the required SDL2 and GL libraries are installed. Once the example was 13 | working natively it was then built with emscripten to work in the browser. 14 | 15 | # Building 16 | 17 | Run ```make```. 18 | 19 | # Running 20 | 21 | Run ```make serve``` to start a web server on local port 8062 (this requires 22 | Python) and then visit the test page 23 | [http://localhost:8062/](http://localhost:8062/). 24 | -------------------------------------------------------------------------------- /examples/05-opengl/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgym/cpython-emscripten/009ba956d0791d89e4000df06c611a40f4408ad8/examples/05-opengl/app/__init__.py -------------------------------------------------------------------------------- /examples/05-opengl/app/__main__.py: -------------------------------------------------------------------------------- 1 | try: 2 | import pyximport 3 | pyximport.install() 4 | except ImportError: 5 | pass 6 | 7 | import math 8 | import time 9 | 10 | from . import sdl2 11 | 12 | 13 | sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) 14 | window = sdl2.SDL_CreateWindow( 15 | bytes('test', 'utf8'), 0, 0, 800, 600, 16 | sdl2.SDL_WINDOW_OPENGL | sdl2.SDL_WINDOW_SHOWN, 17 | ) 18 | 19 | sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, 2) 20 | sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, 0) 21 | sdl2.SDL_GL_SetSwapInterval(0) 22 | sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DOUBLEBUFFER, 1) 23 | sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DEPTH_SIZE, 24) 24 | 25 | sdl2.SDL_GL_CreateContext(window) 26 | 27 | 28 | counter = 0.0 29 | 30 | 31 | def loop(): 32 | start = time.time() 33 | 34 | global counter 35 | sdl2.glClearColor(math.sin(counter), 0.5, 0.6, 1.0) 36 | sdl2.glClear(sdl2.GL_COLOR_BUFFER_BIT) 37 | sdl2.SDL_GL_SwapWindow(window) 38 | counter += 0.01 39 | if counter > math.pi: 40 | counter = 0 41 | 42 | elapsed = time.time() - start 43 | remaining = 0.030 - elapsed 44 | if remaining > 0: 45 | time.sleep(remaining) 46 | 47 | 48 | sdl2.main_loop(loop) 49 | -------------------------------------------------------------------------------- /examples/05-opengl/app/loop.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __EMSCRIPTEN__ 4 | #include 5 | #endif 6 | 7 | 8 | static void main_loop(void (*loop_thunk)(void)) { 9 | #ifdef __EMSCRIPTEN__ 10 | emscripten_set_main_loop(loop_thunk, 0, true); 11 | #else 12 | for (;;) { 13 | SDL_Event e; 14 | while (SDL_PollEvent(&e)) { 15 | switch (e.type) { 16 | case SDL_QUIT: 17 | return; 18 | case SDL_KEYDOWN: 19 | if (e.key.keysym.sym == SDLK_ESCAPE) { 20 | return; 21 | } 22 | break; 23 | default: 24 | break; 25 | } 26 | } 27 | 28 | loop_thunk(); 29 | } 30 | #endif 31 | } 32 | -------------------------------------------------------------------------------- /examples/05-opengl/app/sdl2.pyx: -------------------------------------------------------------------------------- 1 | cimport sdl2_defs as defs 2 | 3 | 4 | SDL_INIT_VIDEO = defs.SDL_INIT_VIDEO 5 | 6 | SDL_WINDOW_OPENGL = defs.SDL_WINDOW_OPENGL 7 | SDL_WINDOW_SHOWN = defs.SDL_WINDOW_SHOWN 8 | 9 | SDL_GL_DOUBLEBUFFER = defs.SDL_GL_DOUBLEBUFFER 10 | SDL_GL_DEPTH_SIZE = defs.SDL_GL_DEPTH_SIZE 11 | SDL_GL_CONTEXT_MAJOR_VERSION = defs.SDL_GL_CONTEXT_MAJOR_VERSION 12 | SDL_GL_CONTEXT_MINOR_VERSION = defs.SDL_GL_CONTEXT_MINOR_VERSION 13 | 14 | 15 | cdef class SDL_Window(object): 16 | cdef defs.SDL_Window *inst 17 | 18 | 19 | cdef class SDL_GLContext(object): 20 | cdef defs.SDL_GLContext inst 21 | 22 | 23 | def SDL_Init(flags): 24 | return defs.SDL_Init(flags) 25 | 26 | 27 | cpdef SDL_CreateWindow(title, x, y, w, h, flags): 28 | cdef SDL_Window result = SDL_Window() 29 | result.inst = defs.SDL_CreateWindow(title, x, y, w, h, flags) 30 | return result 31 | 32 | 33 | def SDL_GL_SetAttribute(attr, value): 34 | return defs.SDL_GL_SetAttribute(attr, value) 35 | 36 | 37 | def SDL_GL_SetSwapInterval(interval): 38 | return defs.SDL_GL_SetSwapInterval(interval) 39 | 40 | 41 | def SDL_GL_CreateContext(window): 42 | cdef SDL_GLContext result = SDL_GLContext() 43 | result.inst = defs.SDL_GL_CreateContext((window).inst) 44 | return result 45 | 46 | 47 | def SDL_GL_SwapWindow(window): 48 | defs.SDL_GL_SwapWindow((window).inst) 49 | 50 | 51 | GL_COLOR_BUFFER_BIT = defs.GL_COLOR_BUFFER_BIT 52 | 53 | 54 | def glClearColor(r, g, b, a): 55 | defs.glClearColor(r, g, b, a) 56 | 57 | 58 | def glClear(bits): 59 | defs.glClear(bits) 60 | 61 | 62 | loop_callback = None 63 | 64 | 65 | cdef void loop_thunk(): 66 | loop_callback() 67 | 68 | 69 | def main_loop(callback): 70 | global loop_callback 71 | loop_callback = callback 72 | defs.main_loop(loop_thunk) 73 | -------------------------------------------------------------------------------- /examples/05-opengl/app/sdl2.pyxbld: -------------------------------------------------------------------------------- 1 | import os.path 2 | import subprocess 3 | 4 | 5 | def make_ext(modname, pyxfilename): 6 | from distutils.extension import Extension 7 | cflags = subprocess.check_output(['sdl2-config', '--cflags']).split() 8 | ldflags = subprocess.check_output(['sdl2-config', '--libs']).split() 9 | 10 | cflags += ['-I' + os.path.dirname(pyxfilename)] 11 | cflags += ['-DGL_GLEXT_PROTOTYPES'] 12 | 13 | ldflags += ['-lGL'] 14 | 15 | return Extension( 16 | name=modname, 17 | sources=[pyxfilename], 18 | extra_compile_args=cflags, 19 | extra_link_args=ldflags, 20 | ) 21 | -------------------------------------------------------------------------------- /examples/05-opengl/app/sdl2_defs.pxd: -------------------------------------------------------------------------------- 1 | from libc.stdint cimport uint32_t 2 | 3 | 4 | cdef extern from "SDL2/SDL.h" nogil: 5 | uint32_t SDL_INIT_VIDEO 6 | 7 | uint32_t SDL_WINDOW_OPENGL 8 | uint32_t SDL_WINDOW_SHOWN 9 | 10 | ctypedef enum SDL_GLattr: 11 | SDL_GL_DOUBLEBUFFER 12 | SDL_GL_DEPTH_SIZE 13 | SDL_GL_CONTEXT_MAJOR_VERSION 14 | SDL_GL_CONTEXT_MINOR_VERSION 15 | 16 | ctypedef struct SDL_Window: 17 | pass 18 | 19 | ctypedef void* SDL_GLContext 20 | 21 | int SDL_Init(uint32_t flags) 22 | SDL_Window* SDL_CreateWindow(const char* title, int x, int y, int w, int h, uint32_t flags) 23 | 24 | int SDL_GL_SetAttribute(SDL_GLattr attr, int value) 25 | int SDL_GL_SetSwapInterval(int interval) 26 | SDL_GLContext SDL_GL_CreateContext(SDL_Window* window) 27 | void SDL_GL_SwapWindow(SDL_Window* window) 28 | 29 | 30 | cdef extern from "SDL2/SDL_opengles2.h": 31 | uint32_t GL_COLOR_BUFFER_BIT 32 | 33 | void glClearColor(float r, float g, float b, float alpha) 34 | void glClear(uint32_t) 35 | 36 | 37 | cdef extern from "loop.h": 38 | ctypedef void (*thunk)() 39 | void main_loop(thunk callback) 40 | -------------------------------------------------------------------------------- /examples/05-opengl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/05-opengl/lib_files: -------------------------------------------------------------------------------- 1 | lib/python3.6/_collections_abc.py 2 | lib/python3.6/_compression.py 3 | lib/python3.6/_dummy_thread.py 4 | lib/python3.6/_sitebuiltins.py 5 | lib/python3.6/_sysconfigdata.py 6 | lib/python3.6/_threading_local.py 7 | lib/python3.6/_weakrefset.py 8 | lib/python3.6/abc.py 9 | lib/python3.6/codecs.py 10 | lib/python3.6/collections/__init__.py 11 | lib/python3.6/collections/abc.py 12 | lib/python3.6/contextlib.py 13 | lib/python3.6/copy.py 14 | lib/python3.6/copyreg.py 15 | lib/python3.6/dummy_threading.py 16 | lib/python3.6/encodings/__init__.py 17 | lib/python3.6/encodings/aliases.py 18 | lib/python3.6/encodings/cp437.py 19 | lib/python3.6/encodings/latin_1.py 20 | lib/python3.6/encodings/utf_8.py 21 | lib/python3.6/enum.py 22 | lib/python3.6/fnmatch.py 23 | lib/python3.6/functools.py 24 | lib/python3.6/genericpath.py 25 | lib/python3.6/glob.py 26 | lib/python3.6/heapq.py 27 | lib/python3.6/importlib/__init__.py 28 | lib/python3.6/importlib/_bootstrap.py 29 | lib/python3.6/importlib/_bootstrap_external.py 30 | lib/python3.6/importlib/abc.py 31 | lib/python3.6/importlib/machinery.py 32 | lib/python3.6/importlib/util.py 33 | lib/python3.6/io.py 34 | lib/python3.6/keyword.py 35 | lib/python3.6/linecache.py 36 | lib/python3.6/operator.py 37 | lib/python3.6/os.py 38 | lib/python3.6/pkgutil.py 39 | lib/python3.6/posixpath.py 40 | lib/python3.6/re.py 41 | lib/python3.6/reprlib.py 42 | lib/python3.6/runpy.py 43 | lib/python3.6/shutil.py 44 | lib/python3.6/site.py 45 | lib/python3.6/sre_compile.py 46 | lib/python3.6/sre_constants.py 47 | lib/python3.6/sre_parse.py 48 | lib/python3.6/stat.py 49 | lib/python3.6/struct.py 50 | lib/python3.6/sysconfig.py 51 | lib/python3.6/tarfile.py 52 | lib/python3.6/threading.py 53 | lib/python3.6/token.py 54 | lib/python3.6/tokenize.py 55 | lib/python3.6/traceback.py 56 | lib/python3.6/types.py 57 | lib/python3.6/warnings.py 58 | lib/python3.6/weakref.py 59 | lib/python3.6/zipfile.py 60 | -------------------------------------------------------------------------------- /examples/05-opengl/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | #if PY_MAJOR_VERSION < 3 9 | PyMODINIT_FUNC initsdl2(void); 10 | #else 11 | PyMODINIT_FUNC PyInit_sdl2(void); 12 | #endif 13 | 14 | 15 | static void onload(const char *filename) { 16 | printf("Loaded %s.\n", filename); 17 | PyRun_SimpleString( 18 | "import zipfile;" 19 | "zipfile.ZipFile('/app.zip').extractall('/');" 20 | ); 21 | PyRun_SimpleString( 22 | "import sys;" 23 | "sys.path.insert(0, '/');" 24 | ); 25 | PyRun_SimpleString( 26 | "import runpy;" 27 | "runpy.run_module('app');" 28 | ); 29 | } 30 | 31 | 32 | static void onloaderror(const char *filename) { 33 | printf("Failed to load %s, aborting.\n", filename); 34 | PyRun_SimpleString("print('fail')"); 35 | } 36 | 37 | 38 | int main(int argc, char** argv) { 39 | setenv("PYTHONHOME", "/", 0); 40 | setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0); 41 | 42 | Py_InitializeEx(0); 43 | #if PY_MAJOR_VERSION < 3 44 | initsdl2(); 45 | #else 46 | PyInit_sdl2(); 47 | #endif 48 | 49 | // Fetch app.zip from the server. 50 | emscripten_async_wget("app.zip", "/app.zip", onload, onloaderror); 51 | 52 | emscripten_exit_with_live_runtime(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/06-cython-packages/.gitignore: -------------------------------------------------------------------------------- 1 | gen0/* 2 | gen1/* 3 | builtins.h 4 | -------------------------------------------------------------------------------- /examples/06-cython-packages/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | PYX_SRC=$(patsubst ./%,%,$(shell find . -name "*.pyx")) 4 | MOD_SRC_0=$(patsubst %.pyx,gen0/%.c,$(PYX_SRC)) 5 | MOD_SRC_1=$(patsubst %.pyx,gen1/%.c,$(PYX_SRC)) 6 | MOD_OBJ=$(patsubst %.c,%.o,$(MOD_SRC_1)) 7 | 8 | 9 | all: python.js app.zip 10 | 11 | 12 | python.js: main.o $(MOD_OBJ) root 13 | $(CC) -o $@ $(filter %.o,$^) $(LDFLAGS) --preload-file root@/ 14 | 15 | 16 | app.zip: app 17 | rm -f $@ 18 | zip -r $@ app/*.py 19 | 20 | 21 | clean: 22 | -rm -fr root gen0 gen1 23 | -rm python.js python.data app.zip 24 | 25 | 26 | gen0/%.c: %.pyx 27 | @mkdir -p $(dir $@) 28 | cython -o $@ $< 29 | 30 | 31 | gen1/%.c: gen0/%.c 32 | python ../../utils/patch_cython_module.py $< $@ --start-depth 1 33 | touch gen1 34 | 35 | 36 | builtins.h: $(PYX_SRC) 37 | python ../../utils/make_cython_builtins.py $(MOD_SRC_1) --start-depth 1 > $@ 38 | -------------------------------------------------------------------------------- /examples/06-cython-packages/README.md: -------------------------------------------------------------------------------- 1 | # Cython modules in packages 2 | 3 | This example shows how Cython modules can be linked with Python and made 4 | available as built in modules. 5 | 6 | There are currently two complications with doing this: 7 | 8 | - If the module is in a package Cython drops the package information. 9 | - Python does not handle built in modules which are in a package. 10 | 11 | The first issue is resolved by editing Cython's output to add package 12 | information. 13 | The first step is to give the init function a unique name based on the 14 | package, otherwise conflicts may occur. 15 | The second is to replace the module name with its full path. 16 | Both steps are handled by the patch_cython_module.py script in utils/. 17 | 18 | The second issue is resolved by adding a custom import hook that recognises 19 | built in modules and handles them correctly. This is done in main.c using 20 | some Python code. 21 | 22 | Currently only Python 3 is supported, although the techniques may be applicable 23 | to a 2.7 build. 24 | 25 | 26 | # Building 27 | 28 | Run ```make```. 29 | 30 | # Running 31 | 32 | Run ```make serve``` to start a web server on local port 8062 (this requires 33 | Python) and then visit the test page 34 | [http://localhost:8062/](http://localhost:8062/). 35 | -------------------------------------------------------------------------------- /examples/06-cython-packages/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgym/cpython-emscripten/009ba956d0791d89e4000df06c611a40f4408ad8/examples/06-cython-packages/app/__init__.py -------------------------------------------------------------------------------- /examples/06-cython-packages/app/__main__.py: -------------------------------------------------------------------------------- 1 | import js 2 | js.run(b''' 3 | window.output = function (line) { 4 | document.getElementById('output').appendChild( 5 | document.createTextNode(line) 6 | ); 7 | } 8 | ''') 9 | 10 | 11 | js.run(b'output("Imported top level module: success\\n");') 12 | 13 | 14 | js.run(b'output("Importing absolute package module a: ");') 15 | try: 16 | import app.a 17 | except ImportError: 18 | js.run(b'output("failed\\n");') 19 | else: 20 | js.run(b'output("success\\n");') 21 | 22 | 23 | js.run(b'output("Importing relative package module b: ");') 24 | try: 25 | from . import b 26 | except ImportError: 27 | js.run(b'output("failed\\n");') 28 | else: 29 | js.run(b'output("success\\n");') 30 | 31 | 32 | js.run(b'output("Importing nested relative modules c: ");') 33 | try: 34 | from . import c 35 | except ImportError: 36 | js.run(b'output("failed\\n");') 37 | else: 38 | js.run(b'output("success\\n");') 39 | -------------------------------------------------------------------------------- /examples/06-cython-packages/app/a.pyx: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /examples/06-cython-packages/app/b.pyx: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /examples/06-cython-packages/app/c.pyx: -------------------------------------------------------------------------------- 1 | from . import d 2 | -------------------------------------------------------------------------------- /examples/06-cython-packages/app/d.pyx: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /examples/06-cython-packages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

 8 |         
 9 |     
10 | 
11 | 


--------------------------------------------------------------------------------
/examples/06-cython-packages/js.pyx:
--------------------------------------------------------------------------------
1 | cdef extern from "emscripten.h":
2 |     void emscripten_run_script(const char *)
3 | 
4 | 
5 | def run(code):
6 |     emscripten_run_script(code)
7 | 


--------------------------------------------------------------------------------
/examples/06-cython-packages/lib_files:
--------------------------------------------------------------------------------
 1 | lib/python3.6/_collections_abc.py
 2 | lib/python3.6/_compression.py
 3 | lib/python3.6/_dummy_thread.py
 4 | lib/python3.6/_sitebuiltins.py
 5 | lib/python3.6/_sysconfigdata.py
 6 | lib/python3.6/_threading_local.py
 7 | lib/python3.6/_weakrefset.py
 8 | lib/python3.6/abc.py
 9 | lib/python3.6/codecs.py
10 | lib/python3.6/collections/__init__.py
11 | lib/python3.6/collections/abc.py
12 | lib/python3.6/contextlib.py
13 | lib/python3.6/copy.py
14 | lib/python3.6/copyreg.py
15 | lib/python3.6/dummy_threading.py
16 | lib/python3.6/encodings/__init__.py
17 | lib/python3.6/encodings/aliases.py
18 | lib/python3.6/encodings/cp437.py
19 | lib/python3.6/encodings/latin_1.py
20 | lib/python3.6/encodings/utf_8.py
21 | lib/python3.6/enum.py
22 | lib/python3.6/fnmatch.py
23 | lib/python3.6/functools.py
24 | lib/python3.6/genericpath.py
25 | lib/python3.6/glob.py
26 | lib/python3.6/heapq.py
27 | lib/python3.6/importlib/__init__.py
28 | lib/python3.6/importlib/_bootstrap.py
29 | lib/python3.6/importlib/_bootstrap_external.py
30 | lib/python3.6/importlib/abc.py
31 | lib/python3.6/importlib/machinery.py
32 | lib/python3.6/importlib/util.py
33 | lib/python3.6/io.py
34 | lib/python3.6/keyword.py
35 | lib/python3.6/linecache.py
36 | lib/python3.6/operator.py
37 | lib/python3.6/os.py
38 | lib/python3.6/pkgutil.py
39 | lib/python3.6/posixpath.py
40 | lib/python3.6/re.py
41 | lib/python3.6/reprlib.py
42 | lib/python3.6/runpy.py
43 | lib/python3.6/shutil.py
44 | lib/python3.6/site.py
45 | lib/python3.6/sre_compile.py
46 | lib/python3.6/sre_constants.py
47 | lib/python3.6/sre_parse.py
48 | lib/python3.6/stat.py
49 | lib/python3.6/struct.py
50 | lib/python3.6/sysconfig.py
51 | lib/python3.6/tarfile.py
52 | lib/python3.6/threading.py
53 | lib/python3.6/token.py
54 | lib/python3.6/tokenize.py
55 | lib/python3.6/traceback.py
56 | lib/python3.6/types.py
57 | lib/python3.6/warnings.py
58 | lib/python3.6/weakref.py
59 | lib/python3.6/zipfile.py
60 | 


--------------------------------------------------------------------------------
/examples/06-cython-packages/main.c:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | 
 7 | #include "builtins.h"
 8 | 
 9 | 
10 | static void onload(const char *filename) {
11 |     printf("Loaded %s.\n", filename);
12 |     PyRun_SimpleString(
13 |         "import zipfile;"
14 |         "zipfile.ZipFile('/app.zip').extractall('/');"
15 |     );
16 |     PyRun_SimpleString(
17 |         "import sys;"
18 |         "sys.path.insert(0, '/');"
19 |     );
20 |     PyRun_SimpleString(
21 |         "import runpy;"
22 |         "runpy.run_module('app');"
23 |     );
24 | }
25 | 
26 | 
27 | static void onloaderror(const char *filename) {
28 |     printf("Failed to load %s, aborting.\n", filename);
29 |     PyRun_SimpleString("print('fail')");
30 | }
31 | 
32 | 
33 | int main(int argc, char** argv) {
34 |     setenv("PYTHONHOME", "/", 0);
35 |     setenv("_PYTHON_SYSCONFIGDATA_NAME", "_sysconfigdata", 0);
36 | 
37 |     PyImport_ExtendInittab(builtins);
38 | 
39 |     Py_InitializeEx(0);
40 | 
41 |     PyRun_SimpleString(
42 |         "import importlib.abc\n" \
43 |         "import importlib.machinery\n" \
44 |         "import sys\n" \
45 |         "\n" \
46 |         "\n" \
47 |         "class Finder(importlib.abc.MetaPathFinder):\n" \
48 |         "    def find_spec(self, fullname, path, target=None):\n" \
49 |         "        if fullname in sys.builtin_module_names:\n" \
50 |         "            return importlib.machinery.ModuleSpec(\n" \
51 |         "                fullname,\n" \
52 |         "                importlib.machinery.BuiltinImporter,\n" \
53 |         "            )\n" \
54 |         "\n" \
55 |         "\n" \
56 |         "sys.meta_path.append(Finder())\n" \
57 |     );
58 | 
59 |     // Fetch app.zip from the server.
60 |     emscripten_async_wget("app.zip", "/app.zip", onload, onloaderror);
61 | 
62 |     emscripten_exit_with_live_runtime();
63 |     return 0;
64 | }
65 | 


--------------------------------------------------------------------------------
/examples/common.mk:
--------------------------------------------------------------------------------
 1 | PYVERSION=3.6.7
 2 | PYMINOR=$(basename $(PYVERSION))
 3 | 
 4 | CC=emcc
 5 | OPTFLAGS=-O3
 6 | CFLAGS=-std=gnu99 $(OPTFLAGS) -g -I ../../installs/python-$(PYVERSION)/include/python$(PYMINOR)/ -Wno-warn-absolute-paths -s WASM=1
 7 | LDFLAGS=$(OPTFLAGS) ../../installs/python-$(PYVERSION)/lib/libpython$(PYMINOR).a \
 8 |   -s TOTAL_MEMORY=268435456 \
 9 |   -s ASSERTIONS=2 \
10 |   -s EMULATE_FUNCTION_POINTER_CASTS=1 \
11 |   -s WASM=1 \
12 |   --memory-init-file 0
13 | 
14 | 
15 | all:
16 | 
17 | 
18 | serve: all
19 | 	@echo "Serving on port 8062"
20 | 	python3 -m http.server 8062
21 | 
22 | 
23 | %.o: %.c ../../installs/python-$(PYVERSION)/lib/python$(PYMINOR)
24 | 	$(CC) -o $@ -c $< $(CFLAGS)
25 | 
26 | 
27 | root: ../../installs/python-$(PYVERSION)/lib/python$(PYMINOR)
28 | 	mkdir -p root/lib
29 | 	tar -C ../../installs/python-$(PYVERSION) -cf - --files-from lib_files | tar -C root -xvf -
30 | 
31 | 
32 | ../../installs/python-$(PYVERSION)/lib/python$(PYMINOR):
33 | 	make -C ../../$(PYVERSION)
34 | 


--------------------------------------------------------------------------------
/utils/make_cython_builtins.py:
--------------------------------------------------------------------------------
 1 | import argparse
 2 | from os import path, makedirs
 3 | 
 4 | 
 5 | def main():
 6 |     parser = argparse.ArgumentParser()
 7 |     parser.add_argument('sources', nargs='+')
 8 |     parser.add_argument('--start-depth', type=int, default=0)
 9 |     args = parser.parse_args()
10 | 
11 |     decls = []
12 |     builtins = []
13 |     for src_filename in args.sources:
14 |         src_filename = path.normpath(src_filename)
15 |         module_name = path.splitext(src_filename)[0]
16 |         module_path = module_name.split(path.sep)[args.start_depth:]
17 |         init_name = 'PyInit_{}'.format('__'.join(module_path))
18 |         decls.append('PyMODINIT_FUNC {}(void);'.format(init_name))
19 |         builtins.append('    {{"{}", {}}}'.format(
20 |             '.'.join(module_path), init_name,
21 |         ))
22 | 
23 |     builtins.append('    {NULL, NULL}')
24 | 
25 |     header = '''{}
26 | 
27 | static struct _inittab builtins[] = {{
28 | {}
29 | }};'''.format(
30 |         '\n'.join(decls),
31 |         ',\n'.join(builtins),
32 |     )
33 | 
34 |     print(header)
35 | 
36 | 
37 | if __name__ == '__main__':
38 |     main()
39 | 


--------------------------------------------------------------------------------
/utils/patch_cython_module.py:
--------------------------------------------------------------------------------
 1 | import argparse
 2 | from os import path, makedirs
 3 | import re
 4 | 
 5 | 
 6 | def patch_init_name(src, module_path):
 7 |     current_name = module_path[-1]
 8 |     new_name = '__'.join(module_path)
 9 |     dst = re.sub(
10 |         r'(PyMODINIT_FUNC (?:init|PyInit_))' + re.escape(current_name),
11 |         '\\1' + re.escape(new_name),
12 |         src,
13 |     )
14 |     return dst
15 | 
16 | 
17 | def patch_module_name(src, module_path):
18 |     current_name = module_path[-1]
19 |     new_name = '.'.join(module_path)
20 |     dst = re.sub(
21 |         r'(__pyx_moduledef.*?"){}"'.format(re.escape(current_name)),
22 |         '\\1{}"'.format(new_name),
23 |         src,
24 |         flags=re.DOTALL,
25 |     )
26 |     dst = re.sub(
27 |         r'(Py_InitModule4\("){}"'.format(re.escape(current_name)),
28 |         '\\1{}"'.format(new_name),
29 |         dst,
30 |     )
31 |     return dst
32 | 
33 | 
34 | def main():
35 |     parser = argparse.ArgumentParser()
36 |     parser.add_argument('src')
37 |     parser.add_argument('dst')
38 |     parser.add_argument('--start-depth', type=int, default=0)
39 |     args = parser.parse_args()
40 | 
41 |     src_filename = path.normpath(args.src)
42 |     dst_filename = path.normpath(args.dst)
43 | 
44 |     module_name = path.splitext(src_filename)[0]
45 |     module_path = module_name.split(path.sep)[args.start_depth:]
46 |     module_name = '.'.join(module_path)
47 | 
48 |     with open(src_filename) as stream:
49 |         src = stream.read()
50 | 
51 |     if len(module_path) > 1:
52 |         tmp = patch_init_name(src, module_path)
53 |         tmp = patch_module_name(tmp, module_path)
54 |         dst = tmp
55 |     else:
56 |         dst = src
57 | 
58 |     dst_dir = path.dirname(dst_filename)
59 |     if dst_dir and not path.exists(dst_dir):
60 |         makedirs(dst_dir)
61 | 
62 |     with open(dst_filename, 'w') as stream:
63 |         stream.write(dst)
64 | 
65 | 
66 | if __name__ == '__main__':
67 |     main()
68 | 


--------------------------------------------------------------------------------