BDE 4.14.0 Production release
|
Macros | |
#define | BSLS_DEPRECATE_COMPILER_SUPPORT 0 |
#define | BSLS_DEPRECATE |
#define | BSLS_DEPRECATE_CAT(X, Y) BSLS_DEPRECATE_CAT_A(X, Y) |
#define | BSLS_DEPRECATE_CAT_A(X, Y) BSLS_DEPRECATE_CAT_B(X, Y) |
#define | BSLS_DEPRECATE_CAT_B(X, Y) X ## Y |
Internal implementation machinery for BSLS_DEPRECATE_CAT . | |
#define | BSLS_DEPRECATE_ISDEFINED(...) BSLS_DEPRECATE_ISDEFINED_A(__VA_ARGS__) |
#define | BSLS_DEPRECATE_ISDEFINED_A(...) ((__VA_ARGS__ ## 1L) != 0) |
Internal implementation machinery for BSLS_DEPRECATE_ISDEFINED . | |
#define | BSLS_DEPRECATE_ISNONZERO(...) BSLS_DEPRECATE_ISNONZERO_A(__VA_ARGS__) |
#define | BSLS_DEPRECATE_ISNONZERO_A(...) (__VA_ARGS__ + 1 != 1) |
Internal implementation machinery for BSLS_DEPRECATE_ISNONZERO . | |
#define | BSLS_DEPRECATE_MAKE_VER(M, N) ((M) * 1000 + (N)) |
#define | BSLS_DEPRECATE_ISPASTTHRESHOLD(U, M, N) |
#define | BSLS_DEPRECATE_ISPASTTHRESHOLD_A(U) BSLS_DEPRECATE_CAT(U, _VERSION_DEPRECATION_THRESHOLD) |
Internal implementation machinery for BSLS_DEPRECATE_ISPASTTHRESHOLD . | |
#define | BSLS_DEPRECATE_ISRETAINED(U, M, N) BSLS_DEPRECATE_ISRETAINED_A(U, M, N) |
#define | BSLS_DEPRECATE_ISRETAINED_A(U, M, N) BSLS_DEPRECATE_ISRETAINED_B(U, M, N) |
#define | BSLS_DEPRECATE_ISRETAINED_B(U, M, N) |
Internal implementation machinery for BSLS_DEPRECATE_ISRETAINED . | |
#define | BSLS_DEPRECATE_IS_ACTIVE(U, M, N) |
Provide machinery to deprecate interfaces on a per-version basis.
This component defines a suite of macros to control (on a per-version, per-UOR basis) the deprecation of functions, user-defined types, and typedef
s, and the conditional compilation of enumerators and preprocessor macros. The bsls_deprecate facility operates by triggering compiler warnings when types or interfaces are used that have been tagged with deprecation macros defined by this component. Unlike previous deprecation facilities based exclusively on the use of #ifndef
with global macros (such as BDE_OMIT_DEPRECATED
and BDE_OMIT_INTERNAL_DEPRECATED
), supported use of the bsls_deprecate facility does not affect a UOR's ABI. It is therefore safe to link applications based on libraries built with different deprecation policies.
UOR owners who wish to mark an interface as deprecated can do so by tagging the declaration of that interface with the BSLS_DEPRECATE
macro, wrapped in a #if
block to apply BSLS_DEPRECATE
only when BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
evaluates to true for a given version M.N
of the specified UOR
:
The above application of BSLS_DEPRECATE_IS_ACTIVE
indicates that foo
is deprecated starting with bde
version 3.2. Once the deprecation threshold for bde
advances to version 3.2, code calling foo
will generate a deprecation warning with compilers that support deprecation attributes. (See {Version Control Macros for Library Authors} for information on defining a deprecation threshold for a UOR.) Note that in the absence of an explicit deprecation threshold (BDE_VERSION_DEPRECATION_THRESHOLD
, in this case), code calling foo
would begin generating deprecation warnings in the very next minor or major release of bde
(3.3 or 4.0, whichever applies).
If an interface has several entities being deprecated at the same time, clients can define a new deprecation macro within that header to avoid repeated use of BSLS_DEPRECATE_IS_ACTIVE
:
When an interface is tagged with BSLS_DEPRECATE
as shown above, the deprecation is initially not enforced by default. That is, a normal build of code calling the deprecated interface will not emit a deprecation warning.
Downstream developers who wish to make sure that their code uses no deprecated interfaces can do so by defining the symbol BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
in their build system.
NEVER define BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
in a PRODUCTION BUILD CONFIGURATION. If you do so, all libraries that you depend on will be prevented from deprecating more code in future versions.
At some point after an interface has been tagged with BSLS_DEPRECATE
, the library owner can make new uses of that interface generate warnings by defining a deprecation threshold for the UOR that contains the deprecated interface (or by adjusting the deprecation threshold for the UOR if it already exists). Defining a deprecation threshold enforces deprecations made in all versions up to and including the threshold. If the version number of the deprecation threshold is greater than or equal to the version number specified in the BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
macro, then the BSLS_DEPRECATE
macro will be enabled and generate a warning.
This is the recommended way to define a deprecation threshold (see Version Control Macros for Library Authors :
Prior to the availability of this component, when a developer wanted to deprecate an API they might either apply an attribute to the API that would generate a warning, or they would use #ifdef
to remove deprecated code when it is built with appropriate options. These solutions have a practical shortcoming in a production environment like Bloomberg's, where code changes in lower-level libraries cannot be checked in if they break the build of (higher-level) client libraries. In such a system, well-meaning clients might build their libraries using -Werror
(to turn compilation warnings into errors) or with appropriate #ifdef
s to ensure their code does not use deprecated APIs, but in so doing they hinder the introduction of any new deprecations. In addition, the use of #ifdef
results in ABI compatibility issues, as some clients may build with deprecated code removed, and others may not.
This deprecation facility is based around two concepts that attempt to address these shortcomings:
BSLS_DEPRECATE_*
macros are used to trigger compilation warnings on platforms that support deprecation attributes, instead of removing code from the codebase.BSLS_DEPRECATE
macro is generally guarded by a version check using BSLS_DEPRECATE_IS_ACTIVE
. In an environment where compiler warnings are considered to be build failures, it is possible (and encouraged) to tag a C++ entity with a deprecation macro in one release cycle, and not have that deprecation affect any clients by default until a later release cycle. During the intervening period, clients have an opportunity to proactively check their code for uses of newly-deprecated code.Notice that the cost for maintaining ABI compatibility is that clients cannot check whether they are using deprecated interfaces unless they build their software on certain platforms with warnings activated. For this facility to be effective across an enterprise, it is required that such warning-enabled builds be part of the standard process for checking in code in the enterprise.
This component stipulates two sets of macros. One set of deprecation macros, defined in this component, are used to identify a C++ entity as being deprecated in a given version of a given UOR. A second set of control macros, defined by clients of this component, dictates which deprecation macros are enforced at any point in the code during compilation.
BSLS_DEPRECATE
Expands to a particular deprecation attribute with compilers that have such support; otherwise,
BSLS_DEPRECATE
expands to nothing.BSLS_DEPRECATE
can be applied toclass
orstruct
definitions, function declarations, andtypedef
s.
BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
These two macros are intended to be placed together in a preprocessorExpands to 1 if deprecations are enforced for the specified version
M.N
of the specifiedUOR
, and to 0 otherwise.
#if
block in front of a function, type, or typedef
declaration, with BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
controlling whether or not BSLS_DEPRECATE
is applied to the declaration. The exact placement of the block should match the requirements of the C++14 [[deprecated]]
attribute.Examples:
At present, the underlying compiler intrinsics represented by BSLS_DEPRECATE
cannot be applied uniformly to some C++ constructs, most notably variables, enumerators, and preprocessor macros. Fortunately, these constructs can often be removed from a library without otherwise affecting ABI, so !BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
can be used with a #if
directive to entirely remove blocks of code containing those C++ constructs.
Example:
Note the use of the !
operator: deprecated code is compiled only if deprecations are not enforced for the specified UOR version.
Particular care must be taken to ensure that deprecating one or more enumerators does not (inadvertently) change the values of other enumerators in the same enum
:
A UOR-specific deprecation threshold can be (and typically should be) specified by the authors of a UOR to govern which of their deprecations are active by default:
<UOR>_VERSION_DEPRECATION_THRESHOLD
Example:This macro should be defined in
<uor>scm_versiontag.h
alongside<UOR>_VERSION_MAJOR
and<UOR>_VERSION_MINOR
to indicate the greatest version of the unit of releaseUOR
for which deprecations are enforced by default.
BSLS_DEPRECATE_IS_ACTIVE(ABC, M, N)
will expand to 1 for all versions M.N
of ABC
up to and including version 1.2. For M.N
later than 1.2 (e.g., 1.3 or 2.0), BSLS_DEPRECATE_IS_ACTIVE(ABC, M, N)
will expand to 1 only if the BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
macro is defined by the user (see {Build Control Macros for Clients}).Note that if a deprecation threshold is not explicitly defined for a UOR that defines <UOR>_VERSION_MAJOR
and <UOR>_VERSION_MINOR
, then BSLS_DEPRECATE_IS_ACTIVE(UOR, M, N)
will expand to 1 once the version indicated by <UOR>_VERSION_MAJOR
and <UOR>_VERSION_MINOR
becomes greater than M.N
. For example, BSLS_DEPRECATE_IS_ACTIVE(ABC, 1, 4)
will expand to 1 in version 1.5 of ABC
(or 2.0 if there is no release 1.5) if ABC_VERSION_DEPRECATION_THRESHOLD
is not defined. For this reason, it is highly recommended that UOR authors explicitly define a deprecation threshold to avoid unexpected build failures when a new release is issued, especially in environments where warnings are considered fatal.
A second UOR-specific macro is available to the authors of a UOR that must, for whatever reason, continue to use interfaces that are deprecated in their own library:
BB_SILENCE_DEPRECATIONS_FOR_BUILDING_UOR_<UOR>
Example:This macro prevents bsls_deprecate from enforcing deprecations for all versions of
UOR
. This macro must be defined in each.cpp
file ofUOR
that either uses a deprecated interface from the same UOR that has reached the deprecation threshold forUOR
, or includes a header file ofUOR
that uses such an interface in inline code. This macro must be defined before the first#include
of a header fromUOR
.
The following two macros are intended for client use during builds, either to enable all deprecations or to suppress selected deprecations:
BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
This macro should be defined as a
-D
parameter during test builds of components that are intended to be deprecation-clean. When this macro is defined, deprecations will be enforced for all versions of all UORs, except as overridden byBB_SILENCE_DEPRECATIONS_FOR_BUILDING_UOR_<UOR>
(see Version Control Macros for Library Authors orBB_SILENCE_DEPRECATIONS_<UOR>_<M>_<N>
(see below). This macro must never appear in source code, and must never be defined for any production or check-in build configuration.
BB_SILENCE_DEPRECATIONS_<UOR>_<M>_<N>
Example:This macro should be defined by clients of
UOR
who still need to use an interface that was deprecated in versionM.N
after the deprecation threshold forUOR
has reached (or exceeded)M.N
. This macro should be defined before the first#include
of a header fromUOR
. This macro must never be defined in a header file.
BSLS_DEPRECATE
will produce a warning with the following compilers:
Additionally, BSLS_DEPRECATE
will produce a warning with any compiler that provides the C++14 deprecated
attribute.
Deprecation is a negotiation process between code authors and code consumers to allow old code to be removed from the codebase. This component supports a deprecation model where code moves through four steps from being fully supported, to optionally deprecated, to fully deprecated, and finally to being deleted. At each step, responsibility for moving the process forward is passed back and forth between library authors and library users.
When the owners of a library want to deprecate an interface, they start by adding appropriate deprecation macros, specifying their UOR and the version of their next release. For example, suppose package group abc
is currently at version 1.1. If the owners of abc
want to deprecate a function abcxyz::SomeUtil::someFunction
, they could add the deprecation macros BSLS_DEPRECATE
and BSLS_DEPRECATE_IS_ACTIVE(ABC, 1, 2)
in front of the declaration of someFunction
:
At this point deprecations are not enforced by default for version 1.2 of abc
, so the deprecation macro alone will not have any affect on clients. A client building their code normally will trigger no compiler warnings due to this new deprecation:
If the owners of a client library or application want to check that their code uses no deprecated interfaces, they can define the BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
flag in their test build process. A compiler that supports deprecation attributes will then trigger compiler warnings:
WARNING: Clients at Bloomberg must not define BB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
in a production build. This flag should be used for development builds only.
Now the owners have the opportunity to fix their code by removing the dependency on abcxyz::SomeUtil::someFunction
.
At some point in the future, possibly on release of abc
version 1.3, the owners of abc
will make deprecations enforced by default for version 1.2 of abc
, by setting the deprecation threshold for abc
in their version control headers:
If the owners of grp
have cleaned up their code, normal builds will trigger no compiler warnings. However, any new development by any clients will trigger warnings if they add a new use of abcxyz::SomeUtil::someFunction
:
But what if the owners of grp
will not, or for some reason cannot, clean up their code in the near term? Moving the threshold for abc
to version 1.2 will of course trigger warnings when the owners of grp
next try to build grppkg_fooutil . In a development context requiring that all production builds remain warning-free, we would be at an impasse: either the owners of grp
must clean up their code immediately, or the owners of abc
will not be able to enforce deprecations by default for version 1.2.
This impasse can be resolved by allowing the owners of grp
to locally silence warnings caused by deprecations for version 1.2 of abc
. This is done by adding a definition of BB_SILENCE_DEPRECATIONS_ABC_1_2
to any .cpp
files that use abcxyz::SomeUtil::someFunction
:
Now the entire codebase can build warning-free again.
Managers can easily detect BB_SILENCE_DEPRECATIONS_<UOR>_<M>_<N>
macros in the codebase, and put pressure on teams to remove such remnant uses of deprecated code. When all remnant uses have been removed, then the deprecated function can be deleted entirely:
This section illustrates intended use of this component.
When one piece of code has been superseded by another, we would like to get users to adopt the new code and stop using the old code. Being able to inform clients that they need to clean up existing uses of the old code, and also to prevent new uses of that code, makes it easier to get to the point where old code actually has zero uses and can be deleted. The deprecation macros BSLS_DEPRECATE
and BSLS_DEPRECATE_IS_ACTIVE
, and their associated control macros, can be used to gradually reduce the number of uses of deprecated code, so that it can be removed eventually.
Suppose we own package group xxx
that is currently at version 7.6. One of our components contains a function foo
that has been superseded by another function bar
.
First, we add a deprecation tag to the declaration of foo
, showing that it will be deprecated starting with version 7.7, and update the documentation accordingly:
When we release version 7.7, the added deprecation tag will not immediately affect any of the users of foo
. However if any of those users do a test build of their code with -DBB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
, they will see a warning that foo
has been deprecated.
Finally, when enough time has passed to allow all users of foo
to switch over to using bar
, probably on or after the release of xxx
version 7.8, we can enforce the deprecation of foo
by moving the deprecation threshold for xxx
to version 7.7, to indicate that all interfaces deprecated for version 7.7 are disallowed by default:
#define BSLS_DEPRECATE |
#define BSLS_DEPRECATE_CAT | ( | X, | |
Y | |||
) | BSLS_DEPRECATE_CAT_A(X, Y) |
Expand to the expansion of the specified X
, joined to the expansion of the specified Y
.
#define BSLS_DEPRECATE_CAT_A | ( | X, | |
Y | |||
) | BSLS_DEPRECATE_CAT_B(X, Y) |
#define BSLS_DEPRECATE_CAT_B | ( | X, | |
Y | |||
) | X ## Y |
#define BSLS_DEPRECATE_COMPILER_SUPPORT 0 |
#define BSLS_DEPRECATE_IS_ACTIVE | ( | U, | |
M, | |||
N | |||
) |
Expand to an expression evaluating to true
in a preprocessor context if deprecations are being enforced for the specified version M.N
of the specified UOR U
, and expand to an expression evaluating to false
otherwise. Deprecations will be enforced for version M.N
of UOR U
if:
BB_SILENCE_DEPRECATIONS_<U>_<M>_<N>
has not been defined in this translation unit, andBB_SILENCE_DEPRECATIONS_FOR_BUILDING_UOR_<U>
has not been defined in this translation unit, andBB_WARN_ALL_DEPRECATIONS_FOR_TESTING_ONLY
has been defined, orU
and that threshold is greater than or equal to version M.N
, orU
, the versioning package for UOR U
defines <U>_VERSION_MAJOR
and <U>_VERSION_MINOR
, and the version so designated is greater than version M.N
. #define BSLS_DEPRECATE_ISDEFINED | ( | ... | ) | BSLS_DEPRECATE_ISDEFINED_A(__VA_ARGS__) |
Expand to an expression evaluating to true
in a preprocessor context if the deprecation control macro symbol supplied as an argument has been #define
d as nil, 0, or 1, and expand to an expression evaluating to false
otherwise. The behavior is undefined unless this macro is evaluated with a single argument having the form of a deprecation control macro symbol, and that symbol has either not been #define
d at all or has been #define
d as nil, 0, or 1.
#define BSLS_DEPRECATE_ISDEFINED_A | ( | ... | ) | ((__VA_ARGS__ ## 1L) != 0) |
#define BSLS_DEPRECATE_ISNONZERO | ( | ... | ) | BSLS_DEPRECATE_ISNONZERO_A(__VA_ARGS__) |
Expand to an expression evaluating to true
in a preprocessor context if the deprecation control macro symbol supplied as an argument has been #define
d as an expression that evaluates to a non-zero value, and expand to an expression evaluating to false
otherwise. The behavior is undefined unless this macro is evaluated with a single argument having the form of a deprecation control macro symbol, and that symbol has either not been #define
d at all, or has been #define
d as nil or an arithmetic expression.
#define BSLS_DEPRECATE_ISNONZERO_A | ( | ... | ) | (__VA_ARGS__ + 1 != 1) |
#define BSLS_DEPRECATE_ISPASTTHRESHOLD | ( | U, | |
M, | |||
N | |||
) |
Expand to an expression evaluating to true
in a preprocessor context if the specified version M.N
of the specified UOR U
is past the deprecation threshold for U
, and expand to an expression evaluating to false
otherwise. Version M.N
of U
is past the deprecation threshold for U
if:
U
and that threshold is greater than or equal to version M.N
, orU
, the versioning package for UOR U
defines <U>_VERSION_MAJOR
and <U>_VERSION_MINOR
, and the version so designated is greater than version M.N
. #define BSLS_DEPRECATE_ISPASTTHRESHOLD_A | ( | U | ) | BSLS_DEPRECATE_CAT(U, _VERSION_DEPRECATION_THRESHOLD) |
#define BSLS_DEPRECATE_ISRETAINED | ( | U, | |
M, | |||
N | |||
) | BSLS_DEPRECATE_ISRETAINED_A(U, M, N) |
Expand to an expression evaluating to true
in a preprocessor context if deprecations in the specified version M.N
of the specified UOR U
have been deactivated in this build by defining either the corresponding BB_SILENCE_DEPRECATIONS_<U>_<M>_<N>
macro or the corresponding BB_SILENCE_DEPRECATIONS_FOR_BUILDING_UOR_<U>
macro, and expand to an expression evaluating to false
otherwise.
#define BSLS_DEPRECATE_ISRETAINED_A | ( | U, | |
M, | |||
N | |||
) | BSLS_DEPRECATE_ISRETAINED_B(U, M, N) |
#define BSLS_DEPRECATE_ISRETAINED_B | ( | U, | |
M, | |||
N | |||
) |
#define BSLS_DEPRECATE_MAKE_VER | ( | M, | |
N | |||
) | ((M) * 1000 + (N)) |
Expand to an opaque sequence of symbols encoding a UOR version where the specified M
is the major version number and the specified N
is the minor version number.