11# Application Binary Interface (ABI) Policy
22
3- To support scenarios where OpenTelemetry implementations are deployed as binary
4- plugins, certain restrictions are imposed on portions of the OpenTelemetry API.
3+ To support scenarios where opentelemetry-cpp is included in multiple libraries
4+ that are combined into a single application (for example as binary plugins, or
5+ as independently instrumented libraries), certain restrictions are imposed on
6+ portions of the OpenTelemetry API to ensure ABI stability and predictable
7+ behavior. See [ library distribution] ( ./library-distribution.md ) for how
8+ components control their exported symbols in that scenario.
59
610Many parts of the C++ standard library don't have well-defined ABIs. To ensure
7- that a plugin compiled against one version of the C++ standard library can work
8- with an application or library compiled against a different version of the C++
9- standard library, we limit a portion of the OpenTelemetry API to use ABI stable
10- types.
11+ that a component compiled against one version of the C++ standard library can
12+ work with an application or library compiled against a different version of the
13+ C++ standard library, we limit a portion of the OpenTelemetry API to use ABI
14+ stable ` nostd:: ` types by default. The ` OPENTELEMETRY_STL_VERSION ` preprocessor macro
15+ (defined by the CMake ` WITH_STL ` build option) can be set to replace
16+ these ABI stable types with their ` std:: ` equivalents (see [ building with the
17+ standard C++ library] ( ./building-with-stdlib.md ) for when this is appropriate).
1118
1219In the areas of the API where we need ABI stability, we use C++ as an extended
1320C. We assume that standard language features like inheritance follow a
@@ -16,16 +23,43 @@ ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable)) and can be used
1623across compilers, but don't rely on the ABI stability of the C++ standard
1724library classes.
1825
19- ABI stability is not provided by the interfaces the SDK provides as
20- implementation hooks to vendor implementors, like exporters, processors,
21- aggregators and propagators.
26+ ABI stability is provided for the OTel API and is not required for
27+ OTel SDK-provided interfaces (e.g., resource detectors, exporters, processors, samplers).
2228
23- These are some of the rules for where ABI stability is required.
29+ Within a stable ABI version, non-breaking additive changes may be accepted, for example:
2430
25- Note: This assumes export maps are used to properly control symbol resolution.
31+ - add new non-virtual member functions to an existing API class
32+ - add new overloads of an existing non-virtual function
33+ - add new types
34+ - append new values to an enum
2635
27- 1 . Abstract classes in the OpenTelemetry API must use ABI stable types in their
28- virtual function signatures. Example
36+ The following changes are considered breaking and must target an
37+ experimental ABI version:
38+
39+ - use of non-ABI-stable types in virtual function signatures or
40+ singletons of an API class
41+ - change the order, add, remove, or modify the signature of virtual
42+ functions on an API class
43+ - change the memory layout of a type that crosses the ABI boundary
44+ - change the definition or observable behavior of an inline function,
45+ template, or ` inline ` /` constexpr ` variable in an API header
46+
47+ The following sections describe common cases where ABI stability is broken
48+ and provide examples of how to apply breaking changes.
49+
50+ For the ABI-stable OTel API, breaking changes must target the
51+ experimental ABI version, guarded by the ` OPENTELEMETRY_ABI_VERSION_NO `
52+ preprocessor macro (shown by the `#if
53+ OPENTELEMETRY_ABI_VERSION_NO >= 2` guards in the examples). See the [ ABI version
54+ policy] ( ./abi-version-policy.md ) for which ABI versions are stable versus
55+ experimental.
56+
57+ ## Virtual function signatures
58+
59+ Abstract classes in the OpenTelemetry API must use ABI stable types in their
60+ virtual function signatures.
61+
62+ Example:
2963
3064``` cpp
3165class Tracer {
@@ -58,3 +92,107 @@ private:
5892Singletons defined by the OpenTelemetry API must use ABI stable types since they
5993could potentially be shared across multiple instrumented dynamic shared objects
6094(DSOs) compiled against different versions of the C++ standard library.
95+
96+ ## Virtual function tables
97+
98+ The set, order, and signatures of virtual functions
99+ on an existing API class must not change within a stable ABI version. Doing so
100+ alters the vtable layout and breaks
101+ binary compatibility for callers built against the previous layout. New or
102+ changed virtual functions must instead be introduced in an experimental ABI
103+ version.
104+
105+ Example:
106+
107+ ``` cpp
108+ class Logger {
109+ public:
110+ virtual ~ Logger() = default;
111+
112+ #if OPENTELEMETRY_ABI_VERSION_NO >= 2
113+ // OK: adding a new virtual method under the experimental ABI guard, so the stable ABI (v1) vtable layout is unchanged.
114+ virtual void NewVirtualMethod() noexcept {}
115+ #endif
116+ };
117+ ```
118+
119+ ## Memory layout
120+
121+ Within a stable ABI version, the memory layout of any type that crosses the ABI
122+ boundary must not change.
123+
124+ This applies to the abstract API classes, the ABI stable value types (such as
125+ `nostd::string_view` and `nostd::span`), and singletons. Any change that alters
126+ layout, such as the order, type, or alignment of non-static data members, or the
127+ set and order of base classes, must be delivered in an experimental ABI version.
128+ The same applies to enumerations: do not change the underlying type or renumber
129+ existing enumerators.
130+
131+ Example:
132+
133+ ```cpp
134+ class Logger
135+ {
136+ public:
137+ // OK: adding a non-virtual method does not change the memory layout.
138+ bool NewMethod() const noexcept;
139+
140+ private:
141+
142+ #if OPENTELEMETRY_ABI_VERSION_NO >= 2
143+ // OK: new data member added only under the experimental ABI guard.
144+ bool new_member_{};
145+ #endif
146+ };
147+ ```
148+
149+ ## Definitions in API headers
150+
151+ Entities defined in ABI-stable API headers (inline functions, templates, and
152+ ` inline ` /` constexpr ` variables) must not change their definition or observable
153+ behavior within a stable ABI version.
154+
155+ A single application may link multiple independently built libraries that were
156+ compiled against different opentelemetry-cpp API header versions, or with
157+ different API-level compiler definitions. Each carries its own definition of
158+ these inline entities. The C++ [ One Definition
159+ Rule] ( https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule )
160+ requires every definition to be identical. If they differ, the linker silently
161+ keeps one unspecified definition. A library can then run a definition it was not
162+ built against, producing unexpected behavior.
163+
164+ Any change to API headers that impacts observable behavior must instead be
165+ delivered in an experimental ABI version. Critical correctness or security fixes
166+ may be exceptions. All such changes must be noted in
167+ ` CHANGELOG.md ` .
168+
169+ Example:
170+
171+ ` Logger::EmitLogRecord(args...) ` applies the severity filter on log
172+ records (and may drop the record). This is an observable behavior change and
173+ only allowed under the experimental ABI (v2).
174+
175+ ``` cpp
176+ class Logger
177+ {
178+ public:
179+ template <class... ArgumentType>
180+ void EmitLogRecord(ArgumentType &&...args)
181+ {
182+ #if OPENTELEMETRY_ABI_VERSION_NO >= 2
183+ // Behavior change added to the experimental ABI
184+ const Severity arg_severity = detail::FindSeverityInArgs(args...);
185+ if (arg_severity != Severity::kInvalid && !Enabled(arg_severity))
186+ {
187+ return;
188+ }
189+ nostd::unique_ptr<LogRecord > log_record = CreateLogRecord(/* context_or_span * /);
190+ #else
191+ // Stable ABI behavior
192+ nostd::unique_ptr<LogRecord > log_record = CreateLogRecord();
193+ #endif
194+
195+ ...
196+ }
197+ };
198+ ```
0 commit comments