|
Packit |
875988 |
/*
|
|
Packit |
875988 |
* AutoinitFuncs: Automatic Initialization and Deinitialization Functions
|
|
Packit |
875988 |
* Copyright(C) 2014-2017 Karlson2k (Evgeny Grin)
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* This header is free software; you can redistribute it and / or
|
|
Packit |
875988 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
875988 |
* License as published by the Free Software Foundation; either
|
|
Packit |
875988 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* This header is distributed in the hope that it will be useful,
|
|
Packit |
875988 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
875988 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
875988 |
* Lesser General Public License for more details.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
875988 |
* License along with this header; if not, see
|
|
Packit |
875988 |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/*
|
|
Packit |
875988 |
General usage is simple: include this header, declare or define two
|
|
Packit |
875988 |
functions with zero parameters (void) and any return type: one for
|
|
Packit |
875988 |
initialization and one for deinitialization, add
|
|
Packit |
875988 |
_SET_INIT_AND_DEINIT_FUNCS(FuncInitName, FuncDeInitName) to the code
|
|
Packit |
875988 |
and functions will be automatically called during application startup
|
|
Packit |
875988 |
and shutdown.
|
|
Packit |
875988 |
This is useful for libraries as libraries doesn't have direct access
|
|
Packit |
875988 |
to main() functions.
|
|
Packit |
875988 |
Example:
|
|
Packit |
875988 |
-------------------------------------------------
|
|
Packit |
875988 |
#include <stdlib.h>
|
|
Packit |
875988 |
#include "autoinit_funcs.h"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
int someVar;
|
|
Packit |
875988 |
void* somePtr;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
void libInit(void)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
someVar = 3;
|
|
Packit |
875988 |
somePtr = malloc(100);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
void libDeinit(void)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free(somePtr);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
_SET_INIT_AND_DEINIT_FUNCS(libInit,libDeinit);
|
|
Packit |
875988 |
-------------------------------------------------
|
|
Packit |
875988 |
|
|
Packit |
875988 |
If initializer or deinitializer function is not needed, just define
|
|
Packit |
875988 |
it as empty function.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This header should work with GCC, clang, MSVC (2010 or later) and
|
|
Packit |
875988 |
SunPro / Sun Studio / Oracle Solaris Studio / Oracle Developer Studio
|
|
Packit |
875988 |
compiler.
|
|
Packit |
875988 |
Supported C and C++ languages; application, static and dynamic (DLL)
|
|
Packit |
875988 |
libraries; non-optimized (Debug) and optimized (Release) compilation
|
|
Packit |
875988 |
and linking.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
For more information see header code and comments in code.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#ifndef AUTOINIT_FUNCS_INCLUDED
|
|
Packit |
875988 |
#define AUTOINIT_FUNCS_INCLUDED 1
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Current version of the header.
|
|
Packit |
875988 |
* 0x01093001 = 1.9.30-1.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define AUTOINIT_FUNCS_VERSION 0x01000100
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if defined(__GNUC__)
|
|
Packit |
875988 |
/* if possible - check for supported attribute */
|
|
Packit |
875988 |
#ifdef __has_attribute
|
|
Packit |
875988 |
#if !__has_attribute(constructor) || !__has_attribute(destructor)
|
|
Packit |
875988 |
#define _GNUC_ATTR_CONSTR_NOT_SUPPORTED 1
|
|
Packit |
875988 |
#endif /* !__has_attribute(constructor) || !__has_attribute(destructor) */
|
|
Packit |
875988 |
#endif /* __has_attribute */
|
|
Packit |
875988 |
#endif /* __GNUC__ */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* "_attribute__ ((constructor))" is supported by GCC, clang and
|
|
Packit |
875988 |
Sun/Oracle compiler starting from version 12.1. */
|
|
Packit |
875988 |
#if (defined(__GNUC__) && !defined(_GNUC_ATTR_CONSTR_NOT_SUPPORTED)) || \
|
|
Packit |
875988 |
(defined(__SUNPRO_C) && __SUNPRO_C+0 >= 0x5100)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#define GNUC_SET_INIT_AND_DEINIT(FI,FD) \
|
|
Packit |
875988 |
void __attribute__ ((constructor)) _GNUC_init_helper_##FI(void) \
|
|
Packit |
875988 |
{ (void)(FI)(); } \
|
|
Packit |
875988 |
void __attribute__ ((destructor)) _GNUC_deinit_helper_##FD(void) \
|
|
Packit |
875988 |
{ (void)(FD)(); } \
|
|
Packit |
875988 |
struct _GNUC_dummy_str_##FI{int i;}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#define _SET_INIT_AND_DEINIT_FUNCS(FI,FD) GNUC_SET_INIT_AND_DEINIT(FI,FD)
|
|
Packit |
875988 |
#define _AUTOINIT_FUNCS_ARE_SUPPORTED 1
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#elif defined (_MSC_FULL_VER) && _MSC_VER+0 >= 1600
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Make sure that your project/sources define:
|
|
Packit |
875988 |
_LIB if building a static library (_LIB is ignored if _CONSOLE is defined);
|
|
Packit |
875988 |
_USRDLL if building DLL-library;
|
|
Packit |
875988 |
not defined both _LIB and _USRDLL if building an application */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Define AUTOINIT_FUNCS_DECLARE_STATIC_REG if you need macro declaration
|
|
Packit |
875988 |
for registering static initialization functions even if you building DLL */
|
|
Packit |
875988 |
/* Define AUTOINIT_FUNCS_FORCE_STATIC_REG if you want to set main macro
|
|
Packit |
875988 |
_SET_INIT_AND_DEINIT_FUNCS to static version even if building a DLL*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Stringify macros */
|
|
Packit |
875988 |
#define _INSTRMACRO(a) #a
|
|
Packit |
875988 |
#define _STRMACRO(a) _INSTRMACRO(a)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if !defined(_USRDLL) || defined(AUTOINIT_FUNCS_DECLARE_STATIC_REG)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* required for atexit() */
|
|
Packit |
875988 |
#include <stdlib.h>
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Use "C" linkage for variable to simplify variable decoration */
|
|
Packit |
875988 |
#ifdef __cplusplus
|
|
Packit |
875988 |
#define W32_INITVARDECL extern "C"
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
#define W32_INITVARDECL extern
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* How variable is decorated by compiler */
|
|
Packit |
875988 |
#if defined(_M_X64) || defined(_M_AMD64)
|
|
Packit |
875988 |
#define W32_VARDECORPREFIX
|
|
Packit |
875988 |
#define W32_DECORVARNAME(v) v
|
|
Packit |
875988 |
#define W32_VARDECORPEFIXSTR ""
|
|
Packit |
875988 |
#elif defined(_M_IX86) || defined(_X86_)
|
|
Packit |
875988 |
#define W32_VARDECORPREFIX _
|
|
Packit |
875988 |
#define W32_DECORVARNAME(v) _##v
|
|
Packit |
875988 |
#define W32_VARDECORPEFIXSTR "_"
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
#error Do not know how to decorate symbols for this architecture
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Internal variable prefix (can be any) */
|
|
Packit |
875988 |
#define W32_INITHELPERVARNAME(f) _initHelperDummy_##f
|
|
Packit |
875988 |
#define W32_INITHELPERVARNAMEDECORSTR(f) W32_VARDECORPEFIXSTR _STRMACRO(W32_INITHELPERVARNAME(f))
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Declare section (segment), put variable pointing to init function to chosen segment,
|
|
Packit |
875988 |
force linker to include variable to avoid omitting by optimizer */
|
|
Packit |
875988 |
/* Initialization function must be declared as
|
|
Packit |
875988 |
int __cdecl FuncName(void) */
|
|
Packit |
875988 |
/* Return value is ignored for C++ initializers */
|
|
Packit |
875988 |
/* For C initializers: startup process is aborted if initializer return non-zero */
|
|
Packit |
875988 |
#define W32_FPTR_IN_SEG(S,F) \
|
|
Packit |
875988 |
__pragma(section(S,long,read)) \
|
|
Packit |
875988 |
__pragma(comment(linker, "/INCLUDE:" W32_INITHELPERVARNAMEDECORSTR(F))) \
|
|
Packit |
875988 |
W32_INITVARDECL __declspec(allocate(S)) int(__cdecl *W32_INITHELPERVARNAME(F))(void) = &F
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Section (segment) names for pointers to initializers */
|
|
Packit |
875988 |
#define W32_SEG_INIT_C_USER ".CRT$XCU"
|
|
Packit |
875988 |
#define W32_SEG_INIT_C_LIB ".CRT$XCL"
|
|
Packit |
875988 |
#define W32_SEG_INIT_CXX_USER ".CRT$XIU"
|
|
Packit |
875988 |
#define W32_SEG_INIT_CXX_LIB ".CRT$XIL"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Declare macro for different initializers sections */
|
|
Packit |
875988 |
/* Macro can be used several times to register several initializers */
|
|
Packit |
875988 |
/* Once function is registered as initializer, it will be called automatically
|
|
Packit |
875988 |
during application startup */
|
|
Packit |
875988 |
/* "lib" initializers are called before "user" initializers */
|
|
Packit |
875988 |
/* "C" initializers are called before "C++" initializers */
|
|
Packit |
875988 |
#define W32_REG_INIT_C_USER(F) W32_FPTR_IN_SEG(W32_SEG_INIT_C_USER,F)
|
|
Packit |
875988 |
#define W32_REG_INIT_C_LIB(F) W32_FPTR_IN_SEG(W32_SEG_INIT_C_LIB,F)
|
|
Packit |
875988 |
#define W32_REG_INIT_CXX_USER(F) W32_FPTR_IN_SEG(W32_SEG_INIT_CXX_USER,F)
|
|
Packit |
875988 |
#define W32_REG_INIT_CXX_LIB(F) W32_FPTR_IN_SEG(W32_SEG_INIT_CXX_LIB,F)
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Choose main register macro based on language and program type */
|
|
Packit |
875988 |
/* Assuming that _LIB or _USRDLL is defined for static or DLL-library */
|
|
Packit |
875988 |
/* Macro can be used several times to register several initializers */
|
|
Packit |
875988 |
/* Once function is registered as initializer, it will be called automatically
|
|
Packit |
875988 |
during application startup */
|
|
Packit |
875988 |
/* Define AUTOINIT_FUNCS_FORCE_USER_LVL_INIT to register initializers
|
|
Packit |
875988 |
at user level even if building library */
|
|
Packit |
875988 |
#ifdef __cplusplus
|
|
Packit |
875988 |
#if ((defined(_LIB) && !defined(_CONSOLE)) || defined(_USRDLL)) && !defined(AUTOINIT_FUNCS_FORCE_USER_LVL_INIT)
|
|
Packit |
875988 |
#define W32_REGISTER_INIT(F) W32_REG_INIT_CXX_LIB(F)
|
|
Packit |
875988 |
#else /* ! _LIB && ! _DLL */
|
|
Packit |
875988 |
#define W32_REGISTER_INIT(F) W32_REG_INIT_CXX_USER(F)
|
|
Packit |
875988 |
#endif /* ! _LIB && ! _DLL */
|
|
Packit |
875988 |
#else /* !__cplusplus*/
|
|
Packit |
875988 |
#if ((defined(_LIB) && !defined(_CONSOLE)) || defined(_USRDLL)) && !defined(AUTOINIT_FUNCS_FORCE_USER_LVL_INIT)
|
|
Packit |
875988 |
#define W32_REGISTER_INIT(F) W32_REG_INIT_C_LIB(F)
|
|
Packit |
875988 |
#else /* ! _LIB && ! _DLL */
|
|
Packit |
875988 |
#define W32_REGISTER_INIT(F) W32_REG_INIT_C_USER(F)
|
|
Packit |
875988 |
#endif /* ! _LIB && ! _DLL */
|
|
Packit |
875988 |
#endif /* !__cplusplus*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#else /* _USRDLL */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifndef WIN32_LEAN_AND_MEAN
|
|
Packit |
875988 |
#define WIN32_LEAN_AND_MEAN 1
|
|
Packit |
875988 |
#endif /* WIN32_LEAN_AND_MEAN */
|
|
Packit |
875988 |
/* Required for DllMain */
|
|
Packit |
875988 |
#include <Windows.h>
|
|
Packit |
875988 |
#endif /* _USRDLL */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if !defined(_USRDLL) || defined(AUTOINIT_FUNCS_FORCE_STATIC_REG)
|
|
Packit |
875988 |
#define W32_SET_INIT_AND_DEINIT(FI,FD) \
|
|
Packit |
875988 |
void __cdecl _W32_deinit_helper_##FD(void) \
|
|
Packit |
875988 |
{ (void)(FD)(); } \
|
|
Packit |
875988 |
int __cdecl _W32_init_helper_##FI(void) \
|
|
Packit |
875988 |
{ (void)(FI)(); atexit(_W32_deinit_helper_##FD); return 0; } \
|
|
Packit |
875988 |
W32_REGISTER_INIT(_W32_init_helper_##FI)
|
|
Packit |
875988 |
#else /* _USRDLL */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* If DllMain is already present in code, define AUTOINIT_FUNCS_CALL_USR_DLLMAIN
|
|
Packit |
875988 |
and rename DllMain to usr_DllMain */
|
|
Packit |
875988 |
#ifndef AUTOINIT_FUNCS_CALL_USR_DLLMAIN
|
|
Packit |
875988 |
#define W32_SET_INIT_AND_DEINIT(FI,FD) \
|
|
Packit |
875988 |
BOOL WINAPI DllMain(HINSTANCE hinst,DWORD reason,LPVOID unused) \
|
|
Packit |
875988 |
{ if(DLL_PROCESS_ATTACH==reason) {(void)(FI)();} \
|
|
Packit |
875988 |
else if(DLL_PROCESS_DETACH==reason) {(void)(FD)();} \
|
|
Packit |
875988 |
return TRUE; \
|
|
Packit |
875988 |
} struct _W32_dummy_strc_##FI{int i;}
|
|
Packit |
875988 |
#else /* AUTOINIT_FUNCS_CALL_USR_DLLMAIN */
|
|
Packit |
875988 |
#define W32_SET_INIT_AND_DEINIT(FI,FD) \
|
|
Packit |
875988 |
BOOL WINAPI usr_DllMain(HINSTANCE hinst,DWORD reason,LPVOID unused); \
|
|
Packit |
875988 |
BOOL WINAPI DllMain(HINSTANCE hinst,DWORD reason,LPVOID unused) \
|
|
Packit |
875988 |
{ if(DLL_PROCESS_ATTACH==reason) {(void)(FI)();} \
|
|
Packit |
875988 |
else if(DLL_PROCESS_DETACH==reason) {(void)(FD)();} \
|
|
Packit |
875988 |
return usr_DllMain(hinst,reason,unused); \
|
|
Packit |
875988 |
} struct _W32_dummy_strc_##FI{int i;}
|
|
Packit |
875988 |
#endif /* AUTOINIT_FUNCS_CALL_USR_DLLMAIN */
|
|
Packit |
875988 |
#endif /* _USRDLL */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#define _SET_INIT_AND_DEINIT_FUNCS(FI,FD) W32_SET_INIT_AND_DEINIT(FI,FD)
|
|
Packit |
875988 |
/* Indicate that automatic initializers/deinitializers are supported */
|
|
Packit |
875988 |
#define _AUTOINIT_FUNCS_ARE_SUPPORTED 1
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#else /* !__GNUC__ && !_MSC_FULL_VER */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Define EMIT_ERROR_IF_AUTOINIT_FUNCS_ARE_NOT_SUPPORTED before inclusion of header to
|
|
Packit |
875988 |
abort compilation if automatic initializers/deinitializers are not supported */
|
|
Packit |
875988 |
#ifdef EMIT_ERROR_IF_AUTOINIT_FUNCS_ARE_NOT_SUPPORTED
|
|
Packit |
875988 |
#error Compiler/platform don not support automatic calls of user-defined initializer and deinitializer
|
|
Packit |
875988 |
#endif /* EMIT_ERROR_IF_AUTOINIT_FUNCS_ARE_NOT_SUPPORTED */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* Do nothing */
|
|
Packit |
875988 |
#define _SET_INIT_AND_DEINIT_FUNCS(FI,FD)
|
|
Packit |
875988 |
/* Indicate that automatic initializers/deinitializers are not supported */
|
|
Packit |
875988 |
#define _AUTOINIT_FUNCS_ARE_NOT_SUPPORTED 1
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#endif /* !__GNUC__ && !_MSC_FULL_VER */
|
|
Packit |
875988 |
#endif /* !AUTOINIT_FUNCS_INCLUDED */
|