1 Wrapper binary implementation {#page_wrapperbinary}
2 =============================
4 This page mainly describes the implementation of the `gmx` wrapper binary.
5 Many of the details are not visible to most of the code, but this documentation
6 is included as part of the library API documentation to make it easier to
7 understand the overall implementation without reading extensive documentation.
10 ======================
12 The %main() method for the wrapper binary is implemented in
13 `src/programs/gmx.cpp`. This is a very simple code that does these basic
15 1. Initializes \Gromacs using gmx::initForCommandLine()
16 (see \ref page_usinglibrary).
17 2. Creates a gmx::CommandLineModuleManager instance for the wrapper binary.
18 3. Calls various methods to add modules to the manager and initialize it
19 otherwise. Many of the pre-5.0 binaries are added from
20 `src/programs/legacymodules.cpp`. New C++ tools are added from
21 `src/gromacs/trajectoryanalysis/modules.cpp`.
22 4. Passes control to the manager (see below).
23 5. On successful return, deinitializes \Gromacs and returns the exit code from
25 The %main() method also catches all exceptions, and if one is caught, prints an
26 error message and terminates the program cleanly.
31 The core of the wrapper binary is the gmx::CommandLineModuleManager::run()
33 1. Checks whether the binary is invoked through a symlink. If it is, it
34 searches the registered modules for names matching the name of the symlink
35 (with certain prefixes in the symlink name ignored). If a match is found,
36 it continues as if the command was invoked as `gmx` _module_ `...`, where
37 _module_ is the name of the found module and `...` are the rest of the
39 2. Parses the command line arguments before the module name as arguments to
40 the wrapper binary. Some arguments such as `-h` and `-version` cause rest
41 of the command (the module name and all that follows) to be ignored.
42 3. If a module is specified, also checks the command line arguments after the
43 module name for the options understood by the wrapper binary, such as `-h`
44 and `-version` (see below for details of how `-h` works). Any such options
45 are handled by the manager and removed from the command line for further
47 4. Print the startup header (contents of which can be controlled by the
48 command line options).
49 5. If a command line option requests termination after the startup header
50 (such as `-version`), return.
51 6. Passes control to the selected module. If there is no module specified,
52 the help module is invoked (see below).
53 7. Print a quote at the end, and return the exit code from the module.
58 To handle the `gmx help ...` command, as well as for `gmx -h` and for
59 `gmx` _module_ `-h`, the command line manager internally creates a module that
60 handles the `help` command. All command lines containing the `-h`, as well as
61 invocation of `gmx` without any arguments, are translated to corresponding
62 `gmx help` commands. For example, `gmx` _module_ `-h` is handled exactly like
63 `gmx help` _module_. Note that if `-h` is specified for a module, the command
64 line manager throws away all the other arguments before passing control to the
67 After the above translations, the internal help module handles all the help
68 output. All the help is organized into a hierarchy of gmx::HelpTopicInterface
69 instances. The help module internally creates a root help topic that is
70 printed with `gmx help`. If there are additional words after the `gmx help`
71 command, then those are taken to specify the topic to show in the hierarchy.
73 gmx::CommandLineModuleManager internally creates a help topic for each added
74 module. These topics are shown when `gmx help` _module_ is invoked.
75 They forward the request to the actual module (to
76 gmx::CommandLineModuleInterface::writeHelp()).
78 In addition to the topics created internally, gmx::CommandLineModuleManager
79 provides methods to add additional help topics. Currently, this is used to
80 expose some reference material for the selections (the same content that is
81 accessible using `help` in the selection prompt).
83 Help export for other formats
84 -----------------------------
86 The build system provides two targets, `make man` and `make html`, to generate
87 man pages and online HTML help for the commands. These targets are run
88 automatically as part of `make` if `GMX_BUILD_HELP=ON` is set in CMake.
89 Otherwise, they can be run manually. Internally, these execute
90 `gmx help -export` _format_, which triggers special handling in the internal
93 If this option is set, the help module loops through all the modules in the
94 binary, writing help for each into a separate file. The help module writes
95 common headers and footers, and asks the actual module to write the
96 module-specific content (with gmx::CommandLineModuleInterface::writeHelp(),
97 using a different help context than for console output).
99 Additionally, a list of all the modules is generated (`gromacs.7` for man
100 pages, and alphabetical and by-topic lists for the HTML pages).
102 Part of the functionality depends on template files and other data files that
103 the help module reads from `share/man/` and `share/html/` and uses to generate
106 Part of the HTML help is stored as partial HTML files under `share/html/`.
107 To produce the full HTML pages, the `gmx help -export html` command creates
108 `header.html` from a `header.html.in` template file. This file is used by a
109 separate CMake script that is run by `make html` to add headers and footers to
110 these partial HTML files.
111 The final HTML help is produced in `share/html/final/`.
113 Handling C %main() functions
114 ----------------------------
116 Many pre-5.0 modules are still implemented as a function with a C %main()
117 signature. All these binaries call parse_common_args() as more or less the
118 first thing in their processing. In order to implement the above approach, the
119 module manager internally creates a command line module for these (in
120 gmx::CommandLineModuleManager::addModuleCMain()). The created module
121 collaborates with parse_common_args() to achieve the same functionality as for
124 Running the module simply executes the provided %main() method.
125 Help writing is more complex, as it requires the help context to be passed from
126 the module to parse_common_args(). This is handled using a global instance of
127 the context (see gmx::GlobalCommandLineHelpContext). This context is set in
128 the module, and if parse_common_args() detects it, it prints out the help and
129 returns `false` to indicate to the caller that it should immediately return.