We don't currently support --help, but it'd be nice to.
We could just write a separate help document and then try to make sure that we keep it in sync with the actual argument parsing, however I think it would be inevitable that the two would diverge.
See also #302 for discussion as to why we can't use something like clap.
EDIT: The suggestion here is superseded by the suggestion to use bpaf instead, so be sure to read the whole issue. Some of what's written here is still relevant though - e.g. don't copy help text. Also, still a good idea to do an initial PR that doesn't add help, then add help texts in subsequent PR(s).
My current thought on how we might approach this is to run the same function when printing help as we run when parsing, but just pass a different argument. Currently the argument passed to args::parse is an iterator over the arguments. We could replace this with something that implements our own trait, of which we'd have two implementations, one for parsing and one for printing help.
To provide a concrete example, let's take a snippet of our argument parsing code:
} else if long_arg_eq("static") || long_arg_eq("Bstatic") {
modifier_stack.last_mut().unwrap().allow_shared = false;
} else if long_arg_eq("Bdynamic") {
modifier_stack.last_mut().unwrap().allow_shared = true;
} else if arg == "-o" {
args.output = input
.next()
.map(|a| Arc::from(Path::new(a.as_ref())))
.context("Missing argument to -o")?;
}
We might rewrite this something like:
parser
.declare()
.long("static")
.long("Bstatic")
.help("Disallow linking of shared libraries")
.execute(|| {
modifier_stack.last_mut().unwrap().allow_shared = false;
});
parser
.declare()
.long("Bdynamic")
.help("Allow linking of shared libraries")
.execute(|| {
modifier_stack.last_mut().unwrap().allow_shared = true;
});
parser
.declare_with_param()
.short("-o")
.help("Set the output filename")
.execute(|a| {
args.output = Arc::from(Path::new(a.as_ref()));
});
So the argument parser trait would likely have a couple of associated types that get returned by the declare and declare_with_param methods. That will mean that we'll likely have 3 traits in total with each having two implementations. It'd also be possible to do it all with one trait and no associated types, albeit with slightly more runtime checking.
Some arguments might need to return errors from their closure. For that, we could have a try_execute that takes a closure returning a Result and which itself returns a Result.
Lots of PRs change argument parsing, so to reduce conflicts a bit, I think it'd make sense to do this change as two PRs. The first wouldn't actually add support for help, but would just change the way the existing parser is written. The second would add help support and help messages. We could also potentially add the help messages a bit at a time once the initial help support is added.
I think it's important that we not copy help text from other linkers or man pages, since if we do that, we can't put it under the same license as the rest of the repository and things get messy. So we'd need to write each bit of help text ourselves.
I'll probably open this up as a good-first-issue in a day or two once others have had a chance to comment on the design. When I do, if you'd like to work on this issue, please comment on the issue first, otherwise we risk having two people working on it at the same time without knowing and I don't want to be in the position of having to reject someone's PR because someone else did it. It's perfectly fine to say you're going to work on it, then after a day or to change your mind - just let us know.
We don't currently support --help, but it'd be nice to.
We could just write a separate help document and then try to make sure that we keep it in sync with the actual argument parsing, however I think it would be inevitable that the two would diverge.
See also #302 for discussion as to why we can't use something like clap.
EDIT: The suggestion here is superseded by the suggestion to use bpaf instead, so be sure to read the whole issue. Some of what's written here is still relevant though - e.g. don't copy help text. Also, still a good idea to do an initial PR that doesn't add help, then add help texts in subsequent PR(s).
My current thought on how we might approach this is to run the same function when printing help as we run when parsing, but just pass a different argument. Currently the argument passed to
args::parseis an iterator over the arguments. We could replace this with something that implements our own trait, of which we'd have two implementations, one for parsing and one for printing help.To provide a concrete example, let's take a snippet of our argument parsing code:
We might rewrite this something like:
So the argument parser trait would likely have a couple of associated types that get returned by the
declareanddeclare_with_parammethods. That will mean that we'll likely have 3 traits in total with each having two implementations. It'd also be possible to do it all with one trait and no associated types, albeit with slightly more runtime checking.Some arguments might need to return errors from their closure. For that, we could have a
try_executethat takes a closure returning aResultand which itself returns aResult.Lots of PRs change argument parsing, so to reduce conflicts a bit, I think it'd make sense to do this change as two PRs. The first wouldn't actually add support for help, but would just change the way the existing parser is written. The second would add help support and help messages. We could also potentially add the help messages a bit at a time once the initial help support is added.
I think it's important that we not copy help text from other linkers or man pages, since if we do that, we can't put it under the same license as the rest of the repository and things get messy. So we'd need to write each bit of help text ourselves.
I'll probably open this up as a good-first-issue in a day or two once others have had a chance to comment on the design. When I do, if you'd like to work on this issue, please comment on the issue first, otherwise we risk having two people working on it at the same time without knowing and I don't want to be in the position of having to reject someone's PR because someone else did it. It's perfectly fine to say you're going to work on it, then after a day or to change your mind - just let us know.