Proposal: change `mojo run` argument handling

Hi, I’m Fraser and I work on the compiler team.

I’d like to propose a small change to how mojo run (and mojo debug) handle the split between compiler and program arguments. I’m looking for community feedback and whether people would find it valuable.

As you probably know, mojo run has the following form:

mojo [compiler-options] input.mojo [program-args]

That is, everything before the input filename is treated as a compiler option, and everything after the filename is passed on to the program when it’s run.

I and others have in the past found this behaviour unintuitive. My primary concern is a user thinking they are passing a compiler option when in fact it’s silently being passed to a program that ignores it. For example: wondering why a compiled program doesn’t set the right define; why it doesn’t enable an optimization you’re asking for; why it doesn’t compile for the right CPU:

mojo input.mojo --mcpu=haswell -Dfoo=42 --make-it-fast

These scenarios could all do the wrong thing quite silently.

I therefore propose that we split compiler and program arguments with a double-dash --.

mojo [compiler-options-or-input-file] [-- [program-args]]

This form would make clear the distinction between the two options categories. This could be useful, e.g., if the compiler and program accept similar-looking options (e.g., --help). It also allows compiler options to be interleaved with the input file.

For example:

mojo run --A --B input.mojo --C -- --D E F

With this form, options --A, --B, and --C are passed to the compiler, and arguments --D, E, and F are passed to the program.

There is precedent for this sort of argument handling, including in POSIX guidelines and amongst some other common developer tools.

This would be a breaking change, as any scripts or workflows currently passing arguments to the program (after the input file) would suddenly start passing them to the compiler. This would more likely than not result in a compiler error (as it will error on any unrecognized arguments) but that’s not universally true.

I look forward to your feedback!

2 Likes

I agree, moving to follow POSIX would be good here.

While you’re at it, is making -Dfoo=42 work possible? Right now it gives an error unless you do -D foo=42. In general, I’d love of all single-character compiler flags followed standard convention and you could have arguments to them with no spaces (ex: -I, -j). -O appears to be special cased to work as one would expect. This shouldn’t be a breaking change but would be a nice “while you’re there” change.

1 Like

Just to get this right, if I do not care about compiler args and simply want to run my program with cli args, I would have to do

mojo run myprogram -- -myarg

and

mojo run myprogram -myarg

would run into a compiler error unless the argument is recognized?

For this simple use case, I do not find this ideal.

I do see your point, though, and I may have been running into the issue myself.

Would it be an option to check all arguments whether they match compiler args and raise a warning if they do? And maybe suppress the warning with --?

Oh, thanks for bringing that up! I agree that if we offer options that mirror standard conventions (like -D) then they should behave as such. I’ll make a note.

That’s right - going by my proposal, you’d have to specify the -- regardless. It is unfortunately more characters.

I’m not sure how I feel about checking all arguments. It’s ultimately ambiguous whether or not an option is a compiler or program argument (--help could be both) and I personally like keeping tools simple and consistent.

I should say, I fixed the issue with conjoined -D a week or two back so -Dfoo=42 should work for you now. I couldn’t see a problem with -I and -j. Please file a ticket if you see anything else that needs fixing up!

Sorry if I sent you on a wild goose chase, I meant to use -I and -jas examples of how it should work.-D` now works as expected and my habits from C are no longer fighting me. Thank you!