Coverage for wasmtime/_linker.py: 92%
86 statements
« prev ^ index » next coverage.py v7.11.3, created at 2025-12-01 19:40 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2025-12-01 19:40 +0000
1import ctypes
2from typing import Any
3from wasmtime import Instance, Engine, FuncType
4from wasmtime import Module, WasmtimeError, Func, Managed
5from . import _ffi as ffi
6from ._extern import get_extern_ptr, wrap_extern
7from ._config import setter_property
8from ._exportable import AsExtern
9from ._store import Storelike
10from ._func import enter_wasm, trampoline, FUNCTIONS, finalize
11from typing import Callable
14class Linker(Managed["ctypes._Pointer[ffi.wasmtime_linker_t]"]):
15 engine: Engine
17 def __init__(self, engine: Engine):
18 """
19 Creates a new linker ready to instantiate modules within the store
20 provided.
21 """
22 self._set_ptr(ffi.wasmtime_linker_new(engine.ptr()))
23 self.engine = engine
25 def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_linker_t]") -> None:
26 ffi.wasmtime_linker_delete(ptr)
28 @setter_property
29 def allow_shadowing(self, allow: bool) -> None:
30 """
31 Configures whether definitions are allowed to shadow one another within
32 this linker
33 """
34 ffi.wasmtime_linker_allow_shadowing(self.ptr(), allow)
36 def define(self, store: Storelike, module: str, name: str, item: AsExtern) -> None:
37 """
38 Defines a new item, by name, in this linker.
40 This method will add a new definition to this linker. The `module` nad
41 `name` provided are what to name the `item` within the linker.
43 This function will raise an error if `item` comes from the wrong store
44 or if shadowing is disallowed and the module/name pair has already been
45 defined.
46 """
47 raw_item = get_extern_ptr(item)
48 module_bytes = module.encode('utf-8')
49 module_buf = ctypes.create_string_buffer(module_bytes)
50 name_bytes = name.encode('utf-8')
51 name_buf = ctypes.create_string_buffer(name_bytes)
52 error = ffi.wasmtime_linker_define(
53 self.ptr(),
54 store._context(),
55 module_buf,
56 len(module_bytes),
57 name_buf,
58 len(name_bytes),
59 ctypes.byref(raw_item))
60 if error:
61 raise WasmtimeError._from_ptr(error)
63 def define_func(self, module: str, name: str, ty: FuncType, func: Callable[..., Any], access_caller: bool = False) -> None:
64 """
65 Defines a new function, by name, in this linker.
67 This method is similar to `define` except that you can directly define a
68 function without creating a `Func` itself. This enables
69 `Store`-independent functions to be inserted into this linker, meaning
70 the linker can be used to instantiate modules in multiple stores.
71 """
72 module_bytes = module.encode('utf-8')
73 module_buf = ctypes.create_string_buffer(module_bytes)
74 name_bytes = name.encode('utf-8')
75 name_buf = ctypes.create_string_buffer(name_bytes)
76 if not isinstance(ty, FuncType):
77 raise TypeError("expected a FuncType")
78 idx = FUNCTIONS.allocate((func, ty.results, access_caller))
79 error = ffi.wasmtime_linker_define_func(
80 self.ptr(),
81 module_buf,
82 len(module_bytes),
83 name_buf,
84 len(name_bytes),
85 ty.ptr(),
86 trampoline,
87 idx,
88 finalize)
89 if error:
90 raise WasmtimeError._from_ptr(error)
92 def define_instance(self, store: Storelike, name: str, instance: Instance) -> None:
93 """
94 Convenience wrapper to define an entire instance in this linker.
96 This function will `define` eaech of the exports on the instance into
97 this linker, using the name provided as the module name and the export's
98 own name as the field name.
100 This function will raise an error if `instance` comes from the wrong
101 store or if shadowing is disallowed and a name was previously defined.
102 """
103 if not isinstance(instance, Instance):
104 raise TypeError("expected an `Instance`")
105 name_bytes = name.encode('utf8')
106 name_buf = ctypes.create_string_buffer(name_bytes)
107 error = ffi.wasmtime_linker_define_instance(self.ptr(),
108 store._context(),
109 name_buf,
110 len(name_bytes),
111 ctypes.byref(instance._instance))
112 if error:
113 raise WasmtimeError._from_ptr(error)
115 def define_wasi(self) -> None:
116 """
117 Defines a WASI instance in this linker.
119 The instance provided has been previously constructed and this method
120 will define all the appropriate imports and their names into this linker
121 to assist with instantiating modules that use WASI.
123 This function will raise an error if shadowing is disallowed and a name
124 was previously defined.
125 """
126 error = ffi.wasmtime_linker_define_wasi(self.ptr())
127 if error:
128 raise WasmtimeError._from_ptr(error)
130 def define_module(self, store: Storelike, name: str, module: Module) -> None:
131 """
132 Defines automatic instantiations of the provided module in this linker.
134 The `module` provided is defined under `name` with automatic
135 instantiations which respect WASI Commands and Reactors.
137 For more information see the Rust documentation at
138 https://docs.wasmtime.dev/api/wasmtime/struct.Linker.html#method.module.
140 This method will throw an error if shadowing is disallowed and an item
141 has previously been defined.
142 """
143 if not isinstance(module, Module):
144 raise TypeError("expected a `Module`")
145 name_bytes = name.encode('utf-8')
146 name_buf = ctypes.create_string_buffer(name_bytes)
147 error = ffi.wasmtime_linker_module(self.ptr(), store._context(), name_buf, len(name_bytes), module.ptr())
148 if error:
149 raise WasmtimeError._from_ptr(error)
151 def instantiate(self, store: Storelike, module: Module) -> Instance:
152 """
153 Instantiates a module using this linker's defined set of names.
155 This method will attempt to satisfy all the imports of the `module`
156 provided with the names defined within this linker. If all names are
157 defined then the module is instantiated.
159 Raises an error if an import of `module` hasn't been defined in this
160 linker or if a trap happens while instantiating the instance.
161 """
162 trap = ctypes.POINTER(ffi.wasm_trap_t)()
163 instance = ffi.wasmtime_instance_t()
164 with enter_wasm(store) as trap:
165 error = ffi.wasmtime_linker_instantiate(
166 self.ptr(), store._context(), module.ptr(), ctypes.byref(instance), trap)
167 if error:
168 raise WasmtimeError._from_ptr(error)
169 return Instance._from_raw(instance)
171 def get_default(self, store: Storelike, name: str) -> Func:
172 """
173 Gets the default export for the named module in this linker.
175 For more information on this see the Rust documentation at
176 https://docs.wasmtime.dev/api/wasmtime/struct.Linker.html#method.get_default.
178 Raises an error if the default export wasn't present.
179 """
180 name_bytes = name.encode('utf-8')
181 name_buf = ctypes.create_string_buffer(name_bytes)
182 func = ffi.wasmtime_func_t()
183 error = ffi.wasmtime_linker_get_default(self.ptr(), store._context(),
184 name_buf, len(name_bytes), ctypes.byref(func))
185 if error:
186 raise WasmtimeError._from_ptr(error)
187 return Func._from_raw(func)
189 def get(self, store: Storelike, module: str, name: str) -> AsExtern:
190 """
191 Gets a singular item defined in this linker.
193 Raises an error if this item hasn't been defined or if the item has been
194 defined twice with different types.
195 """
196 module_bytes = module.encode('utf-8')
197 module_buf = ctypes.create_string_buffer(module_bytes)
198 name_bytes = name.encode('utf-8')
199 name_buf = ctypes.create_string_buffer(name_bytes)
200 item = ffi.wasmtime_extern_t()
201 ok = ffi.wasmtime_linker_get(self.ptr(), store._context(),
202 module_buf, len(module_bytes),
203 name_buf, len(name_bytes),
204 ctypes.byref(item))
205 if ok:
206 return wrap_extern(item)
207 raise WasmtimeError("item not defined in linker")