11load ("@aspect_rules_esbuild//esbuild:defs.bzl" , "esbuild" )
2+ load ("@aspect_rules_js//js:defs.bzl" , "js_run_binary" )
23load ("@bazel_skylib//rules:copy_file.bzl" , "copy_file" )
34load ("@bazel_skylib//rules:expand_template.bzl" , "expand_template" )
45load ("@capnp-cpp//src/capnp:cc_capnp_library.bzl" , "cc_capnp_library" )
@@ -30,6 +31,18 @@ def _copy_to_generated(src, version = None, out_name = None, name = None):
3031 name += "@" + version
3132 copy_file (name = name , src = src , out = _out_path (out_name , version ))
3233
34+ def _bin_relative_path (path ):
35+ # js_run_binary runs its tool with the bin directory as the working directory. Returns the
36+ # path, relative to that directory, of a file in the current package. Works whether this
37+ # package is in the main repository or (as when workerd is a dependency) an external one.
38+ package = native .package_name ()
39+ if package :
40+ path = package + "/" + path
41+ repo = native .repo_name ()
42+ if repo :
43+ path = "external/" + repo + "/" + path
44+ return path
45+
3346def _copy_and_capnp_embed (src ):
3447 out_name = _out_name (src )
3548 _copy_to_generated (src )
@@ -159,132 +172,6 @@ def pyodide_static():
159172 tsconfig_json = "tsconfig.json" ,
160173 )
161174
162- _PRELUDE = """
163- import {
164- addEventListener,
165- getRandomValues,
166- location,
167- monotonicDateNow,
168- newWasmModule,
169- patchedApplyFunc,
170- patchedLoadLibData,
171- reportUndefinedSymbolsPatched,
172- wasmInstantiate,
173- patched_PyEM_CountFuncParams,
174- } from "pyodide-internal:pool/builtin_wrappers";
175- """
176-
177- # pyodide.asm.mjs patches
178- # TODO: all of these should be fixed by linking our own Pyodide or by upstreaming.
179- _REPLACEMENTS_COMMON = [
180- [
181- "new WebAssembly.Module" ,
182- "newWasmModule" ,
183- ],
184- [
185- "WebAssembly.instantiate" ,
186- "wasmInstantiate" ,
187- ],
188- [
189- "Date.now" ,
190- "monotonicDateNow" ,
191- ],
192- [
193- "reportUndefinedSymbols()" ,
194- "reportUndefinedSymbolsPatched(Module)" ,
195- ],
196- [
197- "crypto.getRandomValues(" ,
198- "getRandomValues(Module, " ,
199- ],
200- [
201- # Direct eval disallowed in esbuild, see:
202- # https://esbuild.github.io/content-types/#direct-eval
203- "eval(func)" ,
204- "(() => {throw new Error('Internal Emscripten code tried to eval, this should not happen, please file a bug report with your requirements.txt file\\ 's contents')})()" ,
205- ],
206- [
207- "eval(data)" ,
208- "(() => {throw new Error('Internal Emscripten code tried to eval, this should not happen, please file a bug report with your requirements.txt file\\ 's contents')})()" ,
209- ],
210- [
211- "eval(UTF8ToString(ptr))" ,
212- "(() => {throw new Error('Internal Emscripten code tried to eval, this should not happen, please file a bug report with your requirements.txt file\\ 's contents')})()" ,
213- ],
214- # Dynamic linking patches:
215- # library lookup
216- [
217- "function loadLibData(){" ,
218- """
219- function loadLibData(){
220- var libData = patchedLoadLibData(Module, libName, flags.rpath);
221- return flags.loadAsync ? Promise.resolve(libData) : libData;
222- }
223- function dummiedOutOrigLoadLibData(){
224- """ ,
225- ],
226- # for ensuring memory base of dynlib is stable when restoring snapshots
227- [
228- "getMemory(" ,
229- "Module.getMemoryPatched(Module, libName, " ,
230- ],
231- [
232- "function _PyEM_CountFuncParams(func){" ,
233- "function _PyEM_CountFuncParams(func){ return patched_PyEM_CountFuncParams(Module, func);" ,
234- ],
235- [
236- "var tableBase=metadata.tableSize?wasmTable.length:0;" ,
237- "var tableBase=metadata.tableSize?wasmTable.length:0;" +
238- "Module.snapshotDebug && console.log('loadWebAssemblyModule', libName, memoryBase, tableBase);" ,
239- ],
240- # to ensure we report every fatal error, not just the first one
241- [
242- 'console.error("Recursive call to fatal_error. Inner error was:");' ,
243- 'console.error("Recursive call to fatal_error. Inner error was:");\n ' +
244- "try { API.on_fatal?.(e); } catch(e2) { console.error(e2); }\n " ,
245- ],
246- ]
247-
248- _REPLACEMENTS_COMMON_0_26_0_28 = [
249- # for 0.28.2 or earlier, pyodide.asm.js was a commonjs module
250- [
251- # Convert pyodide.asm.js into an es6 module.
252- # When we link our own we can pass `-sES6_MODULE` to the linker and it will do this for us
253- # automatically.
254- "var _createPyodideModule" ,
255- _PRELUDE + "export const _createPyodideModule" ,
256- ],
257- [
258- "globalThis._createPyodideModule = _createPyodideModule;" ,
259- "" ,
260- ],
261- # to fix RPC, applies https://github.com/pyodide/pyodide/commit/8da1f38f7
262- [
263- "nullToUndefined(func.apply(" ,
264- "nullToUndefined(patchedApplyFunc(API, func, " ,
265- ],
266- [
267- "nullToUndefined(Function.prototype.apply.apply" ,
268- "nullToUndefined(API.config.jsglobals.Function.prototype.apply.apply" ,
269- ],
270- ]
271-
272- _REPLACEMENTS_COMMON_314 = [
273- # for 314 or later, pyodide.asm.mjs is es6 module
274- [
275- "export default _createPyodideModule;" ,
276- # still expose _createPyodideModule for compatibility (import { _createPyodideModule })
277- _PRELUDE + "export default _createPyodideModule; export { _createPyodideModule };" ,
278- ],
279- ]
280-
281- _REPLACEMENTS = {
282- "0.26.0a2" : _REPLACEMENTS_COMMON + _REPLACEMENTS_COMMON_0_26_0_28 ,
283- "0.28.2" : _REPLACEMENTS_COMMON + _REPLACEMENTS_COMMON_0_26_0_28 ,
284- "314.0.4" : _REPLACEMENTS_COMMON + _REPLACEMENTS_COMMON_314 ,
285- "314.0.6" : _REPLACEMENTS_COMMON + _REPLACEMENTS_COMMON_314 ,
286- }
287-
288175def _python_bundle (version , * , pyodide_asm_wasm = None , pyodide_asm_mjs = None , python_stdlib_zip = None , emscripten_setup_override = None ):
289176 pyodide_package = "@pyodide-%s//" % version
290177 if not pyodide_asm_wasm :
@@ -304,11 +191,26 @@ def _python_bundle(version, *, pyodide_asm_wasm = None, pyodide_asm_mjs = None,
304191
305192 _copy_to_generated (python_stdlib_zip , version , out_name = "python_stdlib.zip" )
306193
307- expand_template (
194+ # Apply workerd's patches to the Emscripten-generated module (see patch_pyodide_asm.mjs).
195+ # The upstream file is first copied into this package so that both the tool's input and
196+ # output can be addressed relative to the bin directory it runs in.
197+ upstream_asm_mjs = _out_path ("pyodide.asm.upstream.mjs" , version )
198+ patched_asm_mjs = _out_path ("pyodide.asm.mjs" , version )
199+ _copy_to_generated (pyodide_asm_mjs , version , out_name = "pyodide.asm.upstream.mjs" )
200+ js_run_binary (
308201 name = "pyodide.asm.mjs@rule@" + version ,
309- out = _out_path ("pyodide.asm.mjs" , version ),
310- substitutions = dict (_REPLACEMENTS [version ]),
311- template = pyodide_asm_mjs ,
202+ srcs = [upstream_asm_mjs ],
203+ outs = [patched_asm_mjs ],
204+ args = [
205+ "--version" ,
206+ version ,
207+ "--input" ,
208+ _bin_relative_path (upstream_asm_mjs ),
209+ "--output" ,
210+ _bin_relative_path (patched_asm_mjs ),
211+ ],
212+ mnemonic = "PatchPyodideAsm" ,
213+ tool = Label ("//src/pyodide:patch_pyodide_asm" ),
312214 )
313215
314216 js_file (
0 commit comments