BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_linkcoercion.h
Go to the documentation of this file.
1/// @file bsls_linkcoercion.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_linkcoercion.h -*-C++-*-
8#ifndef INCLUDED_BSLS_LINKCOERCION
9#define INCLUDED_BSLS_LINKCOERCION
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_linkcoercion bsls_linkcoercion
15/// @brief Provide a way to force a link-time dependency into an object.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_linkcoercion
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_linkcoercion-purpose"> Purpose</a>
25/// * <a href="#bsls_linkcoercion-macros"> Macros </a>
26/// * <a href="#bsls_linkcoercion-description"> Description </a>
27/// * <a href="#bsls_linkcoercion-macro-summary"> Macro Summary </a>
28/// * <a href="#bsls_linkcoercion-link-coercion-mechanism"> Link coercion mechanism </a>
29/// * <a href="#bsls_linkcoercion-linker-garbage-collection"> Linker garbage collection </a>
30/// * <a href="#bsls_linkcoercion-usage"> Usage </a>
31/// * <a href="#bsls_linkcoercion-example-1-prevent-linking-debug-and-optimized-translation-units"> Example 1: Prevent Linking Debug and Optimized Translation Units </a>
32///
33/// # Purpose {#bsls_linkcoercion-purpose}
34/// Provide a way to force a link-time dependency into an object.
35///
36/// # Macros {#bsls_linkcoercion-macros}
37///
38/// - BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY
39///
40/// # Description {#bsls_linkcoercion-description}
41/// This component provides a facility to force a link-time
42/// dependency on a symbol of the name supplied to the macro into the
43/// translation unit being compiled. This macro can be useful for generating
44/// link-time failures if a library version mismatch occurs.
45///
46/// ## Macro Summary {#bsls_linkcoercion-macro-summary}
47///
48///
49/// This section provides a brief description of the macros defined in this
50/// component.
51/// @code
52/// BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, refName, referredSymbol);
53/// Force a link-time dependency into an object by creating a "symbol" (a
54/// static variable with external linkage) having specified 'type'
55/// (typically 'const char *'), the specified 'name' (which should be
56/// unique), and that will be given the value of the address of the
57/// specified 'referredSymbol'.
58/// @endcode
59/// Notice that this macro is typically used to prevent to binary incompatible
60/// object files from being successfully linked together. This is achieved by
61/// calling this macro in a way that `referredSymbol` will have a different
62/// symbol name for incompatible builds.
63///
64/// ## Link coercion mechanism {#bsls_linkcoercion-link-coercion-mechanism}
65///
66///
67/// Link-time coersion is implemented by creating a static variable that
68/// references an external symbol defined by the library. The actual name of
69/// this external symbol should be different for different build flavors. When
70/// the executable is linked against the libraries with link-coercion symbols,
71/// the linker needs to resolve the symbol name and will fail the link step if
72/// the required symbol name is not present in the linked library (i.e. the
73/// library was built with a different set of flags that control the coercion
74/// symbol creation). For example, we can create different coercion symbols for
75/// code built with c++17 and c++20 flags, effectively preventing translation
76/// units compiled with different c++ standard flags from being linked into an
77/// working program.
78///
79/// ## Linker garbage collection {#bsls_linkcoercion-linker-garbage-collection}
80///
81///
82/// Modern linkers may implement link-time garbage collection. In order to
83/// minimize the size of the final executable the linker can remove sections of
84/// object files that are not referenced anywhere from the code being linked.
85/// Unfortunately, the link coercion symbols are not referenced directly and may
86/// be garbage collected and, if removed, lead to a silent failure and
87/// successful linkage of a potentially binary incompatible executable. To
88/// avoid such a failure, coercion symbols are placed in the dedicated data
89/// section (if supported by the compiler) and this section is marked in-use to
90/// avoid it being garbage collected by the linker.
91///
92/// More information on details on linker garbage collection can be found here:
93/// https://maskray.me/blog/2021-02-28-linker-garbage-collection
94///
95/// ## Usage {#bsls_linkcoercion-usage}
96///
97///
98/// In this section we show intended use of this component.
99///
100/// ### Example 1: Prevent Linking Debug and Optimized Translation Units {#bsls_linkcoercion-example-1-prevent-linking-debug-and-optimized-translation-units}
101///
102///
103/// In this example we use a link coercion symbol to prevent linking a
104/// translation unit built against the header in debug mode, with a translation
105/// unit built against the header in optimized mode.
106///
107/// First we define a macro such that our symbol name will be different for
108/// debug and optimized builds of our library:
109/// @code
110/// mylib_safecompile.h
111/// #ifdef NDEBUG
112/// #define MYLIB_DEBUG_SYMBOL_NAME mylib_BuiltWithNDebugMode
113/// #else
114/// #define MYLIB_DEBUG_SYMBOL_NAME mylib_BuiltWithoutNDebugMode
115/// #endif
116/// @endcode
117/// Now we use the `BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY` macro to require
118/// translation units to link against a library having a matching symbol name:
119/// @code
120/// extern const char* MYLIB_DEBUG_SYMBOL_NAME;
121/// BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(const char *,
122/// mylib_coercebasedondebugmode,
123/// MYLIB_DEBUG_SYMBOL_NAME )
124/// @endcode
125/// Note that the referred symbol will have a different name depending on
126/// whether `NDEBUG` is defined or not.
127///
128/// Finally, in the corresponding `.cpp` file we must define the appropriate
129/// symbol name for the library:
130/// @code
131/// mylib_safecompile.cpp
132/// const char *MYLIB_DEBUG_SYMBOL_NAME = "debug compatibility check: "
133/// #MYLIB_DEBUG_SYMBOL_NAME;
134/// @endcode
135/// @}
136/** @} */
137/** @} */
138
139/** @addtogroup bsl
140 * @{
141 */
142/** @addtogroup bsls
143 * @{
144 */
145/** @addtogroup bsls_linkcoercion
146 * @{
147 */
148
149#include <bsls_platform.h>
150
151
152
153#if defined(BSLS_PLATFORM_OS_LINUX)
154 // Note: we cannot detect the version of the binutils here, so we
155 // tie those specific attributes to the version of the compilers that
156 // should support them.
157 // Please see the "Linker garbage collection" section for details.
158 #if (defined(BSLS_PLATFORM_CMP_GNU) \
159 && BSLS_PLATFORM_CMP_VERSION >= 110000) \
160 || (defined(BSLS_PLATFORM_CMP_CLANG) \
161 && BSLS_PLATFORM_CMP_VERSION >= 130000)
162 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
163 refName, \
164 referredSymbol) \
165 _Pragma("GCC diagnostic push") \
166 _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
167 static type *dummyAcCeSs##refName() { \
168 return &referredSymbol; \
169 } \
170 static type *refName __attribute__((retain,used,section("coercion"))) \
171 = dummyAcCeSs##refName(); \
172 _Pragma("GCC diagnostic pop")
173 #else
174 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
175 refName, \
176 referredSymbol) \
177 static type *dummyAcCeSs##refName() { \
178 return &referredSymbol; \
179 } \
180 static type *refName __attribute__((used)) = dummyAcCeSs##refName();
181 #endif
182
183#elif defined(BSLS_PLATFORM_OS_DARWIN)
184 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
185 refName, \
186 referredSymbol) \
187 static type *dummyAcCeSs##refName() { \
188 return &referredSymbol; \
189 } \
190 static type *refName __attribute__((used)) = dummyAcCeSs##refName();
191#elif defined(BSLS_PLATFORM_CMP_IBM)
192 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
193 refName, \
194 referredSymbol) \
195 static type *refName = &referredSymbol;
196#elif defined(BSLS_PLATFORM_CMP_SUN)
197 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
198 refName, \
199 referredSymbol) \
200 type refName() __attribute__((weak)); \
201 type refName() { return referredSymbol; }
202#else
203 #define BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(type, \
204 refName, \
205 referredSymbol) \
206 namespace { \
207 extern type *const refName = &referredSymbol; \
208 }
209#endif
210
211
212
213#endif
214
215// ----------------------------------------------------------------------------
216// Copyright 2013 Bloomberg Finance L.P.
217//
218// Licensed under the Apache License, Version 2.0 (the "License");
219// you may not use this file except in compliance with the License.
220// You may obtain a copy of the License at
221//
222// http://www.apache.org/licenses/LICENSE-2.0
223//
224// Unless required by applicable law or agreed to in writing, software
225// distributed under the License is distributed on an "AS IS" BASIS,
226// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
227// See the License for the specific language governing permissions and
228// limitations under the License.
229// ----------------------------- END-OF-FILE ----------------------------------
230
231/** @} */
232/** @} */
233/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238