/src/mhd2/src/incl_priv/autoinit_funcs.h
Line | Count | Source |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ |
2 | | /* |
3 | | AutoinitFuncs: Automatic Initialisation and Deinitialisation Functions |
4 | | Copyright(C) 2014-2024 Karlson2k (Evgeny Grin) |
5 | | |
6 | | This header is free software; you can redistribute it and/or |
7 | | modify it under the terms of the GNU Lesser General Public |
8 | | License as published by the Free Software Foundation; either |
9 | | version 2.1 of the License, or (at your option) any later version. |
10 | | |
11 | | This header is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | Lesser General Public License for more details. |
15 | | |
16 | | Alternatively, you can redistribute GNU This header and/or |
17 | | modify it under the terms of the GNU General Public License as |
18 | | published by the Free Software Foundation; either version 2 of |
19 | | the License, or (at your option) any later version, together |
20 | | with the eCos exception, as follows: |
21 | | |
22 | | As a special exception, if other files instantiate templates or |
23 | | use macros or inline functions from this file, or you compile this |
24 | | file and link it with other works to produce a work based on this |
25 | | file, this file does not by itself cause the resulting work to be |
26 | | covered by the GNU General Public License. However the source code |
27 | | for this file must still be made available in accordance with |
28 | | section (3) of the GNU General Public License v2. |
29 | | |
30 | | This exception does not invalidate any other reasons why a work |
31 | | based on this file might be covered by the GNU General Public |
32 | | License. |
33 | | |
34 | | You should have received copies of the GNU Lesser General Public |
35 | | License and the GNU General Public License along with this header; |
36 | | if not, see <https://www.gnu.org/licenses/>. |
37 | | */ |
38 | | |
39 | | /* |
40 | | General usage is simple: include this header, define two functions |
41 | | with zero parameters (void) and any return type: one for initialisation and |
42 | | one for deinitialisation, add |
43 | | AIF_SET_INIT_AND_DEINIT_FUNCS(FuncInitName, FuncDeInitName) to the code, |
44 | | and functions will be automatically called during application startup |
45 | | and shutdown. |
46 | | This is useful for libraries as libraries don't have direct access |
47 | | to the main() function. |
48 | | |
49 | | Example: |
50 | | ------------------------------------------------- |
51 | | #include <stdlib.h> |
52 | | #include "autoinit_funcs.h" |
53 | | |
54 | | int someVar; |
55 | | void* somePtr; |
56 | | |
57 | | void libInit(void) |
58 | | { |
59 | | someVar = 3; |
60 | | // Calling other library functions could be unsafe the as the order |
61 | | // of initialisation of libraries is not strictly defined |
62 | | //somePtr = malloc(100); |
63 | | } |
64 | | |
65 | | void libDeinit(void) |
66 | | { |
67 | | // Calling other library functions could be unsafe |
68 | | //free(somePtr); |
69 | | } |
70 | | |
71 | | AIF_SET_INIT_AND_DEINIT_FUNCS(libInit,libDeinit); |
72 | | ------------------------------------------------- |
73 | | |
74 | | If initialiser or deinitialiser function is not needed, just use |
75 | | an empty function as a placeholder. |
76 | | |
77 | | This header should work with GCC, clang, MSVC (2010 or later) and |
78 | | SunPro / Sun Studio / Oracle Solaris Studio / Oracle Developer Studio |
79 | | compiler and other compatible compilers. |
80 | | Supported C and C++ languages; application, static and dynamic (DLL) |
81 | | libraries; non-optimized (Debug) and optimised (Release) compilation |
82 | | and linking. |
83 | | |
84 | | Besides the main macro mentioned above, the header defines other helper |
85 | | macros prefixed with AIF_. These macros can be used directly, but they |
86 | | are not designed to be defined externally. |
87 | | |
88 | | The header behaviour could be adjusted by defining various AUTOINIT_FUNCS_* |
89 | | macros before including the header. |
90 | | |
91 | | For more information see the header code and comments in the code. |
92 | | */ |
93 | | #ifndef AIF_HEADER_INCLUDED |
94 | | #define AIF_HEADER_INCLUDED 1 |
95 | | |
96 | | /** |
97 | | * The header version number in packed BCD form. |
98 | | * (For example, version 1.9.30-1 would be 0x01093001) |
99 | | */ |
100 | | #define AIF_VERSION 0x02000301 |
101 | | |
102 | | /* Define AUTOINIT_FUNCS_NO_WARNINGS to disable all custom warnings |
103 | | in this header */ |
104 | | #ifdef AUTOINIT_FUNCS_NO_WARNINGS |
105 | | # ifndef AUTOINIT_FUNCS_NO_WARNINGS_W32_ARCH |
106 | | # define AUTOINIT_FUNCS_NO_WARNINGS_W32_ARCH 1 |
107 | | # endif |
108 | | # ifndef AUTOINIT_FUNCS_NO_WARNINGS_SUNPRO_C |
109 | | # define AUTOINIT_FUNCS_NO_WARNINGS_SUNPRO_C 1 |
110 | | # endif |
111 | | #endif |
112 | | |
113 | | /* If possible - check for supported attributes */ |
114 | | #ifdef __has_attribute |
115 | | # if __has_attribute (constructor) && __has_attribute (destructor) |
116 | | # define AIF_GNUC_ATTR_CONSTR_SUPPORTED 1 |
117 | | # else /* ! __has_attribute (constructor) || ! __has_attribute (destructor) */ |
118 | | # define AIF_GNUC_ATTR_CONSTR_NOT_SUPPORTED 1 |
119 | | # endif /* ! __has_attribute (constructor) || ! __has_attribute (destructor) */ |
120 | | #endif /* __has_attribute */ |
121 | | |
122 | | #if defined(__GNUC__) && __GNUC__ < 2 \ |
123 | | && !defined(AIF_GNUC_ATTR_CONSTR_NOT_SUPPORTED) \ |
124 | | && !defined(AIF_GNUC_ATTR_CONSTR_SUPPORTED) |
125 | | # define AIF_GNUC_ATTR_CONSTR_NOT_SUPPORTED 1 |
126 | | #endif |
127 | | |
128 | | /* "__has_attribute__ ((constructor))" is supported by GCC, clang and |
129 | | Sun/Oracle compiler starting from version 12.1. */ |
130 | | #if (defined(AIF_GNUC_ATTR_CONSTR_SUPPORTED) \ |
131 | | || defined(__GNUC__) || defined(__clang__) \ |
132 | | || (defined(__SUNPRO_C) && __SUNPRO_C + 0 >= 0x5100)) && \ |
133 | | !defined(AIF_GNUC_ATTR_CONSTR_NOT_SUPPORTED) |
134 | | |
135 | | # define AIF_GNUC_SET_INIT_AND_DEINIT(FI, FD) \ |
136 | | void __attribute__ ((constructor)) AIF_GNUC_init_helper_ ## FI (void); \ |
137 | | void __attribute__ ((destructor)) AIF_GNUC_deinit_helper_ ## FD (void); \ |
138 | | void __attribute__ ((constructor)) AIF_GNUC_init_helper_ ## FI (void) \ |
139 | 4 | { (void) (FI) (); } \ |
140 | | void __attribute__ ((destructor)) AIF_GNUC_deinit_helper_ ## FD (void) \ |
141 | 0 | { (void) (FD) (); } \ |
142 | | struct AIF_GNUC_dummy_str_ ## FI {int i;} |
143 | | |
144 | | #elif defined(_WIN32) && defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1600 && \ |
145 | | !defined(__CYGWIN__) |
146 | | |
147 | | /* Make sure that your project/sources define: |
148 | | _LIB if building a static library (_LIB is ignored if _CONSOLE is defined); |
149 | | _USRDLL if building DLL-library; |
150 | | not defined both _LIB and _USRDLL if building an application */ |
151 | | |
152 | | /* Stringify macros */ |
153 | | # define AIF_INSTRMACRO(a) #a /* Strigify helper */ |
154 | | # define AIF_STRMACRO(a) AIF_INSTRMACRO (a) /* Expand and strigify */ |
155 | | |
156 | | /* Concatenate macros */ |
157 | | # define AIF_INCONCAT(a, b) a ## b /* Concatenate helper */ |
158 | | # define AIF_CONCAT(a, b) AIF_INCONCAT (a,b) /* Expand and concatenate */ |
159 | | |
160 | | /* Use "C" linkage for variables to simplify symbols decoration */ |
161 | | # ifdef __cplusplus |
162 | | # define AIF_W32_INITVARDECL extern "C" |
163 | | # define AIF_W32_INITHELPERFUNCDECL static |
164 | | # else |
165 | | # define AIF_W32_INITVARDECL extern |
166 | | # define AIF_W32_INITHELPERFUNCDECL static |
167 | | # endif |
168 | | |
169 | | /* How variables are decorated by compiler */ |
170 | | # if (defined(_WIN32) || defined(_WIN64)) \ |
171 | | && !defined(_M_IX86) && !defined(_X86_) |
172 | | # if !defined(_M_X64) && !defined(_M_AMD64) && !defined(_x86_64_) \ |
173 | | && !defined(_M_ARM) && !defined(_M_ARM64) |
174 | | # ifndef AUTOINIT_FUNCS_NO_WARNINGS_W32_ARCH |
175 | | # pragma \ |
176 | | message(__FILE__ "(" AIF_STRMACRO(__LINE__) ") : warning AIFW001 : " \ |
177 | | "Untested architecture, linker may fail with unresolved symbols") |
178 | | # endif /* ! AUTOINIT_FUNCS_NO_WARNINGS_W32_ARCH */ |
179 | | # endif /* ! _M_X64 && ! _M_AMD64 && ! _x86_64_ && ! _M_ARM && ! _M_ARM64 */ |
180 | | # define AIF_W32_VARDECORPREFIX |
181 | | # define AIF_W32_DECORVARNAME(v) v |
182 | | # define AIF_W32_VARDECORPREFIXSTR "" |
183 | | # elif defined(_WIN32) && (defined(_M_IX86) || defined(_X86_)) |
184 | | # define AIF_W32_VARDECORPREFIX _ |
185 | | # define AIF_W32_DECORVARNAME(v) _ ## v |
186 | | # define AIF_W32_VARDECORPREFIXSTR "_" |
187 | | # else |
188 | | # error Do not know how to decorate symbols for this architecture |
189 | | # endif |
190 | | |
191 | | |
192 | | /* Internal variable prefix (can be any) */ |
193 | | # define AIF_W32_INITHELPERVARNAME(f) _aif_init_ptr_ ## f |
194 | | # define AIF_W32_INITHELPERVARNAMEDECORSTR(f) \ |
195 | | AIF_W32_VARDECORPREFIXSTR AIF_STRMACRO (AIF_W32_INITHELPERVARNAME (f)) |
196 | | |
197 | | |
198 | | /* Sections (segments) for pointers to initialisers */ |
199 | | |
200 | | /* Semi-officially suggested section for early initialisers (called before |
201 | | C++ objects initialisers), "void" return type */ |
202 | | # define AIF_W32_SEG_STAT_INIT_EARLY1 ".CRT$XCT" |
203 | | /* Guessed section name for early initialisers (called before |
204 | | C++ objects initialisers, after first initialisers), "void" return type */ |
205 | | # define AIF_W32_SEG_STAT_INIT_EARLY2 ".CRT$XCTa" |
206 | | /* Semi-officially suggested section for late initialisers (called after |
207 | | C++ objects initialisers), "void" return type */ |
208 | | # define AIF_W32_SEG_STAT_INIT_LATE ".CRT$XCV" |
209 | | |
210 | | /* Unsafe sections (segments) for pointers to initialisers */ |
211 | | |
212 | | /* C++ lib initialisers, "void" return type (reserved by the system!) */ |
213 | | # define AIF_W32_SEG_STAT_INIT_CXX_LIB ".CRT$XCL" |
214 | | /* C++ user initialisers, "void" return type (reserved by the system!) */ |
215 | | # define AIF_W32_SEG_STAT_INIT_CXX_USER ".CRT$XCU" |
216 | | |
217 | | /* Declare section (segment), put variable pointing to init function to |
218 | | chosen segment, force linker to always include variable to avoid omitting |
219 | | by optimiser */ |
220 | | /* These initialisation function must be declared as |
221 | | void __cdecl FuncName(void) */ |
222 | | /* Note: "extern" with initialisation value means that variable is declared AND |
223 | | defined. */ |
224 | | # define AIF_W32_INIT_VFPTR_IN_SEG(S, F) \ |
225 | | __pragma(section(S, long, read)) \ |
226 | | __pragma(comment(linker, "/INCLUDE:" \ |
227 | | AIF_W32_INITHELPERVARNAMEDECORSTR (F))) \ |
228 | | AIF_W32_INITVARDECL __declspec(allocate (S)) void \ |
229 | | (__cdecl * AIF_W32_INITHELPERVARNAME (F))(void) = &F |
230 | | |
231 | | /* Unsafe sections (segments) for pointers to initialisers with |
232 | | "int" return type */ |
233 | | |
234 | | /* C lib initialisers, "int" return type (reserved by the system!). |
235 | | These initialisers are called before others. */ |
236 | | # define AIF_W32_SEG_STAT_INIT_C_LIB ".CRT$XIL" |
237 | | /* C user initialisers, "int" return type (reserved by the system!). |
238 | | These initialisers are called before others. */ |
239 | | # define AIF_W32_SEG_STAT_INIT_C_USER ".CRT$XIU" |
240 | | |
241 | | /* Declare section (segment), put variable pointing to init function to |
242 | | chosen segment, force linker to always include variable to avoid omitting |
243 | | by optimiser */ |
244 | | /* These initialisation function must be declared as |
245 | | int __cdecl FuncName(void) */ |
246 | | /* Startup process is aborted if initialiser returns non-zero */ |
247 | | /* Note: "extern" with initialisation value means that variable is declared AND |
248 | | defined. */ |
249 | | # define AIF_W32_INIT_IFPTR_IN_SEG(S, F) \ |
250 | | __pragma(section(S, long, read)) \ |
251 | | __pragma(comment(linker, \ |
252 | | "/INCLUDE:" AIF_W32_INITHELPERVARNAMEDECORSTR (F))) \ |
253 | | AIF_W32_INITVARDECL __declspec(allocate (S)) int \ |
254 | | (__cdecl * AIF_W32_INITHELPERVARNAME (F))(void) = &F |
255 | | |
256 | | /* Not recommended / unsafe */ |
257 | | /* "lib" initialisers are called before "user" initialisers */ |
258 | | /* "C" initialisers are called before "C++" initialisers */ |
259 | | # define AIF_W32_REG_STAT_INIT_C_USER(F) \ |
260 | | AIF_W32_FPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_C_USER,F) |
261 | | # define AIF_W32_REG_STAT_INIT_C_LIB(F) \ |
262 | | AIF_W32_FPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_C_LIB,F) |
263 | | # define AIF_W32_REG_STAT_INIT_CXX_USER(F) \ |
264 | | AIF_W32_FPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_CXX_USER,F) |
265 | | # define AIF_W32_REG_STAT_INIT_CXX_LIB(F) \ |
266 | | AIF_W32_FPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_CXX_LIB,F) |
267 | | |
268 | | /* Declare macros for different initialisers sections */ |
269 | | |
270 | | /* Macro can be used several times to register several initialisers */ |
271 | | /* Once function is registered as initialiser, it will be called automatically |
272 | | during application startup or library loading */ |
273 | | # define AIF_W32_REG_STAT_INIT_EARLY1(F) \ |
274 | | AIF_W32_INIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_EARLY1,F) |
275 | | # define AIF_W32_REG_STAT_INIT_EARLY2(F) \ |
276 | | AIF_W32_INIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_EARLY2,F) |
277 | | # define AIF_W32_REG_STAT_INIT_LATE(F) \ |
278 | | AIF_W32_INIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_INIT_LATE,F) |
279 | | |
280 | | # ifndef _DLL |
281 | | /* Sections (segments) for pointers to deinitialisers */ |
282 | | |
283 | | /* These section are not used when common rutime (CRT, the C library) is used |
284 | | as DLL. In such case only sections in CRT DLL are used for deinitialisation |
285 | | pointers. */ |
286 | | |
287 | | /* The section name based on semi-documented deinitialisation procedure, |
288 | | functions called before first C deinitialisers, "void" return type */ |
289 | | # define AIF_W32_SEG_STAT_DEINIT_FIRST ".CRT$XPAa" |
290 | | /* The section name based on semi-documented deinitialisation procedure, |
291 | | functions called after AIF_W32_SEG_STAT_DEINIT_FIRST deinitialisers and |
292 | | before first C deinitialisers, "void" return type */ |
293 | | # define AIF_W32_SEG_STAT_DEINIT_SECOND ".CRT$XPAb" |
294 | | /* The section name based on semi-documented deinitialisation procedure, |
295 | | functions called after AIF_W32_SEG_STAT_DEINIT_SECOND deinitialisers and |
296 | | before first C deinitialisers, "void" return type */ |
297 | | # define AIF_W32_SEG_STAT_DEINIT_THIRD ".CRT$XPAc" |
298 | | |
299 | | /* Internal variable prefix (can be any) */ |
300 | | # define AIF_W32_DEINITHELPERVARNAME(f) _aif_deinit_ptr_ ## f |
301 | | # define AIF_W32_DEINITHELPERVARNAMEDECORSTR(f) \ |
302 | | AIF_W32_VARDECORPREFIXSTR AIF_STRMACRO (AIF_W32_DEINITHELPERVARNAME (f)) |
303 | | |
304 | | /* The macro to declare section (segment), put variable pointing to deinit |
305 | | function to chosen segment, force linker to always include variable to |
306 | | avoid omitting by optimiser */ |
307 | | /* These deinitialisation function must be declared as |
308 | | void __cdecl FuncName(void) */ |
309 | | /* Note: "extern" with initialisation value means that variable is declared AND |
310 | | defined. */ |
311 | | # define AIF_W32_DEINIT_VFPTR_IN_SEG(S, F) \ |
312 | | __pragma(section(S, long, read)) \ |
313 | | __pragma(comment(linker, "/INCLUDE:" \ |
314 | | AIF_W32_DEINITHELPERVARNAMEDECORSTR (F))) \ |
315 | | AIF_W32_INITVARDECL __declspec(allocate (S)) void \ |
316 | | (__cdecl * AIF_W32_DEINITHELPERVARNAME (F))(void) = &F |
317 | | |
318 | | /* Declare macros for different deinitialisers sections */ |
319 | | /* Macro can be used several times to register several deinitialisers */ |
320 | | /* Once function is registered as initialiser, it will be called automatically |
321 | | during application shutdown or library unloading */ |
322 | | # define AIF_W32_REG_STAT_DEINIT_EARLY(F) \ |
323 | | AIF_W32_DEINIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_DEINIT_FIRST,F) |
324 | | # define AIF_W32_REG_STAT_DEINIT_LATE1(F) \ |
325 | | AIF_W32_DEINIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_DEINIT_SECOND,F) |
326 | | # define AIF_W32_REG_STAT_DEINIT_LATE2(F) \ |
327 | | AIF_W32_DEINIT_VFPTR_IN_SEG (AIF_W32_SEG_STAT_DEINIT_THIRD,F) |
328 | | |
329 | | # endif /* ! _DLL */ |
330 | | |
331 | | /* Choose main register macro based on language and program type */ |
332 | | /* Assuming that _LIB or _USRDLL is defined for static or DLL-library */ |
333 | | /* Macro can be used several times to register several initialisers */ |
334 | | /* Once function is registered as initialiser, it will be called automatically |
335 | | during application startup */ |
336 | | /* Define AUTOINIT_FUNCS_FORCE_EARLY_INIT to force register as early |
337 | | initialiser */ |
338 | | /* Define AUTOINIT_FUNCS_FORCE_LATE_INIT to force register as late |
339 | | initialiser */ |
340 | | /* By default C++ static or DLL-library code and any C code and will be |
341 | | registered as early initialiser, while C++ non-library code will be |
342 | | registered as late initialiser */ |
343 | | # if (!defined(__cplusplus) || \ |
344 | | defined(_LIB) || defined(_USRDLL) || \ |
345 | | defined(AUTOINIT_FUNCS_FORCE_EARLY_INIT)) && \ |
346 | | !defined(AUTOINIT_FUNCS_FORCE_LATE_INIT) |
347 | | /* Use early initialiser and late deinitialiser */ |
348 | | # if defined(_LIB) || defined(_USRDLL) |
349 | | /* Static or DLL library */ |
350 | | # define AIF_W32_REGISTER_STAT_INIT(F) AIF_W32_REG_STAT_INIT_EARLY1 (F) |
351 | | # ifdef AIF_W32_REG_STAT_DEINIT_LATE2 |
352 | | # define AIF_W32_REGISTER_STAT_DEINIT(F) \ |
353 | | AIF_W32_REG_STAT_DEINIT_LATE2 (F) |
354 | | # endif |
355 | | # else |
356 | | /* Application code */ |
357 | | # define AIF_W32_REGISTER_STAT_INIT(F) AIF_W32_REG_STAT_INIT_EARLY2 (F) |
358 | | # ifdef AIF_W32_REG_STAT_DEINIT_LATE1 |
359 | | # define AIF_W32_REGISTER_STAT_DEINIT(F) \ |
360 | | AIF_W32_REG_STAT_DEINIT_LATE1 (F) |
361 | | # endif |
362 | | # endif |
363 | | # else |
364 | | /* Use late initialiser and early deinitialiser */ |
365 | | # define AIF_W32_REGISTER_STAT_INIT(F) AIF_W32_REG_STAT_INIT_LATE (F) |
366 | | # ifdef AIF_W32_REG_STAT_DEINIT_EARLY |
367 | | # define AIF_W32_REGISTER_STAT_DEINIT(F) \ |
368 | | AIF_W32_REG_STAT_DEINIT_EARLY (F) |
369 | | # endif |
370 | | # endif |
371 | | |
372 | | |
373 | | /* Static deinit registration on W32 could be risky as it works only |
374 | | if CRT is used as static lib (not as DLL) and relies on correct |
375 | | definition of "_DLL" macro by build system. */ |
376 | | /* If "_DLL" macro is correctly defined, static deinitialiser registration |
377 | | can be enabled by defining AUTOINIT_FUNCS_ALLOW_W32_STAT_DEINIT macro. |
378 | | If it is used, it can save from including an extra header. */ |
379 | | # if defined(AIF_W32_REGISTER_STAT_DEINIT) \ |
380 | | && defined(AUTOINIT_FUNCS_ALLOW_W32_STAT_DEINIT) |
381 | | # define AIF_W32_SET_STAT_INIT_AND_DEINIT(FI, FD) \ |
382 | | AIF_W32_INITHELPERFUNCDECL void \ |
383 | | __cdecl AIF_W32_stat_init_helper_ ## FI (void); \ |
384 | | AIF_W32_INITHELPERFUNCDECL void \ |
385 | | __cdecl AIF_W32_stat_deinit_helper_ ## FD (void); \ |
386 | | AIF_W32_INITHELPERFUNCDECL void \ |
387 | | __cdecl AIF_W32_stat_init_helper_ ## FI (void) \ |
388 | | { (void) (FI) (); } \ |
389 | | AIF_W32_INITHELPERFUNCDECL void \ |
390 | | __cdecl AIF_W32_stat_deinit_helper_ ## FD (void) \ |
391 | | { (void) (FD) (); } \ |
392 | | AIF_W32_REGISTER_STAT_INIT (AIF_W32_stat_init_helper_ ## FI); \ |
393 | | AIF_W32_REGISTER_STAT_DEINIT (AIF_W32_stat_deinit_helper_ ## FD) |
394 | | # else |
395 | | |
396 | | /* Note: 'atexit()' is just a wrapper for '_onexit()' on W32 */ |
397 | | # include <stdlib.h> /* required for _onexit() */ |
398 | | |
399 | | # define AIF_W32_SET_STAT_INIT_AND_DEINIT(FI, FD) \ |
400 | | AIF_W32_INITHELPERFUNCDECL void \ |
401 | | __cdecl AIF_W32_stat_init_helper_ ## FI (void); \ |
402 | | AIF_W32_INITHELPERFUNCDECL int \ |
403 | | __cdecl AIF_W32_stat_deinit_helper_ ## FD (void); \ |
404 | | AIF_W32_INITHELPERFUNCDECL void \ |
405 | | __cdecl AIF_W32_stat_init_helper_ ## FI (void) \ |
406 | | { (void) (FI) (); \ |
407 | | _onexit (&AIF_W32_stat_deinit_helper_ ## FD); } \ |
408 | | AIF_W32_INITHELPERFUNCDECL int \ |
409 | | __cdecl AIF_W32_stat_deinit_helper_ ## FD (void) \ |
410 | | { (void) (FD) (); return ! 0; } \ |
411 | | AIF_W32_REGISTER_STAT_INIT (AIF_W32_stat_init_helper_ ## FI) |
412 | | # endif |
413 | | |
414 | | #endif /* _WIN32 && _MSC_VER + 0 >= 1600 && ! _GNUC_ATTR_CONSTR_SUPPORTED */ |
415 | | |
416 | | |
417 | | #if defined(_WIN32) && !defined(__CYGWIN__) && \ |
418 | | (defined(_USRDLL) || defined(DLL_EXPORT)) |
419 | | |
420 | | # if defined(__MINGW32__) || defined(__MINGW64__) |
421 | | /* The minimal portable set of the headers to pull in the definitions of "BOOL", |
422 | | "WINAPI", "HINSTANCE", "DWORD" and "LPVOID" */ |
423 | | /* Thi minimal set does not work with MS headers as they depend on some vital |
424 | | macros defined only in the "windows.h" header only */ |
425 | | # include <windef.h> |
426 | | # include <winnt.h> |
427 | | # else |
428 | | # ifndef WIN32_LEAN_AND_MEAN |
429 | | # define WIN32_LEAN_AND_MEAN 1 |
430 | | # endif |
431 | | # include <windows.h> |
432 | | # endif |
433 | | |
434 | | # ifdef DLL_PROCESS_ATTACH |
435 | | # define AIF_W32_DLL_PROCESS_ATTACH DLL_PROCESS_ATTACH |
436 | | # else |
437 | | # define AIF_W32_DLL_PROCESS_ATTACH 1 |
438 | | # endif |
439 | | # if defined(DLL_PROCESS_DETACH) |
440 | | # define AIF_W32_DLL_PROCESS_DETACH DLL_PROCESS_DETACH |
441 | | # else |
442 | | # define AIF_W32_DLL_PROCESS_DETACH 0 |
443 | | # endif |
444 | | |
445 | | /* When process is terminating, DLL should not perform a cleanup, leaving |
446 | | allocated resources to be cleaned by the system. This is because some |
447 | | threads may be explicitly terminated without proper cleanup, and some |
448 | | system resources, including process heap, could be in inconsistent state. |
449 | | Define AUTOINIT_FUNCS_USE_UNSAFE_DLL_DEINIT to enable calling of deinit |
450 | | function such situations. |
451 | | Note: if AUTOINIT_FUNCS_USE_UNSAFE_DLL_DEINIT is defined and the DLL is |
452 | | delay-loaded, then both the initialiser and the deinitialiser could be |
453 | | called late (or last), breaking requirement for calling deinitialisers in |
454 | | reverse order of initialisers. */ |
455 | | # ifndef AUTOINIT_FUNCS_USE_UNSAFE_DLL_DEINIT |
456 | | # define AIF_W32_IS_DLL_DEINIT_SAFE(pReserved) (NULL == (pReserved)) |
457 | | # else |
458 | | # define AIF_W32_IS_DLL_DEINIT_SAFE(pReserved) TRUE |
459 | | # endif |
460 | | |
461 | | /* If DllMain is already present in user's code, |
462 | | define AUTOINIT_FUNCS_CALL_USR_DLLMAIN and |
463 | | rename user's DllMain to usr_DllMain. |
464 | | The usr_DllMain() must be declared (or full defined) before using the macro |
465 | | for setting initialiser and deinitialiser. Alternatively, if usr_DllMain() |
466 | | is another file (or after the macro), define macro |
467 | | AUTOINIT_FUNCS_DECLARE_USR_DLLMAIN to enable automatic declaration of this |
468 | | function. |
469 | | Define AUTOINIT_FUNCS_USR_DLLMAIN_NAME to user function name if usr_DllMain |
470 | | is not suitable. */ |
471 | | # ifndef AUTOINIT_FUNCS_CALL_USR_DLLMAIN |
472 | | # define AIF_W32_CALL_USER_DLLMAIN(h, r, p) TRUE |
473 | | # else /* AUTOINIT_FUNCS_CALL_USR_DLLMAIN */ |
474 | | # ifndef AUTOINIT_FUNCS_USR_DLLMAIN_NAME |
475 | | # define AIF_W32_USR_DLLMAIN_NAME usr_DllMain |
476 | | # else |
477 | | # define AIF_W32_USR_DLLMAIN_NAME AUTOINIT_FUNCS_USR_DLLMAIN_NAME |
478 | | # endif |
479 | | # define AIF_W32_CALL_USER_DLLMAIN(h, r, p) \ |
480 | | AIF_W32_USR_DLLMAIN_NAME ((h),(r),(p)) |
481 | | # ifdef AUTOINIT_FUNCS_DECLARE_USR_DLLMAIN |
482 | | # define AIF_DECL_USR_DLLMAIN \ |
483 | | BOOL WINAPI AIF_W32_USR_DLLMAIN_NAME (HINSTANCE hinst, DWORD reason, \ |
484 | | LPVOID pReserved); |
485 | | # endif |
486 | | # endif /* AUTOINIT_FUNCS_CALL_USR_DLLMAIN */ |
487 | | |
488 | | # ifndef AIF_DECL_USR_DLLMAIN |
489 | | # define AIF_DECL_USR_DLLMAIN /* empty */ |
490 | | # endif |
491 | | |
492 | | # define AIF_W32_SET_DLL_INIT_AND_DEINIT(FI, FD) \ |
493 | | BOOL WINAPI DllMain (HINSTANCE hinst, DWORD reason, LPVOID pReserved); \ |
494 | | AIF_DECL_USR_DLLMAIN \ |
495 | | BOOL WINAPI DllMain (HINSTANCE hinst, DWORD reason, LPVOID pReserved) \ |
496 | | { BOOL aif_ret; (void) hinst; \ |
497 | | if (AIF_W32_DLL_PROCESS_ATTACH == reason) { \ |
498 | | (void) (FI) (); \ |
499 | | aif_ret = AIF_W32_CALL_USER_DLLMAIN (hinst, reason, pReserved); \ |
500 | | if (! aif_ret && NULL != pReserved) { (void) (FD) (); } } \ |
501 | | else if (AIF_W32_DLL_PROCESS_DETACH == reason) { \ |
502 | | aif_ret = AIF_W32_CALL_USER_DLLMAIN (hinst, reason, pReserved); \ |
503 | | if (AIF_W32_IS_DLL_DEINIT_SAFE (pReserved)) { (void) (FD) (); } } \ |
504 | | else aif_ret = AIF_W32_CALL_USER_DLLMAIN (hinst, reason, pReserved); \ |
505 | | return aif_ret; \ |
506 | | } struct AIF_W32_dummy_strc_ ## FI {int i;} |
507 | | #endif /* _WIN32 && ! __CYGWIN__ && (_USRDLL || DLL_EXPORT) */ |
508 | | |
509 | | |
510 | | /* Define AUTOINIT_FUNCS_FORCE_STATIC_REG if you want to set main macro |
511 | | AIF_SET_INIT_AND_DEINIT_FUNCS to static version even if building a DLL. |
512 | | Static registration works for DLL too, but less precise and flexible. */ |
513 | | |
514 | | #if defined(AIF_W32_SET_DLL_INIT_AND_DEINIT) \ |
515 | | && !(defined(AUTOINIT_FUNCS_PREFER_STATIC_REG) \ |
516 | | && (defined(AIF_GNUC_SET_INIT_AND_DEINIT) \ |
517 | | || defined(AIF_W32_SET_STAT_INIT_AND_DEINIT))) |
518 | | |
519 | | # define AIF_SET_INIT_AND_DEINIT_FUNCS(FI, FD) \ |
520 | | AIF_W32_SET_DLL_INIT_AND_DEINIT (FI,FD) |
521 | | /* Indicate that automatic initialisers/deinitialisers are supported */ |
522 | | # define AIF_AUTOINIT_FUNCS_ARE_SUPPORTED 1 |
523 | | |
524 | | #elif defined(AIF_GNUC_SET_INIT_AND_DEINIT) |
525 | | |
526 | | # define AIF_SET_INIT_AND_DEINIT_FUNCS(FI, FD) \ |
527 | | AIF_GNUC_SET_INIT_AND_DEINIT (FI,FD) |
528 | | /* Indicate that automatic initialisers/deinitialisers are supported */ |
529 | | # define AIF_AUTOINIT_FUNCS_ARE_SUPPORTED 1 |
530 | | |
531 | | #elif defined(AIF_W32_SET_STAT_INIT_AND_DEINIT) |
532 | | |
533 | | # define AIF_SET_INIT_AND_DEINIT_FUNCS(FI, FD) \ |
534 | | AIF_W32_SET_STAT_INIT_AND_DEINIT (FI,FD) |
535 | | /* Indicate that automatic initialisers/deinitialisers are supported */ |
536 | | # define AIF_AUTOINIT_FUNCS_ARE_SUPPORTED 1 |
537 | | |
538 | | #else |
539 | | |
540 | | /* Define AUTOINIT_FUNCS_EMIT_ERROR_IF_NOT_SUPPORTED before inclusion of |
541 | | this header to abort compilation if automatic initialisers/deinitialisers |
542 | | are not supported */ |
543 | | # ifdef AUTOINIT_FUNCS_EMIT_ERROR_IF_NOT_SUPPORTED |
544 | | # error User-defined initialiser and deinitialiser functions not supported |
545 | | # endif /* AUTOINIT_FUNCS_EMIT_ERROR_IF_NOT_SUPPORTED */ |
546 | | |
547 | | # if defined(__SUNPRO_C) && (defined(sun) || defined(__sun)) \ |
548 | | && (defined(__SVR4) || defined(__svr4__)) |
549 | | /* "#parama init(func_name)" can be used. "func_name" must be declared. |
550 | | The form is "void func_name(void)". */ |
551 | | # define AIF_PRAGMA_INIT_SUPPORTED 1 |
552 | | /* "#parama fini(func_name)" can be used. "func_name" must be declared. |
553 | | The form is "void func_name(void)". */ |
554 | | # define AIF_PRAGMA_FINI_SUPPORTED 1 |
555 | | # if !defined(AUTOINIT_FUNCS_NO_WARNINGS_SUNPRO_C) |
556 | | # warning Compiler supports "#pragma init(func)" and "#pragma fini(func)" |
557 | | # warning Use "pragma" to set initialiser and deinitialiser functions |
558 | | # endif |
559 | | # endif |
560 | | |
561 | | /* "Not supported" implementation */ |
562 | | # define AIF_SET_INIT_AND_DEINIT_FUNCS(FI, FD) /* No-op */ |
563 | | /* Indicate that automatic initialisers/deinitialisers are not supported */ |
564 | | # define AIF_AUTOINIT_FUNCS_ARE_NOT_SUPPORTED 1 |
565 | | |
566 | | #endif |
567 | | #endif /* !AIF_HEADER_INCLUDED */ |