Skip to content

Commit 3261856

Browse files
clementperonclaude
andcommitted
gh-156780: Emscripten: support static linking
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 4ab6682 commit 3261856

4 files changed

Lines changed: 22 additions & 5 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Emscripten: ``libpython.a`` can now be linked into a program statically.

Python/emscripten_trampoline.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ typedef PyObject* (*TrampolineFunc)(int* success,
4747
PyObject* args,
4848
PyObject* kw);
4949

50+
// The JS glue only binds _PyRuntime if it is exported, which an embedder
51+
// linking libpython does not do.
52+
EMSCRIPTEN_KEEPALIVE _PyRuntimeState *const _PyEM_runtime = &_PyRuntime;
53+
54+
// Placeholder whose function table slot the wasm-gc trampoline takes over,
55+
// so that the table never needs to grow.
56+
static PyObject*
57+
trampoline_placeholder(int* success, PyCFunctionWithKeywords func,
58+
PyObject* self, PyObject* args, PyObject* kw)
59+
{
60+
Py_FatalError("Emscripten trampoline slot was not set up");
61+
}
62+
EMSCRIPTEN_KEEPALIVE const TrampolineFunc _PyEM_trampoline_slot = trampoline_placeholder;
63+
5064
/**
5165
* Backwards compatible trampoline works with all JS runtimes
5266
*/
@@ -79,7 +93,9 @@ function getPyEMTrampolinePtr() {
7993
const trampolineInstance = new WebAssembly.Instance(trampolineModule, {
8094
env: { __indirect_function_table: wasmTable, memory: wasmMemory },
8195
});
82-
return addFunction(trampolineInstance.exports.trampoline_call);
96+
const slot = HEAPU32[__PyEM_trampoline_slot / 4];
97+
wasmTable.set(slot, trampolineInstance.exports.trampoline_call);
98+
return slot;
8399
}
84100
// We have to be careful to work correctly with memory snapshots -- the value of
85101
// _PyRuntimeState.emscripten_trampoline needs to reflect whether wasm-gc is
@@ -90,12 +106,12 @@ function getPyEMTrampolinePtr() {
90106
addOnPreRun(function setEmscriptenTrampoline() {
91107
const ptr = getPyEMTrampolinePtr();
92108
const offset = HEAP32[__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET / 4];
93-
HEAP32[(__PyRuntime + offset) / 4] = ptr;
109+
HEAP32[(HEAPU32[__PyEM_runtime / 4] + offset) / 4] = ptr;
94110
});
95111
);
96112

97113
EM_JS_DEPS(_PyEM_TrampolineCall,
98-
"$wasmTable,$wasmMemory,$addFunction,$addOnPreRun");
114+
"$wasmTable,$wasmMemory,$addOnPreRun");
99115

100116
PyObject*
101117
_PyEM_TrampolineCall(PyCFunctionWithKeywords func,

configure

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2440,7 +2440,7 @@ AS_CASE([$ac_sys_system],
24402440
dnl Include file system support
24412441
AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"])
24422442
AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32,TTY,ERRNO_CODES"])
2443-
AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"])
2443+
AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"])
24442444
AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"])
24452445
dnl Avoid bugs in JS fallback string decoding path
24462446
AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"])

0 commit comments

Comments
 (0)