annotate osx/include/kj/main.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0994c39f1e94
children
rev   line source
cannam@62 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@62 2 // Licensed under the MIT License:
cannam@62 3 //
cannam@62 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@62 5 // of this software and associated documentation files (the "Software"), to deal
cannam@62 6 // in the Software without restriction, including without limitation the rights
cannam@62 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@62 8 // copies of the Software, and to permit persons to whom the Software is
cannam@62 9 // furnished to do so, subject to the following conditions:
cannam@62 10 //
cannam@62 11 // The above copyright notice and this permission notice shall be included in
cannam@62 12 // all copies or substantial portions of the Software.
cannam@62 13 //
cannam@62 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@62 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@62 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@62 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@62 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@62 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@62 20 // THE SOFTWARE.
cannam@62 21
cannam@62 22 #ifndef KJ_MAIN_H_
cannam@62 23 #define KJ_MAIN_H_
cannam@62 24
cannam@62 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
cannam@62 26 #pragma GCC system_header
cannam@62 27 #endif
cannam@62 28
cannam@62 29 #include "array.h"
cannam@62 30 #include "string.h"
cannam@62 31 #include "vector.h"
cannam@62 32 #include "function.h"
cannam@62 33
cannam@62 34 namespace kj {
cannam@62 35
cannam@62 36 class ProcessContext {
cannam@62 37 // Context for command-line programs.
cannam@62 38
cannam@62 39 public:
cannam@62 40 virtual StringPtr getProgramName() = 0;
cannam@62 41 // Get argv[0] as passed to main().
cannam@62 42
cannam@62 43 KJ_NORETURN(virtual void exit()) = 0;
cannam@62 44 // Indicates program completion. The program is considered successful unless `error()` was
cannam@62 45 // called. Typically this exits with _Exit(), meaning that the stack is not unwound, buffers
cannam@62 46 // are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that
cannam@62 47 // matter. However, an alternate context implementation e.g. for unit testing purposes could
cannam@62 48 // choose to throw an exception instead.
cannam@62 49 //
cannam@62 50 // At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if
cannam@62 51 // you lose data? However, it turns out that if you look at each common class of program, _Exit()
cannam@62 52 // is almost always preferable. Let's break it down:
cannam@62 53 //
cannam@62 54 // * Commands: A typical program you might run from the command line is single-threaded and
cannam@62 55 // exits quickly and deterministically. Commands often use buffered I/O and need to flush
cannam@62 56 // those buffers before exit. However, most of the work performed by destructors is not
cannam@62 57 // flushing buffers, but rather freeing up memory, placing objects into freelists, and closing
cannam@62 58 // file descriptors. All of this is irrelevant if the process is about to exit anyway, and
cannam@62 59 // for a command that runs quickly, time wasted freeing heap space may make a real difference
cannam@62 60 // in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what
cannam@62 61 // resources need to be flushed before exit, and easy to tell if they are not being flushed
cannam@62 62 // (because the command fails to produce the expected output). Therefore, it is reasonably
cannam@62 63 // easy for commands to explicitly ensure all output is flushed before exiting, and it is
cannam@62 64 // probably a good idea for them to do so anyway, because write failures should be detected
cannam@62 65 // and handled. For commands, a good strategy is to allocate any objects that require clean
cannam@62 66 // destruction on the stack, and allow them to go out of scope before the command exits.
cannam@62 67 // Meanwhile, any resources which do not need to be cleaned up should be allocated as members
cannam@62 68 // of the command's main class, whose destructor normally will not be called.
cannam@62 69 //
cannam@62 70 // * Interactive apps: Programs that interact with the user (whether they be graphical apps
cannam@62 71 // with windows or console-based apps like emacs) generally exit only when the user asks them
cannam@62 72 // to. Such applications may store large data structures in memory which need to be synced
cannam@62 73 // to disk, such as documents or user preferences. However, relying on stack unwind or global
cannam@62 74 // destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of
cannam@62 75 // all, it's 2013, and applications ought to be actively syncing changes to non-volatile
cannam@62 76 // storage the moment those changes are made. Applications can crash at any time and a crash
cannam@62 77 // should never lose data that is more than half a second old. Meanwhile, if a user actually
cannam@62 78 // does try to close an application while unsaved changes exist, the application UI should
cannam@62 79 // prompt the user to decide what to do. Such a UI mechanism is obviously too high level to
cannam@62 80 // be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here.
cannam@62 81 //
cannam@62 82 // * Servers: A good server is fault-tolerant, prepared for the possibility that at any time
cannam@62 83 // it could crash, the OS could decide to kill it off, or the machine it is running on could
cannam@62 84 // just die. So, using _Exit() should be no problem. In fact, servers generally never even
cannam@62 85 // call exit anyway; they are killed externally.
cannam@62 86 //
cannam@62 87 // * Batch jobs: A long-running batch job is something between a command and a server. It
cannam@62 88 // probably knows exactly what needs to be flushed before exiting, and it probably should be
cannam@62 89 // fault-tolerant.
cannam@62 90 //
cannam@62 91 // Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of
cannam@62 92 // _Exit() shouldn't be a problem anyway:
cannam@62 93 //
cannam@62 94 // * KJ style forbids global mutable state (singletons) in general and global constructors and
cannam@62 95 // destructors in particular. Therefore, everything that could possibly need cleanup either
cannam@62 96 // lives on the stack or is transitively owned by something living on the stack.
cannam@62 97 //
cannam@62 98 // * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you
cannam@62 99 // have resources that require cleanup before exit, make sure they are owned by stack frames
cannam@62 100 // beyond the one that eventually calls exit(). To be as safe as possible, don't place any
cannam@62 101 // state in your program's main class, and don't call exit() yourself. Then, runMainAndExit()
cannam@62 102 // will do it, and the only thing on the stack at that time will be your main class, which
cannam@62 103 // has no state anyway.
cannam@62 104 //
cannam@62 105 // TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is
cannam@62 106 // available for those who really think they need it. Unfortunately, it is not yet available
cannam@62 107 // on many platforms.
cannam@62 108
cannam@62 109 virtual void warning(StringPtr message) = 0;
cannam@62 110 // Print the given message to standard error. A newline is printed after the message if it
cannam@62 111 // doesn't already have one.
cannam@62 112
cannam@62 113 virtual void error(StringPtr message) = 0;
cannam@62 114 // Like `warning()`, but also sets a flag indicating that the process has failed, and that when
cannam@62 115 // it eventually exits it should indicate an error status.
cannam@62 116
cannam@62 117 KJ_NORETURN(virtual void exitError(StringPtr message)) = 0;
cannam@62 118 // Equivalent to `error(message)` followed by `exit()`.
cannam@62 119
cannam@62 120 KJ_NORETURN(virtual void exitInfo(StringPtr message)) = 0;
cannam@62 121 // Displays the given non-error message to the user and then calls `exit()`. This is used to
cannam@62 122 // implement things like --help.
cannam@62 123
cannam@62 124 virtual void increaseLoggingVerbosity() = 0;
cannam@62 125 // Increase the level of detail produced by the debug logging system. `MainBuilder` invokes
cannam@62 126 // this if the caller uses the -v flag.
cannam@62 127
cannam@62 128 // TODO(someday): Add interfaces representing standard OS resources like the filesystem, so that
cannam@62 129 // these things can be mocked out.
cannam@62 130 };
cannam@62 131
cannam@62 132 class TopLevelProcessContext final: public ProcessContext {
cannam@62 133 // A ProcessContext implementation appropriate for use at the actual entry point of a process
cannam@62 134 // (as opposed to when you are trying to call a program's main function from within some other
cannam@62 135 // program). This implementation writes errors to stderr, and its `exit()` method actually
cannam@62 136 // calls the C `quick_exit()` function.
cannam@62 137
cannam@62 138 public:
cannam@62 139 explicit TopLevelProcessContext(StringPtr programName);
cannam@62 140
cannam@62 141 struct CleanShutdownException { int exitCode; };
cannam@62 142 // If the environment variable KJ_CLEAN_SHUTDOWN is set, then exit() will actually throw this
cannam@62 143 // exception rather than exiting. `kj::runMain()` catches this exception and returns normally.
cannam@62 144 // This is useful primarily for testing purposes, to assist tools like memory leak checkers that
cannam@62 145 // are easily confused by quick_exit().
cannam@62 146
cannam@62 147 StringPtr getProgramName() override;
cannam@62 148 KJ_NORETURN(void exit() override);
cannam@62 149 void warning(StringPtr message) override;
cannam@62 150 void error(StringPtr message) override;
cannam@62 151 KJ_NORETURN(void exitError(StringPtr message) override);
cannam@62 152 KJ_NORETURN(void exitInfo(StringPtr message) override);
cannam@62 153 void increaseLoggingVerbosity() override;
cannam@62 154
cannam@62 155 private:
cannam@62 156 StringPtr programName;
cannam@62 157 bool cleanShutdown;
cannam@62 158 bool hadErrors = false;
cannam@62 159 };
cannam@62 160
cannam@62 161 typedef Function<void(StringPtr programName, ArrayPtr<const StringPtr> params)> MainFunc;
cannam@62 162
cannam@62 163 int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]);
cannam@62 164 // Runs the given main function and then exits using the given context. If an exception is thrown,
cannam@62 165 // this will catch it, report it via the context and exit with an error code.
cannam@62 166 //
cannam@62 167 // Normally this function does not return, because returning would probably lead to wasting time
cannam@62 168 // on cleanup when the process is just going to exit anyway. However, to facilitate memory leak
cannam@62 169 // checkers and other tools that require a clean shutdown to do their job, if the environment
cannam@62 170 // variable KJ_CLEAN_SHUTDOWN is set, the function will in fact return an exit code, which should
cannam@62 171 // then be returned from main().
cannam@62 172 //
cannam@62 173 // Most users will use the KJ_MAIN() macro rather than call this function directly.
cannam@62 174
cannam@62 175 #define KJ_MAIN(MainClass) \
cannam@62 176 int main(int argc, char* argv[]) { \
cannam@62 177 ::kj::TopLevelProcessContext context(argv[0]); \
cannam@62 178 MainClass mainObject(context); \
cannam@62 179 return ::kj::runMainAndExit(context, mainObject.getMain(), argc, argv); \
cannam@62 180 }
cannam@62 181 // Convenience macro for declaring a main function based on the given class. The class must have
cannam@62 182 // a constructor that accepts a ProcessContext& and a method getMain() which returns
cannam@62 183 // kj::MainFunc (probably building it using a MainBuilder).
cannam@62 184
cannam@62 185 class MainBuilder {
cannam@62 186 // Builds a main() function with nice argument parsing. As options and arguments are parsed,
cannam@62 187 // corresponding callbacks are called, so that you never have to write a massive switch()
cannam@62 188 // statement to interpret arguments. Additionally, this approach encourages you to write
cannam@62 189 // main classes that have a reasonable API that can be used as an alternative to their
cannam@62 190 // command-line interface.
cannam@62 191 //
cannam@62 192 // All StringPtrs passed to MainBuilder must remain valid until option parsing completes. The
cannam@62 193 // assumption is that these strings will all be literals, making this an easy requirement. If
cannam@62 194 // not, consider allocating them in an Arena.
cannam@62 195 //
cannam@62 196 // Some flags are automatically recognized by the main functions built by this class:
cannam@62 197 // --help: Prints help text and exits. The help text is constructed based on the
cannam@62 198 // information you provide to the builder as you define each flag.
cannam@62 199 // --verbose: Increase logging verbosity.
cannam@62 200 // --version: Print version information and exit.
cannam@62 201 //
cannam@62 202 // Example usage:
cannam@62 203 //
cannam@62 204 // class FooMain {
cannam@62 205 // public:
cannam@62 206 // FooMain(kj::ProcessContext& context): context(context) {}
cannam@62 207 //
cannam@62 208 // bool setAll() { all = true; return true; }
cannam@62 209 // // Enable the --all flag.
cannam@62 210 //
cannam@62 211 // kj::MainBuilder::Validity setOutput(kj::StringPtr name) {
cannam@62 212 // // Set the output file.
cannam@62 213 //
cannam@62 214 // if (name.endsWith(".foo")) {
cannam@62 215 // outputFile = name;
cannam@62 216 // return true;
cannam@62 217 // } else {
cannam@62 218 // return "Output file must have extension .foo.";
cannam@62 219 // }
cannam@62 220 // }
cannam@62 221 //
cannam@62 222 // kj::MainBuilder::Validity processInput(kj::StringPtr name) {
cannam@62 223 // // Process an input file.
cannam@62 224 //
cannam@62 225 // if (!exists(name)) {
cannam@62 226 // return kj::str(name, ": file not found");
cannam@62 227 // }
cannam@62 228 // // ... process the input file ...
cannam@62 229 // return true;
cannam@62 230 // }
cannam@62 231 //
cannam@62 232 // kj::MainFunc getMain() {
cannam@62 233 // return MainBuilder(context, "Foo Builder v1.5", "Reads <source>s and builds a Foo.")
cannam@62 234 // .addOption({'a', "all"}, KJ_BIND_METHOD(*this, setAll),
cannam@62 235 // "Frob all the widgets. Otherwise, only some widgets are frobbed.")
cannam@62 236 // .addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
cannam@62 237 // "<filename>", "Output to <filename>. Must be a .foo file.")
cannam@62 238 // .expectOneOrMoreArgs("<source>", KJ_BIND_METHOD(*this, processInput))
cannam@62 239 // .build();
cannam@62 240 // }
cannam@62 241 //
cannam@62 242 // private:
cannam@62 243 // bool all = false;
cannam@62 244 // kj::StringPtr outputFile;
cannam@62 245 // kj::ProcessContext& context;
cannam@62 246 // };
cannam@62 247
cannam@62 248 public:
cannam@62 249 MainBuilder(ProcessContext& context, StringPtr version,
cannam@62 250 StringPtr briefDescription, StringPtr extendedDescription = nullptr);
cannam@62 251 ~MainBuilder() noexcept(false);
cannam@62 252
cannam@62 253 class OptionName {
cannam@62 254 public:
cannam@62 255 OptionName() = default;
cannam@62 256 inline OptionName(char shortName): isLong(false), shortName(shortName) {}
cannam@62 257 inline OptionName(const char* longName): isLong(true), longName(longName) {}
cannam@62 258
cannam@62 259 private:
cannam@62 260 bool isLong;
cannam@62 261 union {
cannam@62 262 char shortName;
cannam@62 263 const char* longName;
cannam@62 264 };
cannam@62 265 friend class MainBuilder;
cannam@62 266 };
cannam@62 267
cannam@62 268 class Validity {
cannam@62 269 public:
cannam@62 270 inline Validity(bool valid) {
cannam@62 271 if (!valid) errorMessage = heapString("invalid argument");
cannam@62 272 }
cannam@62 273 inline Validity(const char* errorMessage)
cannam@62 274 : errorMessage(heapString(errorMessage)) {}
cannam@62 275 inline Validity(String&& errorMessage)
cannam@62 276 : errorMessage(kj::mv(errorMessage)) {}
cannam@62 277
cannam@62 278 inline const Maybe<String>& getError() const { return errorMessage; }
cannam@62 279 inline Maybe<String> releaseError() { return kj::mv(errorMessage); }
cannam@62 280
cannam@62 281 private:
cannam@62 282 Maybe<String> errorMessage;
cannam@62 283 friend class MainBuilder;
cannam@62 284 };
cannam@62 285
cannam@62 286 MainBuilder& addOption(std::initializer_list<OptionName> names, Function<Validity()> callback,
cannam@62 287 StringPtr helpText);
cannam@62 288 // Defines a new option (flag). `names` is a list of characters and strings that can be used to
cannam@62 289 // specify the option on the command line. Single-character names are used with "-" while string
cannam@62 290 // names are used with "--". `helpText` is a natural-language description of the flag.
cannam@62 291 //
cannam@62 292 // `callback` is called when the option is seen. Its return value indicates whether the option
cannam@62 293 // was accepted. If not, further option processing stops, and error is written, and the process
cannam@62 294 // exits.
cannam@62 295 //
cannam@62 296 // Example:
cannam@62 297 //
cannam@62 298 // builder.addOption({'a', "all"}, KJ_BIND_METHOD(*this, showAll), "Show all files.");
cannam@62 299 //
cannam@62 300 // This option could be specified in the following ways:
cannam@62 301 //
cannam@62 302 // -a
cannam@62 303 // --all
cannam@62 304 //
cannam@62 305 // Note that single-character option names can be combined into a single argument. For example,
cannam@62 306 // `-abcd` is equivalent to `-a -b -c -d`.
cannam@62 307 //
cannam@62 308 // The help text for this option would look like:
cannam@62 309 //
cannam@62 310 // -a, --all
cannam@62 311 // Show all files.
cannam@62 312 //
cannam@62 313 // Note that help text is automatically word-wrapped.
cannam@62 314
cannam@62 315 MainBuilder& addOptionWithArg(std::initializer_list<OptionName> names,
cannam@62 316 Function<Validity(StringPtr)> callback,
cannam@62 317 StringPtr argumentTitle, StringPtr helpText);
cannam@62 318 // Like `addOption()`, but adds an option which accepts an argument. `argumentTitle` is used in
cannam@62 319 // the help text. The argument text is passed to the callback.
cannam@62 320 //
cannam@62 321 // Example:
cannam@62 322 //
cannam@62 323 // builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
cannam@62 324 // "<filename>", "Output to <filename>.");
cannam@62 325 //
cannam@62 326 // This option could be specified with an argument of "foo" in the following ways:
cannam@62 327 //
cannam@62 328 // -ofoo
cannam@62 329 // -o foo
cannam@62 330 // --output=foo
cannam@62 331 // --output foo
cannam@62 332 //
cannam@62 333 // Note that single-character option names can be combined, but only the last option can have an
cannam@62 334 // argument, since the characters after the option letter are interpreted as the argument. E.g.
cannam@62 335 // `-abofoo` would be equivalent to `-a -b -o foo`.
cannam@62 336 //
cannam@62 337 // The help text for this option would look like:
cannam@62 338 //
cannam@62 339 // -o FILENAME, --output=FILENAME
cannam@62 340 // Output to FILENAME.
cannam@62 341
cannam@62 342 MainBuilder& addSubCommand(StringPtr name, Function<MainFunc()> getSubParser,
cannam@62 343 StringPtr briefHelpText);
cannam@62 344 // If exactly the given name is seen as an argument, invoke getSubParser() and then pass all
cannam@62 345 // remaining arguments to the parser it returns. This is useful for implementing commands which
cannam@62 346 // have lots of sub-commands, like "git" (which has sub-commands "checkout", "branch", "pull",
cannam@62 347 // etc.).
cannam@62 348 //
cannam@62 349 // `getSubParser` is only called if the command is seen. This avoids building main functions
cannam@62 350 // for commands that aren't used.
cannam@62 351 //
cannam@62 352 // `briefHelpText` should be brief enough to show immediately after the command name on a single
cannam@62 353 // line. It will not be wrapped. Users can use the built-in "help" command to get extended
cannam@62 354 // help on a particular command.
cannam@62 355
cannam@62 356 MainBuilder& expectArg(StringPtr title, Function<Validity(StringPtr)> callback);
cannam@62 357 MainBuilder& expectOptionalArg(StringPtr title, Function<Validity(StringPtr)> callback);
cannam@62 358 MainBuilder& expectZeroOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
cannam@62 359 MainBuilder& expectOneOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
cannam@62 360 // Set callbacks to handle arguments. `expectArg()` and `expectOptionalArg()` specify positional
cannam@62 361 // arguments with special handling, while `expect{Zero,One}OrMoreArgs()` specifies a handler for
cannam@62 362 // an argument list (the handler is called once for each argument in the list). `title`
cannam@62 363 // specifies how the argument should be represented in the usage text.
cannam@62 364 //
cannam@62 365 // All options callbacks are called before argument callbacks, regardless of their ordering on
cannam@62 366 // the command line. This matches GNU getopt's behavior of permuting non-flag arguments to the
cannam@62 367 // end of the argument list. Also matching getopt, the special option "--" indicates that the
cannam@62 368 // rest of the command line is all arguments, not options, even if they start with '-'.
cannam@62 369 //
cannam@62 370 // The interpretation of positional arguments is fairly flexible. The non-optional arguments can
cannam@62 371 // be expected at the beginning, end, or in the middle. If more arguments are specified than
cannam@62 372 // the number of non-optional args, they are assigned to the optional argument handlers in the
cannam@62 373 // order of registration.
cannam@62 374 //
cannam@62 375 // For example, say you called:
cannam@62 376 // builder.expectArg("<foo>", ...);
cannam@62 377 // builder.expectOptionalArg("<bar>", ...);
cannam@62 378 // builder.expectArg("<baz>", ...);
cannam@62 379 // builder.expectZeroOrMoreArgs("<qux>", ...);
cannam@62 380 // builder.expectArg("<corge>", ...);
cannam@62 381 //
cannam@62 382 // This command requires at least three arguments: foo, baz, and corge. If four arguments are
cannam@62 383 // given, the second is assigned to bar. If five or more arguments are specified, then the
cannam@62 384 // arguments between the third and last are assigned to qux. Note that it never makes sense
cannam@62 385 // to call `expect*OrMoreArgs()` more than once since only the first call would ever be used.
cannam@62 386 //
cannam@62 387 // In practice, you probably shouldn't create such complicated commands as in the above example.
cannam@62 388 // But, this flexibility seems necessary to support commands where the first argument is special
cannam@62 389 // as well as commands (like `cp`) where the last argument is special.
cannam@62 390
cannam@62 391 MainBuilder& callAfterParsing(Function<Validity()> callback);
cannam@62 392 // Call the given function after all arguments have been parsed.
cannam@62 393
cannam@62 394 MainFunc build();
cannam@62 395 // Build the "main" function, which simply parses the arguments. Once this returns, the
cannam@62 396 // `MainBuilder` is no longer valid.
cannam@62 397
cannam@62 398 private:
cannam@62 399 struct Impl;
cannam@62 400 Own<Impl> impl;
cannam@62 401
cannam@62 402 class MainImpl;
cannam@62 403 };
cannam@62 404
cannam@62 405 } // namespace kj
cannam@62 406
cannam@62 407 #endif // KJ_MAIN_H_