Skip to content

Redesign Wasmtime's CLI flags #6741

@alexcrichton

Description

@alexcrichton

Currently the set of CLI flags added to Wasmtime has been ad-hoc and generally "throw another option in there" style historically, which is great for easily adding new options (which happens a fair bit), but I personally feel like there have been some growing pains that may be worthwhile to address sooner rather than later.

Some concerns I have with the current CLI are:

  • Discoverability is hard right now as --help or -h prints out quite a lot of information.
  • Not a lot of single-letter flags are in use so CLI commands tend to be quite long
  • It's tough to review "at a glance" what Wasmtime's capabilities are on the CLI through the help page since there's so much to sift through
  • Some options have little papercuts like trying to remember --dir vs --mapdir, there's no way to inherit the caller's environment or a single env var from the environment easily, etc.
  • Options can be randomly --disable-foo or --enable-foo and it's not clear why which is which when you're approaching the CLI for the first time.

To be clear none of these are dealbreakers by any means. While I think the Wasmtime CLI is important the embedding API are where things "get serious" so it's ok for the CLI to not be perfect. That being said folks often interact with Wasmtime through the CLI to start off with and it's also mega-useful during development and debugging and such.

So given all the above I'd like to propose a (hopefully) brief bikeshed about the Wasmtime CLI. I'd like to ideally address the above concerns and provide guidelines of how to add new options into the future. This will hopefully clean up our CLI, make it a bit more ergonomic to use, all while not hindering our ability to easily add various knobs here and there as they're implemented.

At a high level my proposal is "let's do what rustc does". I'm very biased in that regard as I helped design rustc's CLI as well. Some things I like about rustc though are:

  • The output of rustc -h fits more-or-less on one terminal. This serves as a good index from which you can learn more.
  • There are "option groups" that are behind other flags, such as rustc -C foo or rustc -Z foo. These single-letter capital flags are easy to type and easy to remember and serve as a good place to house sub-options.
  • More information can be read through rustc -C help which provides an window into all the codegen capabilities of rustc
  • Instead of --enable-foo or --disable-foo most rustc options are -C foo for --enable-foo or -C foo=no for --disable-foo. This makes it easy for callers to forcibly enable/disable something and you don't have to worry about what the defaults are since as a user you typically want to turn something on or off and you don't care too much about whatever the default happens to be.

My proposal here for Wasmtime's option groups are:

Codegen options (-C or --codegen)

  • All --disable-foo flags become -C foo=no
  • All --enable-foo flags become -C foo
  • -C foo is shorthand for -C foo=yes
  • *=yes can support y, yes, true, etc
  • *=no can support n, no, false, etc
  • Non-boolean flags support -C name=val where val is parsed as whatever
    name wants.
  • Can support comma-separation as well such as -C foo,bar or -C foo=n,bar
old cli flag new cli flag
--compiler <COMPILER> -C compiler=..
-O, --optimize -C opt-level=N / -O
--opt-level <LEVEL> -C opt-level=N
--config <CONFIG_PATH> -C cache-config=..
--disable-address-map -C address-map=no
--disable-cache -C cache=no
--disable-parallel-compilation -C parallel-compilation=no
--epoch-interruption -C epoch-interruption
-g -C debuginfo / -g
--dynamic-memory-guard-size <SIZE> -C dynamic-memory-guard-size=...
--static-memory-forced -C static-memory-forced
--static-memory-guard-size <SIZE> -C static-memory-guard-size=N
--static-memory-maximum-size <MAXIMUM> -C static-memory-maximum-size=N
--relaxed-simd-deterministic -C relaxed-simd-deterministic
--cranelift-enable <SETTING> -C cranelift-NAME
--enable-cranelift-debug-verifier -C cranelift-debug-verifier
--enable-cranelift-nan-canonicalization -C cranelift-nan-canonicalization
--cranelift-set <NAME=VALUE> -C cranelift-NAME=VALUE

Runtime options (-R or --runtime)

  • Various *-unknown-* options are all -R unknown-* now.
  • Same system for boolean flags as -C options
old cli flag new cli flag
--allow-unknown-exports -R unknown-exports-allow
--trap-unknown-imports -R unknown-imports-trap
--default-values-unknown-imports -R unknown-imports-default
--coredump-on-trap <PATH> -R coredump=..
--disable-logging -R logging=no
--disable-memory-init-cow -R memory-init-cow=no
--dynamic-memory-reserved-for-growth <SIZE> -R dynamic-memory-reserved-for-growth=...
--fuel <N> -R fuel=N
--log-to-files -R log-to-files
--max-instances <MAX_INSTANCES> -R max-instances=N
--max-memories <MAX_MEMORIES> -R max-memories=N
--max-memory-size <BYTES> -R max-memory-size=N
--max-table-elements <MAX_TABLE_ELEMENTS> -R max-table-elements=N
--max-tables <MAX_TABLES> -R max-tables=N
--max-wasm-stack <MAX_WASM_STACK> -R max-wasm-stack=N
--pooling-allocator -R pooling-allocator
--trap-on-grow-failure -R trap-on-grow-failure
--wasm-timeout <TIME> -R timeout=N

WASI options (-W or --wasi)

  • Separate from runtime options as this'll have WASI-proposal-specific
    configuration options.
  • Leave --env as its own standalone flag
  • Add support for --env FOO which inherits the env var FOO from the outer
    process.
old cli flag new cli flag
--listenfd -W listenfd
--tcplisten <SOCKET ADDRESS> -W tcplisten=...
--wasi-modules <MODULE,MODULE,...> -W common
--wasi-modules <MODULE,MODULE,...> -W experimental-threads
--dir <DIRECTORY> -W dir=..
--mapdir <GUEST_DIR::HOST_DIR> -W dir=a::b
--env <NAME=VAL> --env ...

Other flags

These are the other flags supported by Wasmtime which don't necessarily fit into the groups above. They're either important enough I think they should stick around at the top level or they have enough of their own "sub-syntax" that I'm not sure they fit well in the groups above.

  • --wasm-features <FEATURE,FEATURE,...> - perhaps add something like a -F
    shortcut, I find it a bit annoying to always type this out. Support --wasm-features help for the extended help section on this.
  • --preload <NAME=MODULE_PATH> - allow omitting NAME and infer it by default
    from MODULE_PATH.
  • --profile <STRATEGY> - leave as-is
  • --invoke <FUNCTION> - leave as-is
  • --allow-precompiled - leave as-is
  • --target <TARGET> - leave as-is
  • --output <OUTPUT> - leave as-is
  • --emit-clif <PATH> - leave as-is

I'm curious what others think about this! If it's broadly amenable and folks are ok with the breakage I'm happy to implement this myself, I don't think it'll take all that long (perhaps just a day or so)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions