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