]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [section:pem Program Execution Monitor] |
2 | ||
3 | The components of a C++ program may report user-detected errors in several ways, such as via a return value or | |
4 | throwing an exception. System-detected errors such as dereferencing an invalid pointer are reported in other ways, | |
5 | totally operating system and compiler dependent. | |
6 | ||
7 | Yet many C++ programs, both production and test, must run in an environment where uniform reporting of errors is | |
8 | necessary. For example, converting otherwise uncaught exceptions to non-zero program return codes allows many | |
9 | command line, script, or batch environments to continue processing in a controlled manner. Even some | |
10 | ['GUI] environments benefit from the unification of errors into program return codes. | |
11 | ||
12 | ||
13 | The Boost.Test Library's *Program Execution Monitor* relieves users from messy error | |
14 | detection and reporting duties by providing a replacement function `main()` which calls a user-supplied `cpp_main()` | |
15 | function within a monitored environment. The supplied `main()` then uniformly detects and reports the occurrence of | |
16 | several types of errors, reducing them to a uniform return code which is returned to the host environment. | |
17 | ||
18 | Uniform error reporting is particularly useful for programs running unattended under control of scripts or batch | |
19 | files. Some operating systems pop up message boxes if an uncaught exception occurs, and this requires manual | |
20 | intervention. By converting such exceptions into non-zero program return codes, the library makes the program a | |
21 | better citizen. More uniform reporting of errors isn't a benefit to some programs, particularly programs always | |
22 | run by hand of a knowledgeable person. So the __PEM__ wouldn't be worth using in that environment. | |
23 | ||
24 | Uniform error reporting can be also useful in test environments such as the Boost | |
25 | regression tests. Be aware though in such case it might be preferable to use the | |
26 | __UTF__, because it allows one to use the | |
27 | [link boost_test.testing_tools testing tools] and generate more detailed | |
28 | error information. | |
29 | ||
30 | [section Usage] | |
31 | ||
32 | To facilitate uniform error reporting the __PEM__ supplies function `main()` as part if it's implementation. To use the | |
33 | __PEM__ instead of regular function `main` your program is required to supply a function `cpp_main()` with same signature. | |
34 | ||
35 | Here is the traditional ['Hello World] program implemented using the __PEM__: | |
36 | ||
37 | [bt_example example24..Hello World with the Program Execution Monitor..run-fail] | |
38 | ||
39 | It really is that simple - just change the name of your initial function from `main()` to `cpp_main()`. Do make sure | |
40 | the `argc` and `argv` parameters are specified (although you don't have to name them if you don't use them). | |
41 | ||
42 | The __PEM__ treats as errors: | |
43 | ||
44 | * Exceptions thrown from `cpp_main()` | |
45 | * Non-zero return from `cpp_main()` | |
46 | ||
47 | So what if some function had thrown a `std::runtime_error` with the message "big trouble" and it is not trapped by any | |
48 | catch clause? Like in a following example: | |
49 | ||
50 | [bt_example example25..Standard exception detection within the __PEM__..run-fail] | |
51 | ||
52 | [note Note that in both examples above we used [link boost_test.components.section_pem.section_pem_compilation.section_pem_full_include single-header variant] | |
53 | of the __PEM__. Alternatively the binaries may be built and linked with | |
54 | a [link boost_test.components.section_pem.section_pem_compilation.section_pem_standalone standalone library] (in case of static library we are not required to include any __PEM__ related headers). | |
55 | ] | |
56 | ||
57 | Let's consider an example where function `cpp_main()` had bubbled up a return code of 5: | |
58 | ||
59 | [bt_example example26..Error return code detection of the __PEM__..run-fail] | |
60 | ||
61 | The __PEM__ reports errors to both `std::cout` (details) and `std::cerr` (summary). Primary detailed error | |
62 | messages appear on standard output stream so that it is properly interlaced with other output, thus aiding error | |
63 | analysis. While the final error notification message appears on standard error stream. This increases the | |
64 | visibility of error notification if standard output and error streams are directed to different devices or files. | |
65 | ||
66 | The __PEM__'s supplied `main()` will return following result codes: | |
67 | ||
68 | * `boost::exit_success` - no errors | |
69 | * `boost::exit_failure` - non-zero and `non-boost::exit_success` return code from `cpp_main()` | |
70 | * `boost::exit_exception_failure` - `cpp_main()` throw an exception | |
71 | ||
72 | [endsect] [/ Usage] | |
73 | ||
74 | ||
75 | ||
76 | [/ #################################################################################### configuration] | |
77 | [section Runtime configuration] | |
78 | ||
79 | There are two aspects of the __PEM__ behavior that you can customize at runtime. Customization is performed using | |
80 | environment variables. | |
81 | ||
82 | [table:id_pem_env The __PEM__ configuration environment variables | |
83 | [ | |
84 | [Flag] | |
85 | [Usage] | |
86 | ] | |
87 | [ | |
88 | [`BOOST_TEST_CATCH_SYSTEM_ERRORS`] | |
89 | [allows customizing behavior of the __PEM__ in regards of catching system errors. For more details about the | |
90 | meaning of this option see the [classref boost::execution_monitor execution_monitor] class. If you | |
91 | want to prevent the __PEM__ from catching system exception, set the value of this | |
92 | variable to "no". The default value is "yes".] | |
93 | ] | |
94 | [ | |
95 | [`BOOST_PRG_MON_CONFIRM`] | |
96 | [allows avoiding success confirmation message. Some users prefer to see a confirmation message in case if program | |
97 | successfully executed. While others don't like the clutter or any output is prohibited by organization standards. | |
98 | To avoid the message set the value of this variable to "no". The default value is "yes".] | |
99 | ] | |
100 | ||
101 | ] | |
102 | ||
103 | [note `BOOST_TEST_CATCH_SYSTEM_ERRORS` is similar to the __UTF__'s | |
104 | [link boost_test.utf_reference.rt_param_reference.catch_system `catch_system_error`] command line parameter.] | |
105 | ||
106 | [endsect] [/ configuration] | |
107 | ||
108 | [/ #################################################################################### implementation] | |
109 | [#ref_pem_implementation][section Implementation] | |
110 | ||
111 | To monitor execution of user supplied function `cpp_main()` the __PEM__ relies on the Boost.Test's | |
112 | [link boost_test.components.execution_monitor Execution Monitor]. Also the __PEM__ supplies the function `main()` to facilitate | |
113 | uniform error reporting. Following files constitute the __PEM__ implementation: | |
114 | ||
115 | ||
116 | [table:pem_implementation_file __PEM__ implementation files | |
117 | ||
118 | [ | |
119 | [File name] | |
120 | [Content] | |
121 | ] | |
122 | [ | |
123 | [`boost/test/impl/execution_monitor.ipp`] | |
124 | [provides __EM__ implementation for all supported configurations] | |
125 | ] | |
126 | [ | |
127 | [`boost/test/impl/cpp_main.ipp`] | |
128 | [supplies function `main()` for static library build] | |
129 | ] | |
130 | [ | |
131 | [`boost/test/included/prg_exec_monitor.hpp`] | |
132 | [combines all implementation files into single header to be use as inlined version of component] | |
133 | ] | |
134 | [ | |
135 | [`boost/test/prg_exec_monitor.hpp`] | |
136 | [contains definitions for `main()` function for dynamic library build and pragmas for auto-linking feature support] | |
137 | ] | |
138 | ] | |
139 | ||
140 | The __PEM__ implementation wraps several system headers and is intended to be used as standalone library. While there | |
141 | exist an alternative variant to [link ref_pem_direct_include include the whole implementation | |
142 | directly] into your program, for the long term usage the preferable solution is to | |
143 | [link ref_pem_stanlone build library once] and reuse it. | |
144 | ||
145 | ||
146 | [endsect] [/implementation] | |
147 | ||
148 | [section:section_pem_compilation Compilation] | |
149 | ||
150 | In comparison with many other boost libraries, which are completely implemented in header files, compilation and | |
151 | linking with the __PEM__ may require additional steps. The __PEM__ presents you with options to either | |
152 | ||
153 | # built and link with a [link ref_pem_stanlone standalone library] or | |
154 | # include the implementation [link ref_pem_direct_include directly] into your program. | |
155 | ||
156 | If you opt to use the library the __PEM__ header implements the | |
157 | [*auto-linking support] and following flags can be used to configure | |
158 | compilation of the __PEM__ library and your program: | |
159 | ||
160 | [table | |
161 | [ | |
162 | [Variable] | |
163 | [Usage] | |
164 | ] | |
165 | [ | |
166 | [__BOOST_TEST_DYN_LINK__] | |
167 | [Define this flag to build/use dynamic library] | |
168 | ] | |
169 | [ | |
170 | [__BOOST_TEST_NO_LIB__] | |
171 | [Define this flag to prevent auto-linking] | |
172 | ] | |
173 | ] | |
174 | ||
175 | [#ref_pem_stanlone][section:section_pem_standalone Standalone library compilation] | |
176 | ||
177 | If you opted to link your program with the standalone library, you need to build it first. To build a standalone | |
178 | library all C++ files (.cpp), that constitute __PEM__ [link ref_pem_implementation implementation] need to be | |
179 | listed as source files in your makefile [footnote There are varieties of make systems that can be used. To name | |
180 | a few: ['GNU] make (and other make clones) and build systems integrated into ['IDE]s | |
181 | (for example ['Microsoft Visual Studio]). The Boost preferred solution is Boost.Build system that is based on top of | |
182 | `bjam` tool. Make systems require some kind of configuration file that lists all files that constitute the library | |
183 | and all build options. For example the makefile that is used by make, or the Microsoft Visual Studio project file, | |
184 | Jamfile is used by Boost.Build. For the sake of simplicity let's call this file the makefile.]. | |
185 | ||
186 | ||
187 | The makefile for use with Boost.Build system is supplied in | |
188 | ||
189 | `` | |
190 | libs/test/build | |
191 | `` | |
192 | ||
193 | directory. The __PEM__ can be built as either [link ref_pem_static static] or [link ref_pem_dynamic dynamic] library. | |
194 | ||
195 | ||
196 | ||
197 | [#ref_pem_static][section:section_pem_compilation_static Static library compilation] | |
198 | ||
199 | There are no additional build defines or options required to build static library. Using Boost.Build system you | |
200 | can build the static library with a following command from `libs/test/build` directory: | |
201 | ||
202 | `` | |
203 | bjam -sTOOLS=<your-tool-name> -sBUILD=boost_prg_exec_monitor | |
204 | `` | |
205 | ||
206 | Also on Windows you can use the Microsoft Visual Studio .NET project file provided. | |
207 | ||
208 | [endsect] [/ static compilation] | |
209 | ||
210 | [#ref_pem_dynamic][section:section_pem_compilation_dynamic Dynamic library compilation] | |
211 | ||
212 | To build the dynamic library [footnote What is meant by the term dynamic library is a ['dynamically | |
213 | loaded library], alternatively called a ['shared library].] you | |
214 | need to add __BOOST_TEST_DYN_LINK__ to the list of macro definitions in the | |
215 | ``libs/test/build`` directory: | |
216 | ||
217 | `` | |
218 | bjam -sTOOLS=<your-tool-name> -sBUILD=boost_prg_exec_monitor | |
219 | `` | |
220 | ||
221 | Also on Windows you can use the Microsoft Visual Studio .NET project file provided. | |
222 | ||
223 | [caution | |
224 | For your program to successfully link with the dynamic library the flag | |
225 | __BOOST_TEST_DYN_LINK__ needs to be defined both during dynamic library | |
226 | build and during your program compilation. | |
227 | ] | |
228 | ||
229 | ||
230 | [endsect] [/ dynamic compilation] | |
231 | [endsect] [/ standalone lib compilation] | |
232 | ||
233 | [#ref_pem_auto_link][section Support of the auto-linking feature] | |
234 | ||
235 | ||
236 | For the Microsoft family of compilers the __PEM__ provides an ability to automatically select proper library name | |
237 | and add it to the list of objects to be linked with. To employ this feature you required to include either header | |
238 | ||
239 | `` | |
240 | #include <boost/test/prg_exec_monitor.hpp> | |
241 | `` | |
242 | or header | |
243 | ||
244 | `` | |
245 | #include <boost/test/included/prg_exec_monitor.hpp> | |
246 | `` | |
247 | ||
248 | By default the feature is enabled. To disable it you have to define the flag __BOOST_TEST_NO_LIB__. | |
249 | ||
250 | ||
251 | [endsect] [/ autolink] | |
252 | ||
253 | [#ref_pem_direct_include][section:section_pem_full_include Including the __PEM__ directly into your program] | |
254 | ||
255 | If you prefer to avoid the standalone library compilation you have two alternative usage variants: you can either | |
256 | include all files that constitute the static library in your program's makefile or include them as a part of | |
257 | your program's source file. To facilitate the later variant the __PEM__ implementation presents the header | |
258 | `` | |
259 | #include <boost/test/included/prg_exec_monitor.hpp> | |
260 | `` | |
261 | ||
262 | In both variants neither __BOOST_TEST_DYN_LINK__ nor __BOOST_TEST_NO_LIB__ are applicable. This solution may not be the best choice | |
263 | in a long run, since it requires the __PEM__ sources recompilation for every program you use it with. | |
264 | ||
265 | [endsect] [/ direct include] | |
266 | ||
267 | ||
268 | [endsect] [/compilation] | |
269 | ||
270 | ||
271 | ||
272 | [endsect] [/program execution monitor] |