├── .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 |
--------------------------------------------------------------------------------