/****************************************************************************** prepost.h: Add function calls before/after main() Copyright (C) 2012-2013 Wang Bin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ #ifndef PREPOST_H #define PREPOST_H /*Avoid a compiler warning when the arguments is empty, *e.g. PRE_FUNC_ADD(foo). The right one is PRE_FUNC_ADD(f,)*/ /* * TODO: * boost::call_once * http://stackoverflow.com/questions/4173384/how-to-make-sure-a-function-is-only-called-once * http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fco.htm */ #ifdef __cplusplus /* for C++, we use non-local static object to call the functions automatically before main(). * anonymous namespace: avoid name confliction('static' keyword is not necessary) * */ #define PRE_FUNC_ADD(f, .../*args*/) \ namespace { \ static const struct initializer_for_##f { \ inline initializer_for_##f() { \ f(__VA_ARGS__); \ } \ } __sInit_##f; \ } #define POST_FUNC_ADD(f, .../*args*/) \ namespace { \ static const struct deinitializer_for_##f { \ inline deinitializer_for_##f() {} \ inline ~deinitializer_for_##f() { f(__VA_ARGS__); } \ } __sDeinit_##f; \ } #else /*for C. ! defined __cplusplus*/ /* *http://buliedian.iteye.com/blog/1069072 *http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/_crt.c.htm */ #if defined(_MSC_VER) #pragma section(".CRT$XIU", long, read) #pragma section(".CRT$XPU", long, read) #define _CRTALLOC(x) __declspec(allocate(x)) /*TODO: Auto unique naming*/ typedef int (__cdecl *_PF)(); /* why not void? */ /*static to avoid multiple defination*/ #define PRE_FUNC_ADD(f, .../*args*/) \ static int init_##f() { f(__VA_ARGS__); return 0;} \ _CRTALLOC(".CRT$XIU") static _PF pinit_##f [] = { init_##f }; /*static void (*pinit_##f)() = init_##f //__cdecl */ #define POST_FUNC_ADD(f, .../*args*/) \ static int deinit_##f() { f(__VA_ARGS__); return 0;} \ _CRTALLOC(".CRT$XPU") static _PF pdeinit_##f [] = { deinit_##f }; #elif defined(__GNUC__) #define PRE_FUNC_ADD(f, ...) \ __attribute__((constructor)) static void init_##f() { f(__VA_ARGS__); } #define POST_FUNC_ADD(f, ...) \ __attribute__((destructor)) static void deinit_##f() { f(__VA_ARGS__); } #else #ifndef __cplusplus #error Not supported for C: PRE_FUNC_ADD, POST_FUNC_ADD #endif #include /*static var init, atexit*/ #define PRE_FUNC_ADD(f, ...) \ static int init_##f() { f(__VA_ARGS__); return 0; } \ static int v_init_##f = init_##f(); /*Works for C++. For C, gcc will throw an error: *initializer element is not constant */ /*atexit do not support arguments*/ #define POST_FUNC_ADD(f, ...) \ static void atexit_##f() { atexit(f); } \ PRE_FUNC_ADD(atexit_##f) #endif #endif //__cplusplus #endif // PREPOST_H