6
6
) ]
7
7
8
8
use anyhow:: { anyhow, bail, Context as _, Error , Result } ;
9
- use clap:: builder:: { OsStringValueParser , TypedValueParser } ;
10
9
use clap:: Parser ;
11
- use std:: ffi:: OsStr ;
12
- use std:: ffi:: OsString ;
13
10
use std:: fs:: File ;
14
11
use std:: io:: Write ;
15
12
use std:: path:: { Path , PathBuf } ;
@@ -38,18 +35,6 @@ use wasmtime_wasi_threads::WasiThreadsCtx;
38
35
#[ cfg( feature = "wasi-http" ) ]
39
36
use wasmtime_wasi_http:: WasiHttpCtx ;
40
37
41
- fn parse_module ( s : OsString ) -> anyhow:: Result < PathBuf > {
42
- // Do not accept wasmtime subcommand names as the module name
43
- match s. to_str ( ) {
44
- Some ( "help" ) | Some ( "config" ) | Some ( "run" ) | Some ( "wast" ) | Some ( "compile" ) => {
45
- bail ! ( "module name cannot be the same as a subcommand" )
46
- }
47
- #[ cfg( unix) ]
48
- Some ( "-" ) => Ok ( PathBuf :: from ( "/dev/stdin" ) ) ,
49
- _ => Ok ( s. into ( ) ) ,
50
- }
51
- }
52
-
53
38
fn parse_env_var ( s : & str ) -> Result < ( String , Option < String > ) > {
54
39
let mut parts = s. splitn ( 2 , '=' ) ;
55
40
Ok ( (
@@ -100,7 +85,11 @@ fn parse_profile(s: &str) -> Result<Profile> {
100
85
101
86
/// Runs a WebAssembly module
102
87
#[ derive( Parser ) ]
88
+ <<<<<<< HEAD
103
89
#[ structopt ( name = "run" , trailing_var_arg = true ) ]
90
+ =======
91
+ #[ structopt ( name = "run" , after_help = AFTER_HELP . as_str ( ) ) ]
92
+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
104
93
pub struct RunCommand {
105
94
#[ clap ( flatten ) ]
106
95
common: CommonOptions ,
@@ -137,13 +126,30 @@ pub struct RunCommand {
137
126
#[ clap( long, value_name = "FUNCTION" ) ]
138
127
invoke: Option <String >,
139
128
129
+ <<<<<<< HEAD
140
130
/// The path of the WebAssembly module to run
141
131
#[ clap(
142
132
required = true ,
143
133
value_name = "MODULE" ,
144
134
value_parser = OsStringValueParser :: new( ) . try_map( parse_module) ,
145
135
) ]
146
136
module: PathBuf ,
137
+ =======
138
+ /// Grant access to a guest directory mapped as a host directory
139
+ #[ clap( long = "mapdir" , number_of_values = 1 , value_name = "GUEST_DIR::HOST_DIR" , value_parser = parse_map_dirs) ]
140
+ map_dirs: Vec <( String , String ) >,
141
+
142
+ /// Pre-load machine learning graphs (i.e., models) for use by wasi-nn.
143
+ ///
144
+ /// Each use of the flag will preload a ML model from the host directory
145
+ /// using the given model encoding. The model will be mapped to the
146
+ /// directory name: e.g., `--wasi-nn-graph openvino:/foo/bar` will preload
147
+ /// an OpenVINO model named `bar`. Note that which model encodings are
148
+ /// available is dependent on the backends implemented in the
149
+ /// `wasmtime_wasi_nn` crate.
150
+ #[ clap( long = "wasi-nn-graph" , value_name = "FORMAT::HOST_DIR" , value_parser = parse_graphs) ]
151
+ graphs: Vec <( String , String ) >,
152
+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
147
153
148
154
/// Load the given WebAssembly module before the main module
149
155
#[ clap(
@@ -176,10 +182,70 @@ pub struct RunCommand {
176
182
) ]
177
183
profile: Option <Profile >,
178
184
185
+ <<<<<<< HEAD
179
186
// NOTE: this must come last for trailing varargs
180
187
/// The arguments to pass to the module
181
188
#[ clap( value_name = "ARGS" ) ]
182
189
module_args: Vec <String >,
190
+ =======
191
+ /// Enable coredump generation after a WebAssembly trap.
192
+ #[ clap( long = "coredump-on-trap" , value_name = "PATH" ) ]
193
+ coredump_on_trap: Option <String >,
194
+
195
+ /// Maximum size, in bytes, that a linear memory is allowed to reach.
196
+ ///
197
+ /// Growth beyond this limit will cause `memory.grow` instructions in
198
+ /// WebAssembly modules to return -1 and fail.
199
+ #[ clap( long, value_name = "BYTES" ) ]
200
+ max_memory_size: Option <usize>,
201
+
202
+ /// Maximum size, in table elements, that a table is allowed to reach.
203
+ #[ clap( long) ]
204
+ max_table_elements: Option <u32>,
205
+
206
+ /// Maximum number of WebAssembly instances allowed to be created.
207
+ #[ clap( long) ]
208
+ max_instances: Option <usize>,
209
+
210
+ /// Maximum number of WebAssembly tables allowed to be created.
211
+ #[ clap( long) ]
212
+ max_tables: Option <usize>,
213
+
214
+ /// Maximum number of WebAssembly linear memories allowed to be created.
215
+ #[ clap( long) ]
216
+ max_memories: Option <usize>,
217
+
218
+ /// Force a trap to be raised on `memory.grow` and `table.grow` failure
219
+ /// instead of returning -1 from these instructions.
220
+ ///
221
+ /// This is not necessarily a spec-compliant option to enable but can be
222
+ /// useful for tracking down a backtrace of what is requesting so much
223
+ /// memory, for example.
224
+ #[ clap( long) ]
225
+ trap_on_grow_failure: bool ,
226
+
227
+ /// Enables memory error checking.
228
+ ///
229
+ /// See wmemcheck.md for documentation on how to use.
230
+ #[ clap( long) ]
231
+ wmemcheck: bool ,
232
+
233
+ /// The WebAssembly module to run and arguments to pass to it.
234
+ ///
235
+ /// Arguments passed to the wasm module will be configured as WASI CLI
236
+ /// arguments unless the `--invoke` CLI argument is passed in which case
237
+ /// arguments will be interpreted as arguments to the function specified.
238
+ #[ clap( value_name = "WASM" , trailing_var_arg = true , required = true ) ]
239
+ module_and_args: Vec <PathBuf >,
240
+
241
+ /// Indicates that the implementation of WASI preview1 should be backed by
242
+ /// the preview2 implementation for components.
243
+ ///
244
+ /// This will become the default in the future and this option will be
245
+ /// removed. For now this is primarily here for testing.
246
+ #[ clap( long) ]
247
+ preview2: bool ,
248
+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
183
249
}
184
250
185
251
#[ derive( Clone ) ]
@@ -242,7 +308,7 @@ impl RunCommand {
242
308
let engine = Engine :: new ( & config) ?;
243
309
244
310
// Read the wasm module binary either as `*.wat` or a raw binary.
245
- let main = self . load_module ( & engine, & self . module ) ?;
311
+ let main = self . load_module ( & engine, & self . module_and_args [ 0 ] ) ?;
246
312
247
313
// Validate coredump-on-trap argument
248
314
if let Some ( coredump_path) = & self . common . debug . coredump {
@@ -335,8 +401,12 @@ impl RunCommand {
335
401
// Load the main wasm module.
336
402
match self
337
403
. load_main_module ( & mut store, & mut linker, & main, modules)
338
- . with_context ( || format ! ( "failed to run main module `{}`" , self . module. display( ) ) )
339
- {
404
+ . with_context ( || {
405
+ format ! (
406
+ "failed to run main module `{}`" ,
407
+ self . module_and_args[ 0 ] . display( )
408
+ )
409
+ } ) {
340
410
Ok ( ( ) ) => ( ) ,
341
411
Err ( e) => {
342
412
// Exit the process if Wasmtime understands the error;
@@ -377,27 +447,25 @@ impl RunCommand {
377
447
Ok ( listeners)
378
448
}
379
449
380
- fn compute_argv ( & self ) -> Vec < String > {
450
+ fn compute_argv ( & self ) -> Result < Vec < String > > {
381
451
let mut result = Vec :: new ( ) ;
382
452
383
- // Add argv[0], which is the program name. Only include the base name of the
384
- // main wasm module, to avoid leaking path information.
385
- result. push (
386
- self . module
387
- . components ( )
388
- . next_back ( )
389
- . map ( |c| c. as_os_str ( ) )
390
- . and_then ( OsStr :: to_str)
391
- . unwrap_or ( "" )
392
- . to_owned ( ) ,
393
- ) ;
394
-
395
- // Add the remaining arguments.
396
- for arg in self . module_args . iter ( ) {
397
- result. push ( arg. clone ( ) ) ;
453
+ for ( i, arg) in self . module_and_args . iter ( ) . enumerate ( ) {
454
+ // For argv[0], which is the program name. Only include the base
455
+ // name of the main wasm module, to avoid leaking path information.
456
+ let arg = if i == 0 {
457
+ arg. components ( ) . next_back ( ) . unwrap ( ) . as_os_str ( )
458
+ } else {
459
+ arg. as_ref ( )
460
+ } ;
461
+ result. push (
462
+ arg. to_str ( )
463
+ . ok_or_else ( || anyhow ! ( "failed to convert {arg:?} to utf-8" ) ) ?
464
+ . to_string ( ) ,
465
+ ) ;
398
466
}
399
467
400
- result
468
+ Ok ( result)
401
469
}
402
470
403
471
fn setup_epoch_handler (
@@ -406,7 +474,7 @@ impl RunCommand {
406
474
modules : Vec < ( String , Module ) > ,
407
475
) -> Box < dyn FnOnce ( & mut Store < Host > ) > {
408
476
if let Some ( Profile :: Guest { path, interval } ) = & self . profile {
409
- let module_name = self . module . to_str ( ) . unwrap_or ( "<main module>" ) ;
477
+ let module_name = self . module_and_args [ 0 ] . to_str ( ) . unwrap_or ( "<main module>" ) ;
410
478
let interval = * interval;
411
479
store. data_mut ( ) . guest_profiler =
412
480
Some ( Arc :: new ( GuestProfiler :: new ( module_name, interval, modules) ) ) ;
@@ -512,9 +580,10 @@ impl RunCommand {
512
580
CliLinker :: Core ( linker) => {
513
581
// Use "" as a default module name.
514
582
let module = module. unwrap_core ( ) ;
515
- linker
516
- . module ( & mut * store, "" , & module)
517
- . context ( format ! ( "failed to instantiate {:?}" , self . module) ) ?;
583
+ linker. module ( & mut * store, "" , & module) . context ( format ! (
584
+ "failed to instantiate {:?}" ,
585
+ self . module_and_args[ 0 ]
586
+ ) ) ?;
518
587
519
588
// If a function to invoke was given, invoke it.
520
589
let func = if let Some ( name) = & self . invoke {
@@ -569,7 +638,7 @@ impl RunCommand {
569
638
is experimental and may break in the future"
570
639
) ;
571
640
}
572
- let mut args = self . module_args . iter ( ) ;
641
+ let mut args = self . module_and_args . iter ( ) . skip ( 1 ) ;
573
642
let mut values = Vec :: new ( ) ;
574
643
for ty in ty. params ( ) {
575
644
let val = match args. next ( ) {
@@ -582,6 +651,9 @@ impl RunCommand {
582
651
}
583
652
}
584
653
} ;
654
+ let val = val
655
+ . to_str ( )
656
+ . ok_or_else ( || anyhow ! ( "argument is not valid utf-8: {val:?}" ) ) ?;
585
657
values. push ( match ty {
586
658
// TODO: integer parsing here should handle hexadecimal notation
587
659
// like `0x0...`, but the Rust standard library currently only
@@ -639,7 +711,9 @@ impl RunCommand {
639
711
if !err. is :: < wasmtime:: Trap > ( ) {
640
712
return err;
641
713
}
642
- let source_name = self . module . to_str ( ) . unwrap_or_else ( || "unknown" ) ;
714
+ let source_name = self . module_and_args [ 0 ]
715
+ . to_str ( )
716
+ . unwrap_or_else ( || "unknown" ) ;
643
717
644
718
if let Err ( coredump_err) = generate_coredump ( & err, & source_name, coredump_path) {
645
719
eprintln ! ( "warning: coredump failed to generate: {}" , coredump_err) ;
@@ -884,7 +958,7 @@ impl RunCommand {
884
958
885
959
fn set_preview1_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
886
960
let mut builder = WasiCtxBuilder :: new ( ) ;
887
- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ?;
961
+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ?;
888
962
889
963
for ( key, value) in self . vars . iter ( ) {
890
964
let value = match value {
@@ -916,7 +990,7 @@ impl RunCommand {
916
990
917
991
fn set_preview2_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
918
992
let mut builder = preview2:: WasiCtxBuilder :: new ( ) ;
919
- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ;
993
+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ;
920
994
921
995
for ( key, value) in self . vars . iter ( ) {
922
996
let value = match value {
0 commit comments