X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=CONTRIBUTING.adoc;h=d166238501f96a65f532fcc9d6bcc34afa93beed;hp=be9688a313beeb2c256c066a9ae25cd8c132a374;hb=HEAD;hpb=d9c39b0a4ad9517178899334c0ca89fd20901609 diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index be9688a3..171fcb14 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -1,30 +1,34 @@ // Render with Asciidoctor -= Babeltrace contributor's guide += Babeltrace{nbsp}2 contributor's guide Jérémie Galarneau, Philippe Proulx -v0.2, 19 June 2019 -:toc: -:toclevels: 5 - +22 February 2024 +:toc: left +:toclevels: 3 +:icons: font +:nofooter: +:bt2: Babeltrace{nbsp}2 +:c-cpp: C/{cpp} +:cpp11: {cpp}11 +:fmt: pass:[{fmt}] This is a partial contributor's guide for the -http://diamon.org/babeltrace[Babeltrace] project. If you have any +https://babeltrace.org[{bt2}] project. If you have any questions that are not answered by this guide, please post them on https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev[Babeltrace's mailing list]. - -== Babeltrace library +== {bt2} library === Object reference counting and lifetime -This section covers the rationale behind the design of Babeltrace's -object lifetime management. This applies to the Babeltrace library, as +This section covers the rationale behind the design of {bt2}'s +object lifetime management. This applies to the {bt2} library, as well as to the CTF writer library (although the public reference counting functions are not named the same way). -Starting from Babeltrace 2.0, all publicly exposed objects inherit a -common base: `bt_object`. This base provides a number of facilities to +Starting from Babeltrace{nbsp}2.0, all publicly exposed objects inherit +a common base: `bt_object`. This base provides a number of facilities to all objects, chief amongst which are lifetime management functions. The lifetime of some public objects is managed by reference counting. In @@ -32,17 +36,16 @@ this case, the API offers the `+bt_*_get_ref()+` and `+bt_*_put_ref()+` functions which respectively increment and decrement an object's reference count. -As far as lifetime management in concerned, Babeltrace makes a clear +As far as lifetime management in concerned, {bt2} makes a clear distinction between regular objects, which have a single parent, and root objects, which don't. - ==== The problem Let us consider a problematic case to illustrate the need for this distinction. -A user of the Babeltrace library creates a trace class, which _has_ a +A user of the {bt2} library creates a trace class, which _has_ a stream class (the class of a stream) and that stream class, in turn, _has_ an event class (the class of an event). @@ -72,10 +75,9 @@ never reach zero. Nonetheless, the API must offer the guarantee that holding a node to any node of the graph keeps all other reachable nodes alive. - ==== The solution -The scheme employed in Babeltrace to break this cycle consists in the +The scheme employed in {bt2} to break this cycle consists in the "children" holding _reverse component references_ to their parents. That is, in the context of the trace IR, that event classes hold a reference to their parent stream class and stream classes hold a reference to @@ -114,7 +116,6 @@ At that point, the child can be thought of as having converted its weak reference to its parent into a regular reference. That is why this reference is referred to as a _claiming_ aggregation reference. - ==== Caveats This scheme imposes a number of strict rules defining the relation @@ -124,7 +125,6 @@ between objects: * Objects, beside the root, are only retrievable from their direct parent or children. - ==== Example The initial situation is rather simple: **User{nbsp}A** is holding a @@ -237,7 +237,7 @@ image::doc/contributing-images/bt-ref13.png[] Logging is a great instrument for a developer to be able to collect information about a running software. -Babeltrace is a complex software with many layers. When a Babeltrace +{bt2} is a complex software with many layers. When a {bt2} graph fails to run, what caused the failure? It could be caused by any component, any message iterator, and any deeply nested validation of a CTF IR object (within the `ctf` plugin), for example. With the @@ -246,13 +246,12 @@ can find the cause of a bug faster. While <> when placing _DEBUG_ to _FATAL_ logging statements, you should liberally instrument your -Babeltrace module with _TRACE_ logging statements to help future you +{bt2} module with _TRACE_ logging statements to help future you and other developers understand what's happening at run time. - === Logging API -The Babeltrace logging API is internal: it is not exposed to the users +The {bt2} logging API is internal: it is not exposed to the users of the library; only to their developers. The only thing that a library user can control is the current log level of the library itself with `bt_logging_set_global_level()` and the initial library's log level with @@ -260,7 +259,7 @@ the `LIBBABELTRACE2_INIT_LOG_LEVEL` environment variable. This API is based on https://github.com/wonder-mice/zf_log[zf_log], a lightweight, yet featureful, MIT-licensed core logging library for C and -pass:[C++]. The zf_log source files were modified to have the `BT_` and +{cpp}. The zf_log source files were modified to have the `BT_` and `bt_` prefixes, and other small changes, like color support and using the project's `BT_DEBUG_MODE` definition instead of the standard `NDEBUG`. @@ -268,7 +267,6 @@ the project's `BT_DEBUG_MODE` definition instead of the standard The logging functions are implemented in the logging convenience library (`src/logging` directory). - [[logging-headers]] ==== Headers @@ -279,7 +277,7 @@ The logging API headers are: libbabeltrace2's current log level. `"logging/log.h"`:: - Internal, generic logging API which you can use in any Babeltrace + Internal, generic logging API which you can use in any {bt2} module. This is the translation of `zf_log.h`. + This header offers the <>. This header offers the <>. - [[log-levels]] ==== Log levels @@ -380,9 +377,9 @@ $ BABELTRACE_MINIMAL_LOG_LEVEL=INFO ./configure + The default build-time log level is `DEBUG`. For optimal performance, set it to `INFO`, which effectively disables all fast path logging in -all the Babeltrace modules. You can't set it to `WARNING`, `ERROR`, +all the {bt2} modules. You can't set it to `WARNING`, `ERROR`, `FATAL`, or `NONE` because the impact on performance is minuscule -starting from the _INFO_ log level anyway and we want any Babeltrace +starting from the _INFO_ log level anyway and we want any {bt2} build to always be able to print _INFO_-level logs. + The library's public API provides `bt_logging_get_minimal_level()` to @@ -443,7 +440,6 @@ level, for example: + [source,c] ---- -BT_HIDDEN char *bt_common_get_home_plugin_path(int log_level); ---- + @@ -461,11 +457,10 @@ Otherwise, just pass `BT_LOG_NONE`: path = bt_common_get_home_plugin_path(BT_LOG_NONE); ---- - [[gen-logging-statements]] ==== Generic logging statement macros -The Babeltrace logging statement macros work just like `printf()` +The {bt2} logging statement macros work just like `printf()` (except the `+BT_LOG*_STR()+` ones) and contain their <> (short name) in their name. @@ -474,9 +469,9 @@ Each of the following macros evaluate the <> expression (as defined by `BT_LOG_OUTPUT_LEVEL`) to log conditionally. -See <> and <> to learn how to be able to use the following macros. +See <> and +<> to learn how to be able to use the +following macros. `+BT_LOGT("format string", ...)+`:: Generic trace logging statement. @@ -550,16 +545,15 @@ file (generic)>> to learn how to be able to use the following macros. `+BT_LOGF_ERRNO("initial message", "format string", ...)+`:: Generic `errno` string fatal logging statement. - [[lib-logging-statements]] ==== Library-specific logging statement macros -The Babeltrace library contains an internal logging API based on the -generic logging framework. You can use it to log known Babeltrace +The {bt2} library contains an internal logging API based on the +generic logging framework. You can use it to log known {bt2} objects without having to manually log each member. -See <> -and <> to +See <> +and <> to learn how to be able to use the following macros. The library logging statement macros are named `+BT_LIB_LOG*()+` instead @@ -591,10 +585,6 @@ of `+BT_LOG*()+`: Library error logging statement, and unconditional error cause appending. -`+BT_LIB_LOGF_APPEND_CAUSE("format string", ...)+`:: - Library fatal logging statement, and unconditional error cause - appending. - The macros above accept the typical `printf()` conversion specifiers with the following limitations: @@ -606,7 +596,7 @@ with the following limitations: except for `PRId64`, `PRIu64`, `PRIx64`, `PRIX64`, `PRIo64`, and `PRIi64`. -The Babeltrace library custom conversion specifier is accepted. Its +The {bt2} library custom conversion specifier is accepted. Its syntax is either `%!u` to format a UUID (`bt_uuid` type), or: . Introductory `%!` sequence. @@ -689,6 +679,10 @@ The available format specifiers are: |Message |`+const struct bt_message *+` +|`I` +|Message iterator class +|`struct bt_message_iterator_class *` + |`i` |Message iterator |`struct bt_message_iterator *` @@ -758,23 +752,21 @@ Example with a custom prefix: BT_LIB_LOGI("Some message: %![ec-a-]e, %![ec-b-]+e", ec_a, ec_b); ---- -It is safe to pass `NULL` as any Babeltrace object parameter: the macros +It is safe to pass `NULL` as any {bt2} object parameter: the macros only print its null address. WARNING: Build-time `printf()` format checks are disabled for the `+BT_LIB_LOG*()+` macros because there are custom conversion specifiers, so make sure to test your logging statements. - [[comp-logging-statements]] ==== Component-specific logging statement macros There are available logging macros for components. They prepend a prefix including the component's name to the logging message. -See <> and <> to learn how to be able to use the +See <> and +<> to learn how to be able to use the following macros. The component logging statement macros are named `+BT_COMP_LOG*()+` @@ -852,7 +844,6 @@ instead of `+BT_LOG*()+`: `+BT_COMP_LOGF_MEM(data_ptr, data_size, "format string", ...)+`:: Component memory fatal logging statement. - ==== Conditional logging `+BT_LOG_IF(cond, statement)+`:: @@ -943,13 +934,12 @@ Or even this: BT_LOGD("Bla bla: number=%d", get_number_of_event_classes_with_property_x(...)); ---- - === Guides [[logging-instrument-c-file-gen]] -==== Instrument a C source file (generic) +==== Instrument a {c-cpp} source file (generic) -To instrument a C source file (`.c`): +To instrument a {c-cpp} source file (`.c`/`.cpp`): . At the top of the file, before the first `#include` line (if any), define your file's <> name: @@ -996,12 +986,11 @@ Examples: . In the file, instrument your code with the <>. - [[logging-instrument-h-file-gen]] -==== Instrument a C header file (generic) +==== Instrument a {c-cpp} header file (generic) -To instrument a C header file (`.h`), if you have `static inline` -functions in it: +To instrument a {c-cpp} header file (`.h`/`.hpp`), if you have +`static inline` functions in it: . Do not include `"logging/log.h"`! @@ -1032,8 +1021,8 @@ int some_function(int x) } ---- + -The C source files which include this header file determine if logging -is enabled or not for them, and if so, what is their +The {c-cpp} source files which include this header file determine if +logging is enabled or not for them, and if so, what is their <> and <> expression. @@ -1050,11 +1039,10 @@ log level>> expression. Then, in the file, instrument your code with the <>. - [[logging-instrument-c-file-lib]] -==== Instrument a library C source file +==== Instrument a library {c-cpp} source file -To instrument a library C source file (`.c`): +To instrument a library {c-cpp} source file (`.c`/`.cpp`): . At the top of the file, before the first `#include` line (if any), define your file's <> name (this @@ -1078,12 +1066,11 @@ To instrument a library C source file (`.c`): <> or with the <>. - [[logging-instrument-h-file-lib]] -==== Instrument a library C header file +==== Instrument a library {c-cpp} header file -To instrument a library C header file (`.h`), if you have `static -inline` functions in it: +To instrument a library {c-cpp} header file (`.h`/`.hpp`), if you have +`static inline` functions in it: . Do not include `"lib/logging.h"`! @@ -1101,11 +1088,10 @@ inline` functions in it: <> or with the <>. - [[logging-instrument-c-file-compcls]] -==== Instrument a component class C source file +==== Instrument a component class {c-cpp} source file -To instrument a component class C source file (`.c`): +To instrument a component class {c-cpp} source file (`.c`/`.cpp`): . At the top of the file, before the first `#include` line (if any), define your file's <> name (this tag @@ -1162,7 +1148,6 @@ struct my_comp { /* ... */ }; -BT_HIDDEN bt_self_component_status my_comp_init( bt_self_component_source *self_comp_src, bt_value *params, void *init_method_data) @@ -1182,12 +1167,11 @@ bt_self_component_status my_comp_init( . In the file, instrument your code with the <>. - [[logging-instrument-h-file-compcls]] -==== Instrument a component class C header file +==== Instrument a component class {c-cpp} header file -To instrument a component class C header file (`.h`), if you have -`static inline` functions in it: +To instrument a component class {c-cpp} header file (`.h`/`.hpp`), if +you have `static inline` functions in it: . Do not include `"logging/comp-logging.h"`! @@ -1204,20 +1188,19 @@ To instrument a component class C header file (`.h`), if you have . In the file, instrument your code with the <>. - [[choose-a-logging-tag]] ==== Choose a logging tag -Each logging-enabled C source file must define `BT_LOG_TAG` to a logging -tag. A logging tag is a namespace to identify the logging messages of -this specific source file. +Each logging-enabled {c-cpp} source file must define `BT_LOG_TAG` to a +logging tag. A logging tag is a namespace to identify the logging +messages of this specific source file. In general, a logging tag name _must_ be only uppercase letters, digits, and the `-`, `.`, and `/` characters. Use `/` to show the subsystem to source file hierarchy. -For the Babeltrace library, start with `LIB/`. +For the {bt2} library, start with `LIB/`. For the CTF writer library, start with `CTF-WRITER/`. @@ -1253,7 +1236,6 @@ With: `__FILE__`:: Additional information to specify the source file name or module. - [[choose-a-log-level]] ==== Choose a log level @@ -1340,7 +1322,7 @@ Very little: always enabled. |_DEBUG_ | -Something that only Babeltrace developers would be interested into, +Something that only {bt2} developers would be interested into, which can occur on the fast path, but not more often than once per message. @@ -1386,7 +1368,6 @@ check if the name/key exists in the object. In this case, use the _TRACE_ level (or do not log at all). -- - [[message]] ==== Write an appropriate message @@ -1453,7 +1434,6 @@ Prefer the following suffixes in field names: |`-name` |Object's name |`\"%s\"` |=== - === Output The log is printed to the standard error stream. A log line contains the @@ -1461,7 +1441,7 @@ time, the process and thread IDs, the <>, the <>, the source's function name, file name and line number, and the <>. -When Babeltrace supports terminal color codes (depends on the +When {bt2} supports terminal color codes (depends on the `BABELTRACE_TERM_COLOR` environment variable's value and what the standard output and error streams are plugged into), _INFO_-level lines are blue, _WARNING_-level lines are yellow, and _ERROR_-level and @@ -1481,7 +1461,6 @@ generates: $ babeltrace2 --log-level=D /path/to/trace |& ag 'D FIELD-CLASS' ---- - == Valgrind To use Valgrind on an application (for example, the CLI or a test) which @@ -1489,8 +1468,7 @@ loads libbabeltrace2, use: ---- $ G_SLICE=always-malloc G_DEBUG=gc-friendly PYTHONMALLOC=malloc \ - LIBBABELTRACE2_NO_DLCLOSE=1 valgrind --leak-check=full \ - --suppressions=/path/to/babeltrace/extras/valgrind/popt.supp app + LIBBABELTRACE2_NO_DLCLOSE=1 valgrind --leak-check=full app ---- `G_SLICE=always-malloc` and `G_DEBUG=gc-friendly` is for GLib and @@ -1507,34 +1485,32 @@ backtrace when Valgrind shows errors. [[test-env]] === Environment -`tests/utils/utils.sh` sets the environment variables for any Babeltrace -test script. +Running `make check` in the build directory (regardless of whether the build is +in-tree or out-of-tree) automatically sets up the appropriate environment for +tests to run in, so nothing more is needed. + +If building in-tree, you can run single tests from the tree directly: -`utils.sh` only needs to know the path to the `tests` directory within -the source and the build directories. By default, `utils.sh` assumes the -build is in tree, that is, you ran `./configure` from the source's root -directory, and sets the `BT_TESTS_SRCDIR` and `BT_TESTS_BUILDDIR` -environment variables accordingly. You can override those variables, for -example if you build out of tree. +---- +$ ./tests/plugins/sink.text.pretty/test-enum.sh +---- -All test scripts eventually do something like this to source `utils.sh`, -according to where they are located relative to the `tests` directory: +If building out-of-tree, you can get the appropriate environment by sourcing +the `tests/utils/env.sh` file residing in the build directory against which you +want to run tests. -[source,bash] ---- -if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then - UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh" -else - UTILSSH="$(dirname "$0")/../utils/utils.sh" -fi +$ source /path/to/my/build/tests/utils/env.sh +$ ./tests/plugins/sink.text.pretty/test-enum.sh ---- ==== Python -You can use the `tests/utils/run_python_bt2` script to run any command -within an environment making the build's `bt2` Python package available. +You can use the `tests/utils/run-in-py-env.sh` script to run any command +within an environment making the build's `bt2` Python package available, +as well as the testing utility Python modules. -`run_python_bt2` uses <> which needs to know the +`run-in-py-env.sh` uses <> which needs to know the build directory, so make sure you set the `BT_TESTS_BUILDDIR` environment variable correctly _if you build out of tree_, for example: @@ -1543,10 +1519,10 @@ $ export BT_TESTS_BUILDDIR=/path/to/build/babeltrace/tests ---- You can run any command which needs the `bt2` Python package through -`run_python_bt2`, for example: +`run-in-py-env.sh`, for example: ---- -$ ./tests/utils/run_python_bt2 ipython3 +$ ./tests/utils/run-in-py-env.sh ipython3 ---- === Report format @@ -1564,16 +1540,14 @@ function. * Print to the standard error. - === Python bindings The `bt2` Python package tests are located in `tests/bindings/python/bt2`. - ==== Python test runner -`tests/utils/python/testrunner.py` is Babeltrace's Python test runner +`tests/utils/python/testrunner.py` is {bt2}'s Python test runner which loads Python files containing unit tests, finds all the test cases, and runs the tests, producing a TAP report. @@ -1587,7 +1561,6 @@ By default, the test runner reports failing tests (TAP's `not{nbsp}ok` line), but continues to run other tests. You can use the `--failfast` option to make the test runner fail as soon as a test fails. - ==== Guides To run all the `bt2` Python package tests: @@ -1595,13 +1568,13 @@ To run all the `bt2` Python package tests: * Run: + ---- -$ ./tests/utils/run_python_bt2 ./tests/bindings/python/bt2/test_python_bt2 +$ ./tests/utils/run-in-py-env.sh ./tests/bindings/python/bt2/test-python-bt2.sh ---- + or: + ---- -$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \ +$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \ ./tests/bindings/python/bt2/ -p '*.py' ---- @@ -1611,7 +1584,7 @@ To run **all the tests** in a test module (for example, * Run: + ---- -$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \ +$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \ ./tests/bindings/python/bt2 -t test_value ---- @@ -1621,7 +1594,7 @@ To run a **specific test case** (for example, `RealValueTestCase` within * Run: + ---- -$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \ +$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \ ./tests/bindings/python/bt2/ -t test_value.RealValueTestCase ---- @@ -1631,6 +1604,702 @@ To run a **specific test** (for example, * Run: + ---- -$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \ +$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \ ./tests/bindings/python/bt2/ -t test_value.RealValueTestCase.test_assign_pos_int ---- + +== {cpp} usage + +A significant part and, in general, all the new code of {bt2} is written +in {cpp}. + +This section shows what's important to know about {cpp} to contribute +to {bt2}. + +[IMPORTANT] +==== +{bt2} only has {cpp} sources for _internal_ code. + +In other words, libbabeltrace2 _must_ expose a pure C99 API to preserve +ABI compatibility over time. +==== + +=== Standard + +The {bt2} project is configured to use the {cpp11} standard. + +{cpp11} makes it possible to build {bt2} with a broad range of +compilers, from GCC{nbsp}4.8 and Clang{nbsp}3.3. + +=== Common {cpp} code + +Many parts of the project need common {cpp} code. You'll find all of it +under `src/cpp-common`. + +In general, anything under a namespace named `internal` is internal to +the API containing it. For example, everything under the `bt2::internal` +namespace is internal to the `bt2` namespace and therefore isn't meant +to be used outside the `src/cpp-common/bt2` directory. + +==== `bt2`: libbabeltrace2 {cpp} bindings + +`src/cpp-common/bt2` contains our internal {cpp} bindings of +the libbabeltrace2 C{nbsp}API, under the `bt2` namespace. + +Those bindings are designed to have, as much as possible, no performance +impact. Anything which inherits `bt2::BorrowedObject` contains a single +libbabeltrace2 object pointer. + +Pass and return borrowed objects _by value_ (copy). + +In general, the following holds: + +[options="header,autowidth",cols="2"] +|=== +|{cpp} expression +|Equivalent C{nbsp}expression + +|`bt2::Xyz` +|`bt_xyz *` + +|`const bt2::Xyz` +|`bt_xyz * const` + +|`bt2::ConstXyz` +|`const bt_xyz *` + +|`const bt2::ConstXyz` +|`const bt_xyz * const` +|=== + +==== `bt2c`: general common {cpp} code + +Similar to the role of `src/common` for C code. + +In general, everything in here is under the `bt2c` namespace. + +Notable files are: + +`align.hpp`:: + The `bt2c::align()` function template: a wrapper of + `src/common/align.h`. + +`c-string-view.hpp`:: + The `bt2c::CStringView` class: a view on a constant null-terminated + C{nbsp}string. ++ +We have this because `bt2s::string_view` doesn't imply null termination, +only a beginning and a length. ++ +A `bt2c::CStringView` instance is convertible to `const char *` and may +be empty (the underlying pointer is null). + +`call.hpp`:: + The `bt2c::call()` function template: a partial implementation of + https://en.cppreference.com/w/cpp/utility/functional[INVOKE]. ++ +We use this mostly to assign the result of calling an immediately +invoked function expression (lambda) to an `auto` variable without +risking to assign the lambda itself, should we forget the calling +parentheses: ++ +[source,cpp] +---- +const auto res = bt2c::call([&] { + /* Complex initialization */ +}); +---- + +`endian.hpp`:: + Typed wrappers of `src/compat/endian.h`. + +`exc.hpp`:: + Common exception classes. + +`fmt.hpp`:: + Common https://fmt.dev/[{fmt}] formatters. + +`logging.hpp`:: + The `bt2c::Logger` class and helper `BT_CPPLOG*()` macros for any + {cpp} logging. ++ +When possible, prefer using this over the C{nbsp}logging API. ++ +One important benefit is that this API uses {fmt} to format the logging +message instead of `vsnprintf()`. + +`make-span.hpp`:: + The function template `bt2c::makeSpan()` which is an alternative to + https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD] + (a {cpp}17 feature). + +`prio-heap.hpp`:: + The `bt2c::PrioHeap` class template: an efficient heap data + structure. + +`read-fixed-len-int.hpp`:: + The function templates `bt2c::readFixedLenInt()`, + `bt2c::readFixedLenIntLe()`, and `bt2c::readFixedLenIntBe()`: read a + fixed-length integer from a byte buffer. + +`safe-ops.hpp`:: + The `bt2c::safe*()` function templates: arithmetic operations which + assert that there's no possible overflow. + +`std-int.hpp`:: + The `bt2c::StdIntT` type alias template: becomes one of the + `std::*int*_t` types depending on its parameters. ++ +For example, `bt2c::StdIntT<32, true>` is `std::int32_t`. + +`type-traits.hpp`:: + Common type traits. + +`uuid.hpp`:: + The following classes: + +`bt2c::Uuid`::: + Container of a 16-byte + https://en.wikipedia.org/wiki/Universally_unique_identifier[UUID]. ++ +Provides the static `generate()` method as well as conversion to +`bt2c::UuidView`. + +`bt2c::UuidView`::: + View on a UUID (not a container). ++ +Provides byte access, comparison, as well as string conversion methods. ++ +Also provides conversion to `bt2c::Uuid`. + +`vector.hpp`:: + The `bt2c::vectorFastRemove()` function template: remove an element + from an `std::vector` instance quickly when the order isn't + important. + +==== `bt2s`: drop-in replacements of {cpp}14 to {cpp}20 STL features + +Everything under the `bt2s` namespace has its equivalent under the `std` +namespace, but in {cpp} versions we don't yet have access to, namely: + +`make-unique.hpp`:: + `bt2s::make_unique()`, a drop-in replacement of `std::make_unique()` + ({cpp}14). + +`optional.hpp`:: + Drop-in replacement of the `std::optional` API ({cpp}17). + +`span.hpp`:: + Drop-in replacement of the `std::span` API ({cpp}20). + +`string-view.hpp`:: + Drop-in replacement of the `std::string_view` API ({cpp}17). + +==== `vendor`: copies of {cpp} dependencies + +This directory contains copies of the source code of {cpp} dependencies +to avoid packaging issues. + +They are: + +`fmt`:: + https://fmt.dev/[{fmt}]. + +`nlohmann`:: + https://json.nlohmann.me/[JSON for Modern C++]. + +`optional-lite`:: + https://github.com/martinmoene/optional-lite[optional lite]. ++ +IMPORTANT: Use the symbols of `src/cpp-common/bt2s/optional.hpp`, under +the `bt2s` namespace, instead of using this directly. + +`span-lite`:: + https://github.com/martinmoene/span-lite[span lite]. ++ +IMPORTANT: Use the symbols of `src/cpp-common/bt2s/span.hpp`, under the +`bt2s` namespace, instead of using this directly. ++ +TIP: `src/cpp-common/bt2c/make-span.hpp` offers `bt2c::makeSpan()` which +is an alternative to +https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD] +(a {cpp}17 feature). + +`string-view-lite`:: + https://github.com/martinmoene/string-view-lite[string_view lite]. ++ +IMPORTANT: Use the symbols of `src/cpp-common/bt2s/string-view.hpp`, +under the `bt2s` namespace, instead of using this directly. + +`wise_enum`:: + https://github.com/quicknir/wise_enum[wise_enum]. + +=== Automake/Libtool requirements + +To add a {cpp} source file to a part of the project, use the `.cpp` +extension and add it to the list of source files in `Makefile.am` as +usual. + +If a program or a shared library has a direct {cpp} source file, then +Libtool uses the {cpp} linker to create the result, dynamically +linking important runtime libraries such as libstdc++ and libgcc_s. + +Because a Libtool _convenience library_ is just an archive (`.a`), it's +_not_ dynamically linked to runtime libraries, even if one of its direct +sources is a {cpp} file. This means that for each program or shared +library named `my_target` in `Makefile.am` which is linked to a +convenience library having {cpp} sources (recursively), you _must_ do +one of: + +* Have at least one direct {cpp} source file in the + `+*_my_target_SOURCES+` list. + +* Add: ++ +---- +nodist_EXTRA_my_target_SOURCES = dummy.cpp +---- ++ +See +https://www.gnu.org/software/automake/manual/automake.html#Libtool-Convenience-Libraries[Libtool +Convenience Libraries] to learn more. + +For a given program or library, you _cannot_ have a C{nbsp}file and a +{cpp}{nbsp}file having the same name, for example `list.c` and +`list.cpp`. + +=== Coding style + +==== Whitespaces, indentation, and line breaks + +All the project's {cpp} files follow the +https://clang.llvm.org/docs/ClangFormat.html[clang-format] +https://clang.llvm.org/docs/ClangFormatStyleOptions.html[style] of the +`.clang-format` file for whitespaces, indentation, and line breaks. + +You _must_ format modified and new {cpp} files with clang-format before +you create a contribution patch. + +You need clang-format{nbsp}15 to use the project's `.clang-format` file. + +To automatically format all the project's {cpp} files, run: + +---- +$ ./tools/format-cpp.sh +---- + +To only format the {cpp} files of a given directory: + +---- +$ ./tools/format-cpp.sh ./src/cli +---- + +Use the `FORMATTER` environment variable to override the default +formatter (`clang-format{nbsp}-i`): + +---- +$ FORMATTER='my-clang-format-15 -i' ./tools/format-cpp.sh +---- + +==== Naming + +* Use camel case with a lowercase first letter for: +** Variable names: `size`, `objSize`. +** Function/method names: `size()`, `formatAndPrint()`. + +* Use camel case with an uppercase first letter for: +** Types: `Pistachio`, `NutManager`. +** Template parameters: `PlanetT`, `TotalSize`. +** Enumerators: `Type::SignedInt`, `Scope::Function`. + +* Use snake case with uppercase letters for: +** Definition/macro names: `MARK_AS_UNUSED()`, `SOME_FEATURE_EXISTS`. + +* Use only lowercase letters and digits for namespaces: `mylib`, `bt2`. + +* Use the `T` suffix for type template parameters and the `V` suffix for + non-type template parameters: ++ +[source,cpp] +---- +template +---- + +* Name a template parameter pack `ArgTs`. ++ +[source,cpp] +---- +template +---- + +* Use an underscore prefix for private and protected methods and member + type names: `_tryConnect()`, `_NodeType`. + +* Use the prefix `_m` for private and protected member variable names: + `_mLogger`, `_mSize`, `_mFieldClass`. ++ +This is to avoid name clashes with private/protected getters/setters. + +* Name setters and getters like the property name, without the `set` and + `get` prefixes. + +* Use the `is` or `has` prefix, if possible, to name the functions which + return `bool`. ++ +However, try to keep the name readable. For example, prefer +`colorIsBlue()` over `isColorBlue()`. + +=== Coding convention + +In general, the project's contributors make an effort to follow, +for {cpp11} code: + +* The + https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md[{cpp} Core Guidelines]. + +* Scott Meyers's + "`https://www.oreilly.com/library/view/effective-modern-c/9781491908419/[Effective Modern {cpp}]`". + +Here are a few important reminders: + +* Namespace your code. + +* Create one header/source file pair per class when possible. ++ +For a class named `MyClass`, name the corresponding files `my-class.hpp` +and `my-class.cpp`. + +* Use the `inline` keyword, not `static inline`, for header-only + functions that are not templates. + +* When defining a class, use this order: ++ +-- +. Friends (without any preceding access specifier). + +. Public types and type aliases. ++ +Private/protected types may be here too if they can't be lower. + +. Constructors, whatever their access. + +. Destructor (always public). + +. Copy-assignment and move-assignment operators. + +. Public methods. + +. Protected types and type aliases. + +. Protected methods. + +. Private types and type aliases. + +. Private methods. + +. Protected data members. + +. Private data members. +-- + +* Declare variables as close to where they're used as possible. + +* In general, try to avoid variables if it doesn't lead to more lines. ++ +For example, given: ++ +[source,cpp] +---- +const auto size = getSize(myObj, 23); +auto& obj = this->_objForSize(size); + +abc::sendObj(obj, SendOpts::WAIT); +---- ++ +Prefer this: ++ +[source,cpp] +---- +abc::sendObj(this->_objForSize(getSize(myObj, 23)), SendOpts::WAIT); +---- + +* If you really need variables, then scope them to avoid "`leaking`" + them: ++ +[source,cpp] +---- +doSomeStuff(123, &obj); + +{ + const auto status = tryChange(obj); + + BT_CPPLOGD("New status: {}.", status); + BT_ASSERT(status == Status::CONTINUE); +} + +doMoreStuff(&obj); +---- ++ +This also means to either use a dedicated, named method/function or to +use `bt2c::call()` with an immediately invoked function expression +(lambda) to perform complex initialization of an ideally `const` +variable: ++ +[source,cpp] +---- +const auto size = bt2c::call([this] { + auto& sender = this->_curSender(); + + if (sender.strategy() == Strategy::ACK) { + return sender.strategySize(); + } else if (sender.strategy() == Strategy::NACK) { + return 0; + } + + return _mDefSize; +}); +---- + +* Always use `bt2c::call()` to call an immediately invoked function + expression (see the previous point). + +* If possible, initialize object members without a default value with + the initializer list of a constructor, not in the constructor body. ++ +If the initialization is complex, either use a dedicated, named +method/function or `bt2c::call()` with an immediately invoked function +expression (lambda): ++ +[source,cpp] +---- +MyObj::MyObj(const std::size_t size) : + _mSize {size}, + _mOtherObj {bt2c::call([size] { + /* Complex initialization here */ + })} +{ +} +---- + +* Use `auto` when possible. ++ +Use `auto&` instead of `const auto&` when you know that the type is +`const` anyway. ++ +Don't use `auto *`. + +* Use `const` as much as possible, even for pointers + (`+const char * const+`) and numeric values (`const unsigned int`) + which never need to change. + +* Prefer the `pass:[MyObj myObj {...}]` initialization form over + `pass:[auto myObj = MyObj {...}]`. + +* Implement simple setters, getters, and one-liners in header files and + everything else that's not a template in source files, including + constructors. + +* Make methods `const noexcept` or `const` as much as possible. + +* Make constructors `explicit` unless you really need an implicit + constructor (which is rare), including default constructors: ++ +[source,cpp] +---- +explicit Meow(); +---- + +* Use `std::unique_ptr` to manage memory when possible. ++ +However, use references (`+*my_unique_ptr+`) and raw pointers +(`+my_unique_ptr.get()+`) when not transferring ownership. + +* Use `nullptr`, not `NULL` nor 0. + +* Return by value (rvalue) instead of by output parameter (non-const + lvalue reference), even complex objects, unless you can prove that the + performance is improved when returning by parameter. + +* For a function parameter or a return value of which the type needs to + be a reference or pointer, use: ++ +If the value is mandatory::: + A reference. +If the value is optional::: + A raw pointer. + +* Don't use `+std::move()+` when you already have an rvalue, which + means: +** Don't write `+return std::move(...);+` as this can interfere with + RVO. +** Don't use `+std::move()+` with a function call + (`+std::move(func())+`). + +* For each possible move/copy constructor or assignment operator, do one + of: +** Write a custom one. +** Mark it as defaulted (`default`) +** Mark it as deleted (`delete`). + +* Use scoped enumerations (`+enum class+`). + +* Mark classes known to be final with the `final` keyword. + +* Use type aliases (`using`), not type definitions (`typedef`). + +* In a `.cpp` file, use anonymous namespaces for local symbols instead + of `static` or `inline`. + +* Prefer a function in an anonymous namespace in a `.cpp` file over a + private static method if it doesn't need private access to an object. + +* Don't pollute the global namespace: +** Don't use `using namespace xyz` anywhere. +** Use only namespace aliases in source files (`.cpp`), trying to + use them in the smallest possible scope (function, or even smaller). + +* Return a structure with named members instead of a generic container + such as `std::pair` or `std::tuple`. + +* When a class inherits a base class with virtual methods, use the + `override` keyword to mark overridden virtual methods, and do not use + the `virtual` keyword again. + +* Define overloaded operators only if their meaning is obvious, + unsurprising, and consistent with the corresponding built-in + operators. ++ +For example, use `+|+` as a bitwise- or logical-or, not as a shell-style +pipe. + +* Use RAII wrappers when managing system resources or interacting with + C{nbsp}libraries. ++ +In other words, don't rely on ``goto``s and error labels to clean up as +you would do in{nbsp}C. ++ +Use the RAII, Luke. + +* Throw an exception when there's an unexpected, exceptional condition, + https://isocpp.org/wiki/faq/exceptions#ctors-can-throw[including from + a constructor], instead of returning a status code. + +* Accept a by-value parameter and move it (when it's moveable) when you + intend to copy it anyway. ++ +You can do this with most STL containers. ++ +Example: ++ +[source,cpp] +---- +void Obj::doSomething(std::string str) +{ + _mName = std::move(str); + /* ... */ +} +---- + +.`baby.hpp` +==== +This example shows a {cpp} header which follows the {bt2} {cpp} coding +convention. + +[source,cpp] +---- +/* + * SPDX-FileCopyrightText: 2020 Harry Burnett + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_BABY_HPP +#define BABELTRACE_BABY_HPP + +#include +#include +#include + +namespace life { + +class Toy; + +/* + * A baby is a little human. + */ +class Baby : public Human +{ + friend class Parent; + +public: + using Toys = std::unordered_set; + + enum class Gender + { + Male, + Female, + Other, + }; + + explicit Baby() = default; + explicit Baby(const Toys& toys); + Baby(const Baby&) = delete; + Baby(Baby&&) = delete; + +protected: + explicit Baby(Gender initialGender = Gender::OTHER); + +public: + ~Baby(); + Baby& operator=(const Baby&) = delete; + Baby& operator=(Baby&&) = delete; + + /* + * Eats `weight` grams of food. + */ + void eat(unsigned long weight); + + /* + * Sleeps for `duration` seconds. + */ + void sleep(double duration); + + /* + * Sets this baby's name to `name`. + */ + void name(std::string name) + { + _mName = std::move(name); + } + + /* + * This baby's name. + */ + const std::string& name() const noexcept + { + return _mName; + } + +protected: + void _addTeeth(unsigned long index); + void _grow(double size) override; + +private: + std::string _mName {"Paul"}; + Toys _mToys; +}; + +} /* namespace life */ + +#endif /* BABELTRACE_BABY_HPP */ +---- +==== + +== Python Usage + +=== Formatting + +All Python code must be formatted using the version of +https://github.com/psf/black[Black] specified in `dev-requirements.txt`. + +All Python imports must be sorted using the version of +https://pycqa.github.io/isort/[isort] indicated in `dev-requirements.txt`.