| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -314,6 +314,35 @@ always available. | |||
| 314 | 314 | yourself to control bytecode file generation. | |
| 315 | 315 | ||
| 316 | 316 | ||
| 317 | + .. data:: _emscripten_info | ||
| 318 | + | ||
| 319 | + A :term:`named tuple` holding information about the environment on the | ||
| 320 | + *wasm32-emscripten* platform. The named tuple is provisional and may change | ||
| 321 | + in the future. | ||
| 322 | + | ||
| 323 | + .. tabularcolumns:: |l|L| | ||
| 324 | + | ||
| 325 | + +-----------------------------+----------------------------------------------+ | ||
| 326 | + | Attribute | Explanation | | ||
| 327 | + +=============================+==============================================+ | ||
| 328 | + | :const:`emscripten_version` | Emscripten version as tuple of ints | | ||
| 329 | + | | (major, minor, micro), e.g. ``(3, 1, 8)``. | | ||
| 330 | + +-----------------------------+----------------------------------------------+ | ||
| 331 | + | :const:`runtime` | Runtime string, e.g. browser user agent, | | ||
| 332 | + | | ``'Node.js v14.18.2'``, or ``'UNKNOWN'``. | | ||
| 333 | + +-----------------------------+----------------------------------------------+ | ||
| 334 | + | :const:`pthreads` | ``True`` if Python is compiled with | | ||
| 335 | + | | Emscripten pthreads support. | | ||
| 336 | + +-----------------------------+----------------------------------------------+ | ||
| 337 | + | :const:`shared_memory` | ``True`` if Python is compiled with shared | | ||
| 338 | + | | memory support. | | ||
| 339 | + +-----------------------------+----------------------------------------------+ | ||
| 340 | + | ||
| 341 | + .. availability:: WebAssembly Emscripten platform (*wasm32-emscripten*). | ||
| 342 | + | ||
| 343 | + .. versionadded:: 3.11 | ||
| 344 | + | ||
| 345 | + | ||
| 317 | 346 | .. data:: pycache_prefix | |
| 318 | 347 | ||
| 319 | 348 | If this is set (not ``None``), Python will write bytecode-cache ``.pyc`` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -222,12 +222,7 @@ def _can_start_thread() -> bool: | |||
| 222 | 222 | support (-s USE_PTHREADS / __EMSCRIPTEN_PTHREADS__). | |
| 223 | 223 | """ | |
| 224 | 224 | if sys.platform == "emscripten": | |
| 225 | - try: | ||
| 226 | - _thread.start_new_thread(lambda: None, ()) | ||
| 227 | - except RuntimeError: | ||
| 228 | - return False | ||
| 229 | - else: | ||
| 230 | - return True | ||
| 225 | + return sys._emscripten_info.pthreads | ||
| 231 | 226 | elif sys.platform == "wasi": | |
| 232 | 227 | return False | |
| 233 | 228 | else: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -629,6 +629,14 @@ def test_thread_info(self): | |||
| 629 | 629 | self.assertIn(info.name, ('nt', 'pthread', 'solaris', None)) | |
| 630 | 630 | self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) | |
| 631 | 631 | ||
| 632 | + @unittest.skipUnless(support.is_emscripten, "only available on Emscripten") | ||
| 633 | + def test_emscripten_info(self): | ||
| 634 | + self.assertEqual(len(sys._emscripten_info), 4) | ||
| 635 | + self.assertIsInstance(sys._emscripten_info.emscripten_version, tuple) | ||
| 636 | + self.assertIsInstance(sys._emscripten_info.runtime, (str, type(None))) | ||
| 637 | + self.assertIsInstance(sys._emscripten_info.pthreads, bool) | ||
| 638 | + self.assertIsInstance(sys._emscripten_info.shared_memory, bool) | ||
| 639 | + | ||
| 632 | 640 | def test_43581(self): | |
| 633 | 641 | # Can't use sys.stdout, as this is a StringIO object when | |
| 634 | 642 | # the test runs under regrtest. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Add provisional :data:`sys._emscripten_info` named tuple with build-time and | ||
| 2 | + run-time information about Emscripten platform. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -48,6 +48,10 @@ extern void *PyWin_DLLhModule; | |||
| 48 | 48 | extern const char *PyWin_DLLVersionString; | |
| 49 | 49 | #endif | |
| 50 | 50 | ||
| 51 | + #ifdef __EMSCRIPTEN__ | ||
| 52 | + #include <emscripten.h> | ||
| 53 | + #endif | ||
| 54 | + | ||
| 51 | 55 | /*[clinic input] | |
| 52 | 56 | module sys | |
| 53 | 57 | [clinic start generated code]*/ | |
@@ -2686,6 +2690,107 @@ make_impl_info(PyObject *version_info) | |||
| 2686 | 2690 | return NULL; | |
| 2687 | 2691 | } | |
| 2688 | 2692 | ||
| 2693 | + #ifdef __EMSCRIPTEN__ | ||
| 2694 | + | ||
| 2695 | + PyDoc_STRVAR(emscripten_info__doc__, | ||
| 2696 | + "sys._emscripten_info\n\ | ||
| 2697 | + \n\ | ||
| 2698 | + WebAssembly Emscripten platform information."); | ||
| 2699 | + | ||
| 2700 | + static PyTypeObject *EmscriptenInfoType; | ||
| 2701 | + | ||
| 2702 | + static PyStructSequence_Field emscripten_info_fields[] = { | ||
| 2703 | + {"emscripten_version", "Emscripten version (major, minor, micro)"}, | ||
| 2704 | + {"runtime", "Runtime (Node.JS version, browser user agent)"}, | ||
| 2705 | + {"pthreads", "pthread support"}, | ||
| 2706 | + {"shared_memory", "shared memory support"}, | ||
| 2707 | + {0} | ||
| 2708 | + }; | ||
| 2709 | + | ||
| 2710 | + static PyStructSequence_Desc emscripten_info_desc = { | ||
| 2711 | + "sys._emscripten_info", /* name */ | ||
| 2712 | + emscripten_info__doc__ , /* doc */ | ||
| 2713 | + emscripten_info_fields, /* fields */ | ||
| 2714 | + 4 | ||
| 2715 | + }; | ||
| 2716 | + | ||
| 2717 | + EM_JS(char *, _Py_emscripten_runtime, (void), { | ||
| 2718 | + var info; | ||
| 2719 | + if (typeof navigator == 'object') { | ||
| 2720 | + info = navigator.userAgent; | ||
| 2721 | + } else if (typeof process == 'object') { | ||
| 2722 | + info = "Node.js ".concat(process.version) | ||
| 2723 | + } else { | ||
| 2724 | + info = "UNKNOWN" | ||
| 2725 | + } | ||
| 2726 | + var len = lengthBytesUTF8(info) + 1; | ||
| 2727 | + var res = _malloc(len); | ||
| 2728 | + stringToUTF8(info, res, len); | ||
| 2729 | + return res; | ||
| 2730 | + }); | ||
| 2731 | + | ||
| 2732 | + static PyObject * | ||
| 2733 | + make_emscripten_info(void) | ||
| 2734 | + { | ||
| 2735 | + PyObject *emscripten_info = NULL; | ||
| 2736 | + PyObject *version = NULL; | ||
| 2737 | + char *ua; | ||
| 2738 | + int pos = 0; | ||
| 2739 | + | ||
| 2740 | + emscripten_info = PyStructSequence_New(EmscriptenInfoType); | ||
| 2741 | + if (emscripten_info == NULL) { | ||
| 2742 | + return NULL; | ||
| 2743 | + } | ||
| 2744 | + | ||
| 2745 | + version = Py_BuildValue("(iii)", | ||
| 2746 | + __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__); | ||
| 2747 | + if (version == NULL) { | ||
| 2748 | + goto error; | ||
| 2749 | + } | ||
| 2750 | + PyStructSequence_SET_ITEM(emscripten_info, pos++, version); | ||
| 2751 | + | ||
| 2752 | + ua = _Py_emscripten_runtime(); | ||
| 2753 | + if (ua != NULL) { | ||
| 2754 | + PyObject *oua = PyUnicode_DecodeUTF8(ua, strlen(ua), "strict"); | ||
| 2755 | + free(ua); | ||
| 2756 | + if (oua == NULL) { | ||
| 2757 | + goto error; | ||
| 2758 | + } | ||
| 2759 | + PyStructSequence_SET_ITEM(emscripten_info, pos++, oua); | ||
| 2760 | + } else { | ||
| 2761 | + Py_INCREF(Py_None); | ||
| 2762 | + PyStructSequence_SET_ITEM(emscripten_info, pos++, Py_None); | ||
| 2763 | + } | ||
| 2764 | + | ||
| 2765 | + #define SetBoolItem(flag) \ | ||
| 2766 | + PyStructSequence_SET_ITEM(emscripten_info, pos++, PyBool_FromLong(flag)) | ||
| 2767 | + | ||
| 2768 | + #ifdef __EMSCRIPTEN_PTHREADS__ | ||
| 2769 | + SetBoolItem(1); | ||
| 2770 | + #else | ||
| 2771 | + SetBoolItem(0); | ||
| 2772 | + #endif | ||
| 2773 | + | ||
| 2774 | + #ifdef __EMSCRIPTEN_SHARED_MEMORY__ | ||
| 2775 | + SetBoolItem(1); | ||
| 2776 | + #else | ||
| 2777 | + SetBoolItem(0); | ||
| 2778 | + #endif | ||
| 2779 | + | ||
| 2780 | + #undef SetBoolItem | ||
| 2781 | + | ||
| 2782 | + if (PyErr_Occurred()) { | ||
| 2783 | + goto error; | ||
| 2784 | + } | ||
| 2785 | + return emscripten_info; | ||
| 2786 | + | ||
| 2787 | + error: | ||
| 2788 | + Py_CLEAR(emscripten_info); | ||
| 2789 | + return NULL; | ||
| 2790 | + } | ||
| 2791 | + | ||
| 2792 | + #endif // __EMSCRIPTEN__ | ||
| 2793 | + | ||
| 2689 | 2794 | static struct PyModuleDef sysmodule = { | |
| 2690 | 2795 | PyModuleDef_HEAD_INIT, | |
| 2691 | 2796 | "sys", | |
@@ -2821,6 +2926,16 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) | |||
| 2821 | 2926 | } | |
| 2822 | 2927 | } | |
| 2823 | 2928 | ||
| 2929 | + #ifdef __EMSCRIPTEN__ | ||
| 2930 | + if (EmscriptenInfoType == NULL) { | ||
| 2931 | + EmscriptenInfoType = PyStructSequence_NewType(&emscripten_info_desc); | ||
| 2932 | + if (EmscriptenInfoType == NULL) { | ||
| 2933 | + goto type_init_failed; | ||
| 2934 | + } | ||
| 2935 | + } | ||
| 2936 | + SET_SYS("_emscripten_info", make_emscripten_info()); | ||
| 2937 | + #endif | ||
| 2938 | + | ||
| 2824 | 2939 | /* adding sys.path_hooks and sys.path_importer_cache */ | |
| 2825 | 2940 | SET_SYS("meta_path", PyList_New(0)); | |
| 2826 | 2941 | SET_SYS("path_importer_cache", PyDict_New()); | |
@@ -3066,6 +3181,9 @@ _PySys_Fini(PyInterpreterState *interp) | |||
| 3066 | 3181 | #endif | |
| 3067 | 3182 | _PyStructSequence_FiniType(&Hash_InfoType); | |
| 3068 | 3183 | _PyStructSequence_FiniType(&AsyncGenHooksType); | |
| 3184 | + #ifdef __EMSCRIPTEN__ | ||
| 3185 | + Py_CLEAR(EmscriptenInfoType); | ||
| 3186 | + #endif | ||
| 3069 | 3187 | } | |
| 3070 | 3188 | } | |
| 3071 | 3189 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,11 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | 5 | This directory contains configuration and helpers to facilitate cross | |
| 6 | 6 | compilation of CPython to WebAssembly (WASM). For now we support | |
| 7 | - *wasm32-emscripten* builds for modern browser and for *Node.js*. It's not | ||
| 8 | - possible to build for *wasm32-wasi* out-of-the-box yet. | ||
| 7 | + *wasm32-emscripten* builds for modern browser and for *Node.js*. WASI | ||
| 8 | + (*wasm32-wasi*) is work-in-progress | ||
| 9 | 9 | ||
| 10 | 10 | ## wasm32-emscripten build | |
| 11 | 11 | ||
| 12 | + For now the build system has two target flavors. The ``Emscripten/browser`` | ||
| 13 | + target (``--with-emscripten-target=browser``) is optimized for browsers. | ||
| 14 | + It comes with a reduced and preloaded stdlib without tests and threading | ||
| 15 | + support. The ``Emscripten/node`` target has threading enabled and can | ||
| 16 | + access the file system directly. | ||
| 17 | + | ||
| 12 | 18 | Cross compiling to the wasm32-emscripten platform needs the | |
| 13 | 19 | [Emscripten](https://emscripten.org/) SDK and a build Python interpreter. | |
| 14 | 20 | Emscripten 3.1.8 or newer are recommended. All commands below are relative | |
@@ -76,7 +82,7 @@ and header files with debug builds. | |||
| 76 | 82 | ||
| 77 | 83 | ### Cross compile to wasm32-emscripten for node | |
| 78 | 84 | ||
| 79 | - ``` | ||
| 85 | + ```shell | ||
| 80 | 86 | mkdir -p builddir/emscripten-node | |
| 81 | 87 | pushd builddir/emscripten-node | |
| 82 | 88 | ||
@@ -91,7 +97,7 @@ emmake make -j$(nproc) | |||
| 91 | 97 | popd | |
| 92 | 98 | ``` | |
| 93 | 99 | ||
| 94 | - ``` | ||
| 100 | + ```shell | ||
| 95 | 101 | node --experimental-wasm-threads --experimental-wasm-bulk-memory builddir/emscripten-node/python.js | |
| 96 | 102 | ``` | |
| 97 | 103 | ||
@@ -150,9 +156,9 @@ functions. | |||
| 150 | 156 | - Most stdlib modules with a dependency on external libraries are missing, | |
| 151 | 157 | e.g. ``ctypes``, ``readline``, ``sqlite3``, ``ssl``, and more. | |
| 152 | 158 | - Shared extension modules are not implemented yet. All extension modules | |
| 153 | - are statically linked into the main binary. | ||
| 154 | - The experimental configure option ``--enable-wasm-dynamic-linking`` enables | ||
| 155 | - dynamic extensions. | ||
| 159 | + are statically linked into the main binary. The experimental configure | ||
| 160 | + option ``--enable-wasm-dynamic-linking`` enables dynamic extensions | ||
| 161 | + supports. It's currently known to crash in combination with threading. | ||
| 156 | 162 | - glibc extensions for date and time formatting are not available. | |
| 157 | 163 | - ``locales`` module is affected by musl libc issues, | |
| 158 | 164 | [bpo-46390](https://bugs.python.org/issue46390). | |
@@ -167,8 +173,10 @@ functions. | |||
| 167 | 173 | distutils, multiprocessing, dbm, tests and similar modules | |
| 168 | 174 | are not shipped. All other modules are bundled as pre-compiled | |
| 169 | 175 | ``pyc`` files. | |
| 170 | - - Threading is not supported. | ||
| 176 | + - Threading is disabled. | ||
| 171 | 177 | - In-memory file system (MEMFS) is not persistent and limited. | |
| 178 | + - Test modules are disabled by default. Use ``--enable-test-modules`` build | ||
| 179 | + test modules like ``_testcapi``. | ||
| 172 | 180 | ||
| 173 | 181 | ## wasm32-emscripten in node | |
| 174 | 182 | ||
@@ -205,11 +213,17 @@ AddType application/wasm wasm | |||
| 205 | 213 | </IfModule> | |
| 206 | 214 | ``` | |
| 207 | 215 | ||
| 216 | + # WASI (wasm32-wasi) | ||
| 217 | + | ||
| 218 | + WASI builds require [WASI SDK](https://github.com/WebAssembly/wasi-sdk) and | ||
| 219 | + currently [wasix](https://github.com/singlestore-labs/wasix) for POSIX | ||
| 220 | + compatibility stubs. | ||
| 221 | + | ||
| 208 | 222 | # Detect WebAssembly builds | |
| 209 | 223 | ||
| 210 | 224 | ## Python code | |
| 211 | 225 | ||
| 212 | - ```# python | ||
| 226 | + ```python | ||
| 213 | 227 | import os, sys | |
| 214 | 228 | ||
| 215 | 229 | if sys.platform == "emscripten": | |
@@ -222,7 +236,36 @@ if os.name == "posix": | |||
| 222 | 236 | # Windows does not provide os.uname(). | |
| 223 | 237 | machine = os.uname().machine | |
| 224 | 238 | if machine.startswith("wasm"): | |
| 225 | - # WebAssembly (wasm32 or wasm64) | ||
| 239 | + # WebAssembly (wasm32, wasm64 in the future) | ||
| 240 | + ``` | ||
| 241 | + | ||
| 242 | + ```python | ||
| 243 | + >>> import os, sys | ||
| 244 | + >>> os.uname() | ||
| 245 | + posix.uname_result(sysname='Emscripten', nodename='emscripten', release='1.0', version='#1', machine='wasm32') | ||
| 246 | + >>> os.name | ||
| 247 | + 'posix' | ||
| 248 | + >>> sys.platform | ||
| 249 | + 'emscripten' | ||
| 250 | + >>> sys._emscripten_info | ||
| 251 | + sys._emscripten_info( | ||
| 252 | + emscripten_version=(3, 1, 8), | ||
| 253 | + runtime='Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0', | ||
| 254 | + pthreads=False, | ||
| 255 | + shared_memory=False | ||
| 256 | + ) | ||
| 257 | + >>> sys._emscripten_info | ||
| 258 | + sys._emscripten_info(emscripten_version=(3, 1, 8), runtime='Node.js v14.18.2', pthreads=True, shared_memory=True) | ||
| 259 | + ``` | ||
| 260 | + | ||
| 261 | + ```python | ||
| 262 | + >>> import os, sys | ||
| 263 | + >>> os.uname() | ||
| 264 | + posix.uname_result(sysname='wasi', nodename='(none)', release='0.0.0', version='0.0.0', machine='wasm32') | ||
| 265 | + >>> os.name | ||
| 266 | + 'posix' | ||
| 267 | + >>> sys.platform | ||
| 268 | + 'wasi' | ||
| 226 | 269 | ``` | |
| 227 | 270 | ||
| 228 | 271 | ## C code | |
@@ -231,7 +274,7 @@ Emscripten SDK and WASI SDK define several built-in macros. You can dump a | |||
| 231 | 274 | full list of built-ins with ``emcc -dM -E - < /dev/null`` and | |
| 232 | 275 | ``/path/to/wasi-sdk/bin/clang -dM -E - < /dev/null``. | |
| 233 | 276 | ||
| 234 | - ```# C | ||
| 277 | + ```C | ||
| 235 | 278 | #ifdef __EMSCRIPTEN__ | |
| 236 | 279 | // Python on Emscripten | |
| 237 | 280 | #endif | |
| Back | FazBrowse Home | New Git URL |
0 commit comments