]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-126898: Emscripten support: Use es6 modules (#126903)
authorHood Chatham <roberthoodchatham@gmail.com>
Thu, 21 Nov 2024 04:10:46 +0000 (05:10 +0100)
committerGitHub <noreply@github.com>
Thu, 21 Nov 2024 04:10:46 +0000 (15:10 +1100)
Modify Emscripten support to use ES6 modules.

Misc/NEWS.d/next/Build/2024-11-20-17-12-40.gh-issue-126898.I2zILt.rst [new file with mode: 0644]
Tools/wasm/emscripten/__main__.py
Tools/wasm/emscripten/node_entry.mjs [new file with mode: 0644]
Tools/wasm/emscripten/node_pre.js [deleted file]
configure
configure.ac

diff --git a/Misc/NEWS.d/next/Build/2024-11-20-17-12-40.gh-issue-126898.I2zILt.rst b/Misc/NEWS.d/next/Build/2024-11-20-17-12-40.gh-issue-126898.I2zILt.rst
new file mode 100644 (file)
index 0000000..37783c4
--- /dev/null
@@ -0,0 +1 @@
+The Emscripten build of Python is now based on ES6 modules.
index 2015a3764ea8c8e702c1c729f91df81014572dde..9ce8dd6a364ad6298a4b2e35f6cd5675e7ffc365 100644 (file)
@@ -4,20 +4,22 @@ import argparse
 import contextlib
 import functools
 import os
-
-try:
-    from os import process_cpu_count as cpu_count
-except ImportError:
-    from os import cpu_count
-from pathlib import Path
 import shutil
 import subprocess
 import sys
 import sysconfig
 import tempfile
+from pathlib import Path
+from textwrap import dedent
+
+try:
+    from os import process_cpu_count as cpu_count
+except ImportError:
+    from os import cpu_count
 
-WASM_DIR = Path(__file__).parent.parent
-CHECKOUT = WASM_DIR.parent.parent
+
+EMSCRIPTEN_DIR = Path(__file__).parent
+CHECKOUT = EMSCRIPTEN_DIR.parent.parent.parent
 
 CROSS_BUILD_DIR = CHECKOUT / "cross-build"
 BUILD_DIR = CROSS_BUILD_DIR / "build"
@@ -72,7 +74,7 @@ def subdir(working_dir, *, clean_ok=False):
             print("⎯" * terminal_width)
             print("📁", working_dir)
             if clean_ok and getattr(context, "clean", False) and working_dir.exists():
-                print(f"🚮 Deleting directory (--clean)...")
+                print("🚮 Deleting directory (--clean)...")
                 shutil.rmtree(working_dir)
 
             working_dir.mkdir(parents=True, exist_ok=True)
@@ -207,9 +209,21 @@ def configure_emscripten_python(context, working_dir):
         quiet=context.quiet,
     )
 
-    python_js = working_dir / "python.js"
+    shutil.copy(EMSCRIPTEN_DIR / "node_entry.mjs", working_dir / "node_entry.mjs")
+
+    node_entry = working_dir / "node_entry.mjs"
     exec_script = working_dir / "python.sh"
-    exec_script.write_text(f'#!/bin/sh\nexec {host_runner} {python_js} "$@"\n')
+    exec_script.write_text(
+        dedent(
+            f"""\
+            #!/bin/sh
+
+            # We compute our own path, not following symlinks and pass it in so that
+            # node_entry.mjs can set sys.executable correctly.
+            exec {host_runner} {node_entry} "$(realpath -s $0)" "$@"
+            """
+        )
+    )
     exec_script.chmod(0o755)
     print(f"🏃‍♀️ Created {exec_script} ... ")
     sys.stdout.flush()
diff --git a/Tools/wasm/emscripten/node_entry.mjs b/Tools/wasm/emscripten/node_entry.mjs
new file mode 100644 (file)
index 0000000..cb1c6ff
--- /dev/null
@@ -0,0 +1,30 @@
+import EmscriptenModule from "./python.mjs";
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+if (process?.versions?.node) {
+  const nodeVersion = Number(process.versions.node.split(".", 1)[0]);
+  if (nodeVersion < 18) {
+      process.stderr.write(
+          `Node version must be >= 18, got version ${process.version}\n`,
+      );
+      process.exit(1);
+  }
+}
+
+const settings = {
+  preRun(Module) {
+    const __dirname = dirname(fileURLToPath(import.meta.url));
+    Module.FS.mkdirTree("/lib/");
+    Module.FS.mount(Module.FS.filesystems.NODEFS, { root: __dirname + "/lib/" }, "/lib/");
+  },
+  // The first three arguments are: "node", path to this file, path to
+  // python.sh. After that come the arguments the user passed to python.sh.
+  arguments: process.argv.slice(3),
+  // Ensure that sys.executable, sys._base_executable, etc point to python.sh
+  // not to this file. To properly handle symlinks, python.sh needs to compute
+  // its own path.
+  thisProgram: process.argv[2],
+};
+
+await EmscriptenModule(settings);
diff --git a/Tools/wasm/emscripten/node_pre.js b/Tools/wasm/emscripten/node_pre.js
deleted file mode 100644 (file)
index 54b09dc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// If process is undefined, we're not running in the node runtime let it go I
-// guess?
-if (typeof process !== "undefined") {
-    const nodeVersion = Number(process.versions.node.split(".", 1)[0]);
-    if (nodeVersion < 18) {
-        process.stderr.write(
-            `Node version must be >= 18, got version ${process.version}\n`,
-        );
-        process.exit(1);
-    }
-    Module.preRun = () => {
-        FS.mkdirTree("/lib/");
-        FS.mount(NODEFS, { root: __dirname + "/lib/" }, "/lib/");
-    };
-}
index 5b44a3d69929a0889cb7a4d01b84507a7551db9d..84b74ac3584bcd53175b443b07105bf6b74027a1 100755 (executable)
--- a/configure
+++ b/configure
@@ -7291,7 +7291,7 @@ else $as_nop
 
   case $ac_sys_system in #(
   Emscripten) :
-    EXEEXT=.js ;; #(
+    EXEEXT=.mjs ;; #(
   WASI) :
     EXEEXT=.wasm ;; #(
   *) :
@@ -9432,6 +9432,7 @@ fi
         as_fn_append LDFLAGS_NODIST " -sWASM_BIGINT"
 
         as_fn_append LDFLAGS_NODIST " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"
+    as_fn_append LDFLAGS_NODIST " -sEXPORTED_RUNTIME_METHODS=FS"
 
     if test "x$enable_wasm_dynamic_linking" = xyes
 then :
@@ -9450,7 +9451,6 @@ then :
 fi
     as_fn_append LDFLAGS_NODIST " -sALLOW_MEMORY_GROWTH"
         as_fn_append LDFLAGS_NODIST " -sEXIT_RUNTIME"
-    as_fn_append LDFLAGS_NODIST " --pre-js=\$(srcdir)/Tools/wasm/emscripten/node_pre.js"
     WASM_LINKFORSHARED_DEBUG="-gseparate-dwarf --emit-symbol-map"
 
     if test "x$wasm_debug" = xyes
index 7904f8990c48ee26af69d6999c602b970d0b8c6a..8fa6cb60900ad1c059d99d41cb617d3c3141868e 100644 (file)
@@ -1327,7 +1327,7 @@ AC_ARG_WITH([suffix],
   )
 ], [
   AS_CASE([$ac_sys_system],
-    [Emscripten], [EXEEXT=.js],
+    [Emscripten], [EXEEXT=.mjs],
     [WASI], [EXEEXT=.wasm],
     [EXEEXT=]
   )
@@ -2328,6 +2328,7 @@ AS_CASE([$ac_sys_system],
 
     dnl Include file system support
     AS_VAR_APPEND([LDFLAGS_NODIST], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"])
+    AS_VAR_APPEND([LDFLAGS_NODIST], [" -sEXPORTED_RUNTIME_METHODS=FS"])
 
     AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [
       AS_VAR_APPEND([LINKFORSHARED], [" -sMAIN_MODULE"])
@@ -2341,7 +2342,6 @@ AS_CASE([$ac_sys_system],
     AS_VAR_APPEND([LDFLAGS_NODIST], [" -sALLOW_MEMORY_GROWTH"])
     dnl not completely sure whether or not we want -sEXIT_RUNTIME, keeping it for now.
     AS_VAR_APPEND([LDFLAGS_NODIST], [" -sEXIT_RUNTIME"])
-    AS_VAR_APPEND([LDFLAGS_NODIST], [" --pre-js=\$(srcdir)/Tools/wasm/emscripten/node_pre.js"])
     WASM_LINKFORSHARED_DEBUG="-gseparate-dwarf --emit-symbol-map"
 
     AS_VAR_IF([wasm_debug], [yes], [