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