Blame src/include/autoinit_funcs.h

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 */