xref: /aosp_15_r20/art/cmdline/README.md (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard WorkerCmdline
2*795d594fSAndroid Build Coastguard Worker===================
3*795d594fSAndroid Build Coastguard Worker
4*795d594fSAndroid Build Coastguard WorkerIntroduction
5*795d594fSAndroid Build Coastguard Worker-------------
6*795d594fSAndroid Build Coastguard WorkerThis directory contains the classes that do common command line tool initialization and parsing. The
7*795d594fSAndroid Build Coastguard Workerlong term goal is eventually for all `art` command-line tools to be using these helpers.
8*795d594fSAndroid Build Coastguard Worker
9*795d594fSAndroid Build Coastguard Worker----------
10*795d594fSAndroid Build Coastguard Worker
11*795d594fSAndroid Build Coastguard Worker
12*795d594fSAndroid Build Coastguard Worker## Cmdline Parser
13*795d594fSAndroid Build Coastguard Worker-------------
14*795d594fSAndroid Build Coastguard Worker
15*795d594fSAndroid Build Coastguard WorkerThe `CmdlineParser` class provides a fluent interface using a domain-specific language to quickly
16*795d594fSAndroid Build Coastguard Workergenerate a type-safe value parser that process a user-provided list of strings (`argv`). Currently,
17*795d594fSAndroid Build Coastguard Workerit can parse a string into a `VariantMap`, although in the future it might be desirable to parse
18*795d594fSAndroid Build Coastguard Workerinto any struct of any field.
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard WorkerTo use, create a `CmdlineParser::Builder` and then chain the `Define` methods together with
21*795d594fSAndroid Build Coastguard Worker`WithType` and `IntoXX` methods.
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker### Quick Start
24*795d594fSAndroid Build Coastguard WorkerFor example, to save the values into a user-defined variant map:
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker```
27*795d594fSAndroid Build Coastguard Workerstruct FruitVariantMap : VariantMap {
28*795d594fSAndroid Build Coastguard Worker  static const Key<int> Apple;
29*795d594fSAndroid Build Coastguard Worker  static const Key<double> Orange;
30*795d594fSAndroid Build Coastguard Worker  static const Key<bool> Help;
31*795d594fSAndroid Build Coastguard Worker};
32*795d594fSAndroid Build Coastguard Worker// Note that some template boilerplate has been avoided for clarity.
33*795d594fSAndroid Build Coastguard Worker// See variant_map_test.cc for how to completely define a custom map.
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Workerusing FruitParser = CmdlineParser<FruitVariantMap, FruitVariantMap::Key>;
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard WorkerFruitParser MakeParser() {
38*795d594fSAndroid Build Coastguard Worker  auto&& builder = FruitParser::Builder();
39*795d594fSAndroid Build Coastguard Worker  builder.
40*795d594fSAndroid Build Coastguard Worker   .Define("--help")
41*795d594fSAndroid Build Coastguard Worker      .IntoKey(FruitVariantMap::Help)
42*795d594fSAndroid Build Coastguard Worker    Define("--apple:_")
43*795d594fSAndroid Build Coastguard Worker      .WithType<int>()
44*795d594fSAndroid Build Coastguard Worker      .IntoKey(FruitVariantMap::Apple)
45*795d594fSAndroid Build Coastguard Worker   .Define("--orange:_")
46*795d594fSAndroid Build Coastguard Worker      .WithType<double>()
47*795d594fSAndroid Build Coastguard Worker      .WithRange(0.0, 1.0)
48*795d594fSAndroid Build Coastguard Worker      .IntoKey(FruitVariantMap::Orange);
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker  return builder.Build();
51*795d594fSAndroid Build Coastguard Worker}
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Workerint main(char** argv, int argc) {
54*795d594fSAndroid Build Coastguard Worker  auto parser = MakeParser();
55*795d594fSAndroid Build Coastguard Worker  auto result = parser.parse(argv, argc));
56*795d594fSAndroid Build Coastguard Worker  if (result.isError()) {
57*795d594fSAndroid Build Coastguard Worker     std::cerr << result.getMessage() << std::endl;
58*795d594fSAndroid Build Coastguard Worker     return EXIT_FAILURE;
59*795d594fSAndroid Build Coastguard Worker  }
60*795d594fSAndroid Build Coastguard Worker  auto map = parser.GetArgumentsMap();
61*795d594fSAndroid Build Coastguard Worker  std::cout << "Help? " << map.GetOrDefault(FruitVariantMap::Help) << std::endl;
62*795d594fSAndroid Build Coastguard Worker  std::cout << "Apple? " << map.GetOrDefault(FruitVariantMap::Apple) << std::endl;
63*795d594fSAndroid Build Coastguard Worker  std::cout << "Orange? " << map.GetOrDefault(FruitVariantMap::Orange) << std::endl;
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker  return EXIT_SUCCESS;
66*795d594fSAndroid Build Coastguard Worker}
67*795d594fSAndroid Build Coastguard Worker```
68*795d594fSAndroid Build Coastguard Worker
69*795d594fSAndroid Build Coastguard WorkerIn the above code sample, we define a parser which is capable of parsing something like `--help
70*795d594fSAndroid Build Coastguard Worker--apple:123 --orange:0.456` . It will error out automatically if invalid flags are given, or if the
71*795d594fSAndroid Build Coastguard Workerappropriate flags are given but of the the wrong type/range. So for example, `--foo` will not parse
72*795d594fSAndroid Build Coastguard Worker(invalid argument), neither will `--apple:fruit` (fruit is not an int) nor `--orange:1234` (1234 is
73*795d594fSAndroid Build Coastguard Workerout of range of [0.0, 1.0])
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker### Argument Definitions in Detail
76*795d594fSAndroid Build Coastguard Worker#### Define method
77*795d594fSAndroid Build Coastguard WorkerThe 'Define' method takes one or more aliases for the argument. Common examples might be `{"-h",
78*795d594fSAndroid Build Coastguard Worker"--help"}` where both `--help` and `-h` are aliases for the same argument.
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard WorkerThe simplest kind of argument just tests for presence, but we often want to parse out a particular
81*795d594fSAndroid Build Coastguard Workertype of value (such as an int or double as in the above `FruitVariantMap` example). To do that, a
82*795d594fSAndroid Build Coastguard Worker_wildcard_ must be used to denote the location within the token that the type will be parsed out of.
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard WorkerFor example with `-orange:_` the parse would know to check all tokens in an `argv` list for the
85*795d594fSAndroid Build Coastguard Worker`-orange:` prefix and then strip it, leaving only the remains to be parsed.
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker#### WithType method (optional)
88*795d594fSAndroid Build Coastguard WorkerAfter an argument definition is provided, the parser builder needs to know what type the argument
89*795d594fSAndroid Build Coastguard Workerwill be in order to provide the type safety and make sure the rest of the argument definition is
90*795d594fSAndroid Build Coastguard Workercorrect as early as possible (in essence, everything but the parsing of the argument name is done at
91*795d594fSAndroid Build Coastguard Workercompile time).
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard WorkerEverything that follows a `WithType<T>()` call is thus type checked to only take `T` values.
94*795d594fSAndroid Build Coastguard Worker
95*795d594fSAndroid Build Coastguard WorkerIf this call is omitted, the parser generator assumes you are building a `Unit` type (i.e. an
96*795d594fSAndroid Build Coastguard Workerargument that only cares about presence).
97*795d594fSAndroid Build Coastguard Worker
98*795d594fSAndroid Build Coastguard Worker#### WithRange method (optional)
99*795d594fSAndroid Build Coastguard WorkerSome values will not make sense outside of a `[min, max]` range, so this is an option to quickly add
100*795d594fSAndroid Build Coastguard Workera range check without writing custom code. The range check is performed after the main parsing
101*795d594fSAndroid Build Coastguard Workerhappens and happens for any type implementing the `<=` operators.
102*795d594fSAndroid Build Coastguard Worker
103*795d594fSAndroid Build Coastguard Worker#### WithValueMap (optional)
104*795d594fSAndroid Build Coastguard WorkerWhen parsing an enumeration, it might be very convenient to map a list of possible argument string
105*795d594fSAndroid Build Coastguard Workervalues into its runtime value.
106*795d594fSAndroid Build Coastguard Worker
107*795d594fSAndroid Build Coastguard WorkerWith something like
108*795d594fSAndroid Build Coastguard Worker```
109*795d594fSAndroid Build Coastguard Worker    .Define("-hello:_")
110*795d594fSAndroid Build Coastguard Worker      .WithValueMap({"world", kWorld},
111*795d594fSAndroid Build Coastguard Worker                    {"galaxy", kGalaxy})
112*795d594fSAndroid Build Coastguard Worker```
113*795d594fSAndroid Build Coastguard WorkerIt will parse either `-hello:world` or `-hello:galaxy` only (and error out on other variations of
114*795d594fSAndroid Build Coastguard Worker`-hello:whatever`), converting it to the type-safe value of `kWorld` or `kGalaxy` respectively.
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard WorkerThis is meant to be another shorthand (like `WithRange`) to avoid writing a custom type parser. In
117*795d594fSAndroid Build Coastguard Workergeneral it takes a variadic number of `pair<const char* /*arg name*/, T /*value*/>`.
118*795d594fSAndroid Build Coastguard Worker
119*795d594fSAndroid Build Coastguard Worker#### WithValues (optional)
120*795d594fSAndroid Build Coastguard WorkerWhen an argument definition has multiple aliases with no wildcards, it might be convenient to
121*795d594fSAndroid Build Coastguard Workerquickly map them into discrete values.
122*795d594fSAndroid Build Coastguard Worker
123*795d594fSAndroid Build Coastguard WorkerFor example:
124*795d594fSAndroid Build Coastguard Worker```
125*795d594fSAndroid Build Coastguard Worker  .Define({"-xinterpret", "-xnointerpret"})
126*795d594fSAndroid Build Coastguard Worker    .WithValues({true, false}
127*795d594fSAndroid Build Coastguard Worker```
128*795d594fSAndroid Build Coastguard WorkerIt will parse `-xinterpret` as `true` and `-xnointerpret` as `false`.
129*795d594fSAndroid Build Coastguard Worker
130*795d594fSAndroid Build Coastguard WorkerIn general, it uses the position of the argument alias to map into the WithValues position value.
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker(Note that this method will not work when the argument definitions have a wildcard because there is
133*795d594fSAndroid Build Coastguard Workerno way to position-ally match that).
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker#### AppendValues (optional)
136*795d594fSAndroid Build Coastguard WorkerBy default, the argument is assumed to appear exactly once, and if the user specifies it more than
137*795d594fSAndroid Build Coastguard Workeronce, only the latest value is taken into account (and all previous occurrences of the argument are
138*795d594fSAndroid Build Coastguard Workerignored).
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard WorkerIn some situations, we may want to accumulate the argument values instead of discarding the previous
141*795d594fSAndroid Build Coastguard Workerones.
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard WorkerFor example
144*795d594fSAndroid Build Coastguard Worker```
145*795d594fSAndroid Build Coastguard Worker  .Define("-D")
146*795d594fSAndroid Build Coastguard Worker     .WithType<std::vector<std::string>)()
147*795d594fSAndroid Build Coastguard Worker     .AppendValues()
148*795d594fSAndroid Build Coastguard Worker```
149*795d594fSAndroid Build Coastguard WorkerWill parse something like `-Dhello -Dworld -Dbar -Dbaz` into `std::vector<std::string>{"hello",
150*795d594fSAndroid Build Coastguard Worker"world", "bar", "baz"}`.
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker### Setting an argument parse target (required)
153*795d594fSAndroid Build Coastguard WorkerTo complete an argument definition, the parser generator also needs to know where to save values.
154*795d594fSAndroid Build Coastguard WorkerCurrently, only `IntoKey` is supported, but that may change in the future.
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker#### IntoKey (required)
157*795d594fSAndroid Build Coastguard WorkerThis specifies that when a value is parsed, it will get saved into a variant map using the specific
158*795d594fSAndroid Build Coastguard Workerkey.
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard WorkerFor example,
161*795d594fSAndroid Build Coastguard Worker```
162*795d594fSAndroid Build Coastguard Worker   .Define("-help")
163*795d594fSAndroid Build Coastguard Worker     .IntoKey(Map::Help)
164*795d594fSAndroid Build Coastguard Worker```
165*795d594fSAndroid Build Coastguard Workerwill save occurrences of the `-help` argument by doing a `Map.Set(Map::Help, ParsedValue("-help"))`
166*795d594fSAndroid Build Coastguard Workerwhere `ParsedValue` is an imaginary function that parses the `-help` argment into a specific type
167*795d594fSAndroid Build Coastguard Workerset by `WithType`.
168*795d594fSAndroid Build Coastguard Worker
169*795d594fSAndroid Build Coastguard Worker### Ignoring unknown arguments
170*795d594fSAndroid Build Coastguard WorkerThis is highly discouraged, but for compatibility with `JNI` which allows argument ignores, there is
171*795d594fSAndroid Build Coastguard Workeran option to ignore any argument tokens that are not known to the parser. This is done with the
172*795d594fSAndroid Build Coastguard Worker`Ignore` function which takes a list of argument definition names.
173*795d594fSAndroid Build Coastguard Worker
174*795d594fSAndroid Build Coastguard WorkerIt's semantically equivalent to making a series of argument definitions that map to `Unit` but don't
175*795d594fSAndroid Build Coastguard Workerget saved anywhere. Values will still get parsed as normal, so it will *not* ignore known arguments
176*795d594fSAndroid Build Coastguard Workerwith invalid values, only user-arguments for which it could not find a matching argument definition.
177*795d594fSAndroid Build Coastguard Worker
178*795d594fSAndroid Build Coastguard Worker### Parsing custom types
179*795d594fSAndroid Build Coastguard WorkerAny type can be parsed from a string by specializing the `CmdlineType` class and implementing the
180*795d594fSAndroid Build Coastguard Workerstatic interface provided by `CmdlineTypeParser`. It is recommended to inherit from
181*795d594fSAndroid Build Coastguard Worker`CmdlineTypeParser` since it already provides default implementations for every method.
182*795d594fSAndroid Build Coastguard Worker
183*795d594fSAndroid Build Coastguard WorkerThe `Parse` method should be implemented for most types. Some types will allow appending (such as an
184*795d594fSAndroid Build Coastguard Worker`std::vector<std::string>` and are meant to be used with `AppendValues` in which case the
185*795d594fSAndroid Build Coastguard Worker`ParseAndAppend` function should be implemented.
186*795d594fSAndroid Build Coastguard Worker
187*795d594fSAndroid Build Coastguard WorkerFor example:
188*795d594fSAndroid Build Coastguard Worker```
189*795d594fSAndroid Build Coastguard Workertemplate <>
190*795d594fSAndroid Build Coastguard Workerstruct CmdlineType<double> : CmdlineTypeParser<double> {
191*795d594fSAndroid Build Coastguard Worker  Result Parse(const std::string& str) {
192*795d594fSAndroid Build Coastguard Worker    char* end = nullptr;
193*795d594fSAndroid Build Coastguard Worker    errno = 0;
194*795d594fSAndroid Build Coastguard Worker    double value = strtod(str.c_str(), &end);
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker    if (*end != '\0') {
197*795d594fSAndroid Build Coastguard Worker      return Result::Failure("Failed to parse double from " + str);
198*795d594fSAndroid Build Coastguard Worker    }
199*795d594fSAndroid Build Coastguard Worker    if (errno == ERANGE) {
200*795d594fSAndroid Build Coastguard Worker      return Result::OutOfRange(
201*795d594fSAndroid Build Coastguard Worker          "Failed to parse double from " + str + "; overflow/underflow occurred");
202*795d594fSAndroid Build Coastguard Worker    }
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker    return Result::Success(value);
205*795d594fSAndroid Build Coastguard Worker  }
206*795d594fSAndroid Build Coastguard Worker
207*795d594fSAndroid Build Coastguard Worker  static const char* Name() { return "double"; }
208*795d594fSAndroid Build Coastguard Worker  // note: Name() is just here for more user-friendly errors,
209*795d594fSAndroid Build Coastguard Worker  // but in the future we will use non-standard ways of getting the type name
210*795d594fSAndroid Build Coastguard Worker  // at compile-time and this will no longer be required
211*795d594fSAndroid Build Coastguard Worker};
212*795d594fSAndroid Build Coastguard Worker```
213*795d594fSAndroid Build Coastguard WorkerWill parse any non-append argument definitions with a type of `double`.
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard WorkerFor an appending example:
216*795d594fSAndroid Build Coastguard Worker```
217*795d594fSAndroid Build Coastguard Workertemplate <>
218*795d594fSAndroid Build Coastguard Workerstruct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
219*795d594fSAndroid Build Coastguard Worker  Result ParseAndAppend(const std::string& args,
220*795d594fSAndroid Build Coastguard Worker                        std::vector<std::string>& existing_value) {
221*795d594fSAndroid Build Coastguard Worker    existing_value.push_back(args);
222*795d594fSAndroid Build Coastguard Worker    return Result::SuccessNoValue();
223*795d594fSAndroid Build Coastguard Worker  }
224*795d594fSAndroid Build Coastguard Worker  static const char* Name() { return "std::vector<std::string>"; }
225*795d594fSAndroid Build Coastguard Worker};
226*795d594fSAndroid Build Coastguard Worker```
227*795d594fSAndroid Build Coastguard WorkerWill parse multiple instances of the same argument repeatedly into the `existing_value` (which will
228*795d594fSAndroid Build Coastguard Workerbe default-constructed to `T{}` for the first occurrence of the argument).
229*795d594fSAndroid Build Coastguard Worker
230*795d594fSAndroid Build Coastguard Worker#### What is a `Result`?
231*795d594fSAndroid Build Coastguard Worker`Result` is a typedef for `CmdlineParseResult<T>` and it acts similar to a poor version of
232*795d594fSAndroid Build Coastguard Worker`Either<Left, Right>` in Haskell. In particular, it would be similar to `Either< int ErrorCode,
233*795d594fSAndroid Build Coastguard WorkerMaybe<T> >`.
234*795d594fSAndroid Build Coastguard Worker
235*795d594fSAndroid Build Coastguard WorkerThere are helpers like `Result::Success(value)`, `Result::Failure(string message)` and so on to
236*795d594fSAndroid Build Coastguard Workerquickly construct these without caring about the type.
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard WorkerWhen successfully parsing a single value, `Result::Success(value)` should be used, and when
239*795d594fSAndroid Build Coastguard Workersuccessfully parsing an appended value, use `Result::SuccessNoValue()` and write back the new value
240*795d594fSAndroid Build Coastguard Workerinto `existing_value` as an out-parameter.
241*795d594fSAndroid Build Coastguard Worker
242*795d594fSAndroid Build Coastguard WorkerWhen many arguments are parsed, the result is collapsed down to a `CmdlineResult` which acts as a
243*795d594fSAndroid Build Coastguard Worker`Either<int ErrorCode, Unit>` where the right side simply indicates success. When values are
244*795d594fSAndroid Build Coastguard Workersuccessfully stored, the parser will automatically save it into the target destination as a side
245*795d594fSAndroid Build Coastguard Workereffect.
246