0
# Module Linking
1
2
Advanced module linking system for resolving imports, connecting multiple WebAssembly modules, and creating complex WebAssembly applications with shared functionality, WASI integration, and dynamic module loading.
3
4
## Capabilities
5
6
### Linker Management
7
8
Central linking system managing module imports, instance creation, and cross-module communication with support for shadowing, WASI integration, and complex dependency resolution.
9
10
```python { .api }
11
class Linker:
12
def __init__(self, engine: Engine):
13
"""
14
Create a new linker for the given engine.
15
16
Parameters:
17
- engine: WebAssembly engine for linking context
18
"""
19
20
def allow_shadowing(self, enable: bool) -> None:
21
"""
22
Configure whether export shadowing is allowed.
23
24
Parameters:
25
- enable: True to allow shadowing, False to error on conflicts
26
"""
27
28
def define(self, store: Store, module: str, name: str, item) -> None:
29
"""
30
Define an import with a specific module and name.
31
32
Parameters:
33
- store: Store context
34
- module: Module name for the import
35
- name: Import name within the module
36
- item: Export object (Func, Memory, Table, or Global)
37
"""
38
39
def define_func(self, module: str, name: str, ty: FuncType, func: Callable) -> None:
40
"""
41
Define a function import directly from Python callable.
42
43
Parameters:
44
- module: Module name for the import
45
- name: Function name within the module
46
- ty: Function type signature
47
- func: Python callable implementing the function
48
"""
49
50
def define_wasi(self, store: Store, wasi_config: WasiConfig) -> None:
51
"""
52
Define WASI imports using the given configuration.
53
54
Parameters:
55
- store: Store context
56
- wasi_config: WASI configuration for system interface
57
"""
58
59
def define_instance(self, store: Store, name: str, instance: Instance) -> None:
60
"""
61
Define all exports from an instance as imports.
62
63
Parameters:
64
- store: Store context
65
- name: Module name for the instance exports
66
- instance: WebAssembly instance to export
67
"""
68
69
def instantiate(self, store: Store, module: Module) -> Instance:
70
"""
71
Instantiate a module using defined imports.
72
73
Parameters:
74
- store: Store context
75
- module: WebAssembly module to instantiate
76
77
Returns:
78
Instantiated WebAssembly instance
79
80
Raises:
81
WasmtimeError: If imports don't satisfy module requirements
82
"""
83
84
def get_default(self, store: Store, name: str):
85
"""
86
Get the default export for a module.
87
88
Parameters:
89
- store: Store context
90
- name: Module name
91
92
Returns:
93
Default export object if available
94
"""
95
```
96
97
## Usage Examples
98
99
### Basic Module Linking
100
101
```python
102
import wasmtime
103
104
# Create engine and linker
105
engine = wasmtime.Engine()
106
linker = wasmtime.Linker(engine)
107
store = wasmtime.Store(engine)
108
109
# Define host functions for import
110
def host_print(message_ptr: int, message_len: int) -> None:
111
# Implementation would read from memory and print
112
print(f"Host print called with ptr={message_ptr}, len={message_len}")
113
114
print_type = wasmtime.FuncType([wasmtime.ValType.I32, wasmtime.ValType.I32], [])
115
linker.define_func("host", "print", print_type, host_print)
116
117
# Define memory for sharing between modules
118
memory_type = wasmtime.MemoryType(wasmtime.Limits(1, 10))
119
shared_memory = wasmtime.Memory(store, memory_type)
120
linker.define(store, "env", "memory", shared_memory)
121
122
# Load and instantiate module
123
module = wasmtime.Module.from_file(engine, "program.wasm")
124
instance = linker.instantiate(store, module)
125
126
print("Module instantiated with host imports")
127
```
128
129
### Multi-Module Application
130
131
```python
132
import wasmtime
133
134
engine = wasmtime.Engine()
135
linker = wasmtime.Linker(engine)
136
store = wasmtime.Store(engine)
137
138
# Load utility module first
139
utils_module = wasmtime.Module.from_file(engine, "utils.wasm")
140
utils_instance = linker.instantiate(store, utils_module)
141
142
# Make utils exports available to other modules
143
linker.define_instance(store, "utils", utils_instance)
144
145
# Load main application module that imports from utils
146
app_module = wasmtime.Module.from_file(engine, "app.wasm")
147
app_instance = linker.instantiate(store, app_module)
148
149
# Now app can use functions from utils module
150
main_func = app_instance.get_export(store, "main")
151
result = main_func(store)
152
print(f"Application result: {result}")
153
```
154
155
### WASI Application with Custom Imports
156
157
```python
158
import wasmtime
159
import time
160
161
# Custom host functions for the application
162
def get_timestamp() -> int:
163
"""Return current Unix timestamp"""
164
return int(time.time())
165
166
def sleep_ms(milliseconds: int) -> None:
167
"""Sleep for specified milliseconds"""
168
time.sleep(milliseconds / 1000.0)
169
170
# Set up linker with custom functions
171
engine = wasmtime.Engine()
172
linker = wasmtime.Linker(engine)
173
store = wasmtime.Store(engine)
174
175
# Define custom host functions
176
timestamp_type = wasmtime.FuncType([], [wasmtime.ValType.I32])
177
sleep_type = wasmtime.FuncType([wasmtime.ValType.I32], [])
178
179
linker.define_func("host", "get_timestamp", timestamp_type, get_timestamp)
180
linker.define_func("host", "sleep_ms", sleep_type, sleep_ms)
181
182
# Configure and define WASI
183
wasi_config = wasmtime.WasiConfig()
184
wasi_config.inherit_argv()
185
wasi_config.inherit_env()
186
wasi_config.inherit_stdin()
187
wasi_config.inherit_stdout()
188
wasi_config.inherit_stderr()
189
linker.define_wasi(store, wasi_config)
190
191
# Load and run WASI application with custom imports
192
module = wasmtime.Module.from_file(engine, "wasi_app.wasm")
193
instance = linker.instantiate(store, module)
194
195
# Start the application
196
try:
197
start_func = instance.get_export(store, "_start")
198
start_func(store)
199
except wasmtime.ExitTrap as exit_trap:
200
print(f"Application exited with code: {exit_trap.code}")
201
```
202
203
### Dynamic Module Loading
204
205
```python
206
import wasmtime
207
import os
208
209
class ModuleLoader:
210
def __init__(self, engine: wasmtime.Engine):
211
self.engine = engine
212
self.linker = wasmtime.Linker(engine)
213
self.store = wasmtime.Store(engine)
214
self.loaded_modules = {}
215
216
# Allow shadowing for dynamic loading
217
self.linker.allow_shadowing(True)
218
219
# Set up WASI by default
220
wasi_config = wasmtime.WasiConfig()
221
wasi_config.inherit_argv()
222
wasi_config.inherit_env()
223
wasi_config.inherit_stdin()
224
wasi_config.inherit_stdout()
225
wasi_config.inherit_stderr()
226
self.linker.define_wasi(self.store, wasi_config)
227
228
def load_module(self, name: str, path: str) -> wasmtime.Instance:
229
"""Load a WebAssembly module and make its exports available"""
230
if name in self.loaded_modules:
231
return self.loaded_modules[name]
232
233
# Load and instantiate module
234
module = wasmtime.Module.from_file(self.engine, path)
235
instance = self.linker.instantiate(self.store, module)
236
237
# Make this module's exports available to future modules
238
self.linker.define_instance(self.store, name, instance)
239
240
# Cache the instance
241
self.loaded_modules[name] = instance
242
243
print(f"Loaded module '{name}' from {path}")
244
return instance
245
246
def get_module(self, name: str) -> wasmtime.Instance:
247
"""Get a previously loaded module"""
248
if name not in self.loaded_modules:
249
raise ValueError(f"Module '{name}' not loaded")
250
return self.loaded_modules[name]
251
252
# Usage example
253
engine = wasmtime.Engine()
254
loader = ModuleLoader(engine)
255
256
# Load modules in dependency order
257
math_instance = loader.load_module("math", "math_utils.wasm")
258
string_instance = loader.load_module("string", "string_utils.wasm")
259
app_instance = loader.load_module("app", "main_app.wasm")
260
261
# The main app can now use functions from both math and string modules
262
```
263
264
### Import Resolution with Error Handling
265
266
```python
267
import wasmtime
268
269
def safe_module_linking(engine: wasmtime.Engine, module_path: str, imports_config: dict):
270
"""
271
Safely link and instantiate a module with comprehensive error handling.
272
273
Parameters:
274
- engine: WebAssembly engine
275
- module_path: Path to WebAssembly module
276
- imports_config: Dictionary of import configurations
277
"""
278
279
linker = wasmtime.Linker(engine)
280
store = wasmtime.Store(engine)
281
282
try:
283
# Load the module first to check its imports
284
module = wasmtime.Module.from_file(engine, module_path)
285
286
print(f"Module requires {len(module.imports)} imports:")
287
for import_item in module.imports:
288
print(f" {import_item.module}.{import_item.name}: {import_item.type}")
289
290
# Define imports based on configuration
291
for import_item in module.imports:
292
module_name = import_item.module
293
item_name = import_item.name
294
295
if module_name in imports_config:
296
if item_name in imports_config[module_name]:
297
import_obj = imports_config[module_name][item_name]
298
linker.define(store, module_name, item_name, import_obj)
299
print(f" ✓ Resolved {module_name}.{item_name}")
300
else:
301
print(f" ✗ Missing import: {module_name}.{item_name}")
302
else:
303
print(f" ✗ Missing module: {module_name}")
304
305
# Try to instantiate
306
print("Attempting instantiation...")
307
instance = linker.instantiate(store, module)
308
print("✓ Module instantiated successfully")
309
310
return instance
311
312
except wasmtime.WasmtimeError as e:
313
if "unknown import" in str(e):
314
print(f"✗ Import resolution failed: {e}")
315
print("Available imports in linker:")
316
# Note: Wasmtime doesn't provide a way to list available imports
317
print(" (Check your imports_config)")
318
else:
319
print(f"✗ Linking error: {e}")
320
return None
321
322
except FileNotFoundError:
323
print(f"✗ Module file not found: {module_path}")
324
return None
325
326
except Exception as e:
327
print(f"✗ Unexpected error: {e}")
328
return None
329
330
# Example usage
331
engine = wasmtime.Engine()
332
store = wasmtime.Store(engine)
333
334
# Create some sample imports
335
memory = wasmtime.Memory(store, wasmtime.MemoryType(wasmtime.Limits(1)))
336
print_func = wasmtime.Func(store,
337
wasmtime.FuncType([wasmtime.ValType.I32], []),
338
lambda x: print(f"Printed: {x}"))
339
340
imports_config = {
341
"env": {
342
"memory": memory,
343
"print": print_func
344
}
345
}
346
347
instance = safe_module_linking(engine, "test_module.wasm", imports_config)
348
if instance:
349
# Use the instance...
350
pass
351
```