]> www.ginac.de Git - cln.git/blob - include/cln/modules.h
Cater to the fact that g++ 4.3 will use a different naming for
[cln.git] / include / cln / modules.h
1 // Macros for correct module ordering.
2
3 #ifndef _CL_MODULES_H
4 #define _CL_MODULES_H
5
6 // global constructor/destructor naming.
7 #include "cln/config.h"
8
9 // The order of initialization of different compilation units is not
10 // specified in C++. AIX 4 has a linker which apparently does order
11 // the modules according to dependencies, so that low-level modules
12 // will be initialized earlier than the high-level modules which depend
13 // on them. I (Bruno) have a patch for GNU ld that does the same thing.
14 //
15 // But for now, I take a half-automatic approach to the correct module
16 // ordering problem: PROVIDE/REQUIRE, as in Common Lisp.
17 //
18 // CL_PROVIDE(module) must be the first code-generating entity in a module.
19 // Inline function definitions can precede it, but global variable/function/
20 // class definitions may not precede it.
21 // Afterwards, any number of CL_REQUIRE(othermodule) is allowed.
22 // At the end of the module, there must be a corresponding
23 // CL_PROVIDE_END(module). (Sorry for this, it's really needed.)
24 //
25 // These macros work only with g++, and only in optimizing mode. But who
26 // wants to use CLN with other C++ compilers anyway...
27
28 // How to apply these macros:
29 // 1. Find out about variables which need to be initialized.
30 //    On Linux/ELF, you can use a command like
31 //    $ nm -o libcln.a | grep -v ' [UTtRrW] ' | sort +1
32 //    A symbol of type "D" or "d" lies in the preinitialized DATA section,
33 //    a symbol of type "B" or "b" lies in the uninitialized BSS section.
34 //    All of them have to be checked.
35 //  - Those which contain POD (= plain old data, i.e. scalar values or
36 //    class instances without nontrivial constructors) are already fully
37 //    initialized by the linker and can be discarded from these considerations.
38 //  - Those which are static variables inside a function (you recognize
39 //    them: g++ appends a dot and a number to their name) are initialized
40 //    the first time the function is entered. They can be discarded from
41 //    our considerations as well.
42 // 2. Find out which of these variables are publically exposed (to the user of
43 //    the library) through the library's include files, either directly or
44 //    through inline functions, or indirectly through normal function calls.
45 //    These variables can be referenced from any user module U, hence any
46 //    such module must CL_REQUIRE(M) the variable's definition module M.
47 //    Since there is no CL_REQUIRE_IF_NEEDED(M) macro (which is equivalent
48 //    to CL_REQUIRE(M) if the required module will be part of the executable
49 //    but does nothing if M is not used), we must preventively put the
50 //    CL_REQUIRE(M) into the header file. Hopefully M is either used anyway
51 //    or does not bring in too much code into the executable.
52 // 3. Variables which are not publicly exposed but used internally by the
53 //    library can be handled by adding a CL_REQUIRE in all the library's
54 //    modules which directly or indirectly use the variable.
55 // 4. Variables and functions which can be reasonably assumed to not be
56 //    accessed or executed during initialization need not be treated.
57 //    For example, I/O to external streams, exception handling facilities,
58 //    number theory stuff, etc.
59
60 // OK, stop reading here, because it's getting obscene.
61
62 #if defined(PIC)
63   #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_PIC
64 #else
65   #define CL_GLOBAL_CONSTRUCTOR_SUFFIX CL_GLOBAL_CONSTRUCTOR_SUFFIX_NOPIC
66 #endif
67
68 #if defined(__GNUC__) && defined(__OPTIMIZE__) && !(defined(__hppa__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 8)) && !defined(NO_PROVIDE_REQUIRE)
69   #ifdef ASM_UNDERSCORE
70     #define ASM_UNDERSCORE_PREFIX "_"
71   #else
72     #define ASM_UNDERSCORE_PREFIX ""
73   #endif
74   // Globalize a label defined in the same translation unit.
75   // See macro ASM_GLOBALIZE_LABEL in the gcc sources.
76   #if defined(__i386__) || defined(__m68k__) || defined(__mips__) || defined(__mipsel__) || defined(__mips64__) || defined(__alpha__) || defined(__rs6000__) || defined(__powerpc64__) || defined(__x86_64__) || defined(__s390__)
77     // Some m68k systems use "xdef" or "global" or ".global"...
78     #define CL_GLOBALIZE_LABEL(label)  __asm__("\t.globl " label);
79   #endif
80   #if defined(__sparc__) || defined(__sparc64__) || defined(__arm__) || defined(__ia64__)
81     // Some arm systems use "EXPORT" or ".globl"...
82     #define CL_GLOBALIZE_LABEL(label)  __asm__("\t.global " label);
83   #endif
84   #if defined(__hppa__)
85     #define CL_GLOBALIZE_LABEL(label)  __asm__("\t.EXPORT " label ",ENTRY,PRIV_LEV=3");
86   #endif
87   #if defined(__m88k__)
88     #define CL_GLOBALIZE_LABEL(label)  __asm__("\tglobal " label);
89   #endif
90   #if defined(__convex__)
91     #define CL_GLOBALIZE_LABEL(label)  __asm__(".globl " label);
92   #endif
93   #ifndef CL_GLOBALIZE_LABEL
94     #define CL_GLOBALIZE_LABEL(label)
95   #endif
96   #if defined(__rs6000__) || defined(_WIN32)
97     #define CL_GLOBALIZE_JUMP_LABEL(label)  CL_GLOBALIZE_LABEL(ASM_UNDERSCORE_PREFIX #label)
98   #else
99     #define CL_GLOBALIZE_JUMP_LABEL(label)
100   #endif
101   #ifdef CL_NEED_GLOBALIZE_CTORDTOR
102     #define CL_GLOBALIZE_CTORDTOR_LABEL(label)  CL_GLOBALIZE_LABEL(label)
103   #else
104     #define CL_GLOBALIZE_CTORDTOR_LABEL(label)
105   #endif
106   // Output a label inside a function.
107   // See macro ASM_OUTPUT_LABEL in the gcc sources.
108   #if defined(__ia64__)
109     // g++-4.0 on IA64 likes to duplicate parts of basic blocks for no good
110     // reason. To avoid an error when a label is defined twice, we can either
111     // append "-Os" to the CXXFLAGS (then g++ does not create redundant
112     // duplicates of basic blocks), or declare the label in a way that may
113     // be redefined.
114     // Why the "nop 0"? Apparently "." refers to the last instruction bundle.
115     // Just ".set label,." would cause the branch to executed unwanted code.
116     // And ".set label,.+16" might not work at the very beginning of a
117     // function. So we spend a nop; it becomes the target of the jump.
118     #define CL_OUTPUT_LABEL(label)  ASM_VOLATILE ("nop 0" "\n" ".set " label ", .")
119   #elif defined(__m68k__)
120     // C.f. IA64 case above.
121     #define CL_OUTPUT_LABEL(label)  ASM_VOLATILE ("nop" "\n" ".set " label ", .")
122   #else
123     #define CL_OUTPUT_LABEL(label)  ASM_VOLATILE ("\n" label ":")
124   #endif
125   // ASM_VOLATILE(string) is for asms without arguments only!!
126   #if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 91)) || (__GNUC__ >= 3)
127     // avoid warning caused by the volatile keyword
128     #define ASM_VOLATILE  __asm__
129   #else
130     // need volatile to avoid reordering
131     #define ASM_VOLATILE  __asm__ __volatile__
132   #endif
133   // CL_JUMP_TO(addr) jumps to an address, like  goto *(void*)(addr),
134   // except that the latter inhibits inlining of the function containing it
135   // in gcc-2.95. For new CPUs, look for "jump" and "indirect_jump" in gcc's
136   // machine description.
137   #if defined(__i386__)
138     #if defined(__APPLE__) && defined(__MACH__)
139       #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr)
140     #else
141       #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp %*%0" : : "rm" ((void*)(addr)))
142     #endif
143   #endif
144   #if defined(__x86_64__)
145     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp " ASM_UNDERSCORE_PREFIX #addr)
146   #endif
147   #if defined(__m68k__)
148     //#define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp %0@" : : "a" ((void*)(addr)))
149     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp (" ASM_UNDERSCORE_PREFIX #addr ",%pc)")
150   #endif
151   #if defined(__mips__) || defined(__mipsel__)
152     //#define CL_JUMP_TO(addr)  ASM_VOLATILE("%*j %0" : : "d" ((void*)(addr)))
153     #define CL_JUMP_TO(addr)  ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
154   #endif
155   #if defined(__sparc__) || defined(__sparc64__)
156     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp %0\n\tnop" : : "r" ((void*)(addr)))
157   #endif
158   #if defined(__alpha__)
159     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp $31,(%0),0" : : "r" ((void*)(addr)))
160   #endif
161   #if defined(__hppa__)
162     //#define CL_JUMP_TO(addr)  ASM_VOLATILE("bv,n 0(%0)" : : "r" ((void*)(addr)))
163     #define CL_JUMP_TO(addr)  ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr "\n\tnop")
164   #endif
165   #if defined(__arm__)
166     #define CL_JUMP_TO(addr)  ASM_VOLATILE("mov pc,%0" : : "r" ((void*)(addr)))
167   #endif
168   #if defined(__rs6000__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__)
169     //#define CL_JUMP_TO(addr)  ASM_VOLATILE("mtctr %0\n\tbctr" : : "r" ((void*)(addr)))
170     #define CL_JUMP_TO(addr)  ASM_VOLATILE("b " ASM_UNDERSCORE_PREFIX #addr)
171   #endif
172   #if defined(__m88k__)
173     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp %0" : : "r" ((void*)(addr)))
174   #endif
175   #if defined(__convex__)
176     #define CL_JUMP_TO(addr)  ASM_VOLATILE("jmp (%0)" : : "r" ((void*)(addr)))
177   #endif
178   #if defined(__ia64__)
179     #define CL_JUMP_TO(addr)  ASM_VOLATILE("br " ASM_UNDERSCORE_PREFIX #addr)
180   #endif
181   #if defined(__s390__)
182     #define CL_JUMP_TO(addr)  ASM_VOLATILE("br %0" : : "a" ((void*)(addr)))
183   #endif
184   #ifdef CL_GLOBAL_DESTRUCTOR_PREFIX
185     #define CL_PROVIDE(module)  \
186       extern "C" void cl_module__##module##__firstglobalfun () {}       \
187       extern "C" void cl_module__##module##__ctorend (void);            \
188       extern "C" void cl_module__##module##__dtorend (void);            \
189       CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__ctorend)           \
190       CL_GLOBALIZE_JUMP_LABEL(cl_module__##module##__dtorend)           \
191       CL_GLOBALIZE_CTORDTOR_LABEL(                                      \
192                  ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX     \
193                  "cl_module__" #module "__firstglobalfun")              \
194       CL_GLOBALIZE_CTORDTOR_LABEL(                                      \
195                  ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX      \
196                  "cl_module__" #module "__firstglobalfun")              \
197       static int cl_module__##module##__counter;                        \
198       struct cl_module__##module##__controller {                        \
199         inline cl_module__##module##__controller ()                     \
200           { if (cl_module__##module##__counter++)                       \
201               { CL_JUMP_TO(cl_module__##module##__ctorend); }           \
202           }                                                             \
203         inline ~cl_module__##module##__controller ()                    \
204           { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__dtorend"); } \
205       };                                                                        \
206       static cl_module__##module##__controller cl_module__##module##__ctordummy;
207     #define CL_PROVIDE_END(module)  \
208       struct cl_module__##module##__destroyer {                         \
209         inline cl_module__##module##__destroyer ()                      \
210           { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
211         inline ~cl_module__##module##__destroyer ()                     \
212           { if (--cl_module__##module##__counter)                       \
213               { CL_JUMP_TO(cl_module__##module##__dtorend); }           \
214           }                                                             \
215       };                                                                \
216       static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
217     #define CL_REQUIRE(module)  \
218       extern "C" void cl_module__##module##__ctor (void)                \
219         __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX     \
220                  "cl_module__" #module "__firstglobalfun");             \
221       extern "C" void cl_module__##module##__dtor (void)                \
222         __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_DESTRUCTOR_PREFIX      \
223                  "cl_module__" #module "__firstglobalfun");             \
224       struct _CL_REQUIRE_CLASSNAME(module,__LINE__) {                   \
225         inline _CL_REQUIRE_CLASSNAME(module,__LINE__) ()                \
226           { cl_module__##module##__ctor (); }                           \
227         inline ~_CL_REQUIRE_CLASSNAME(module,__LINE__) ()               \
228           { cl_module__##module##__dtor (); }                           \
229       };                                                                \
230       static _CL_REQUIRE_CLASSNAME(module,__LINE__)                     \
231         _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
232   #else
233     // gcc-3.0 -fuse-cxa-atexit doesn't have a single per-module destructor
234     // function anymore. Instead, for each object's static constructor it
235     // executes, it pushes the corresponding object's destructor onto a list.
236     // Thus we need to hack the constructors only. gcc-4.3 uses different names
237     // for global ctors in shared and static objects, so we cannot directly
238     // call the ctors from CL_REQUIRE(M): the compiling function does not know
239     // yet how it's going to be linked. Hence, we must hide the ctor call beind
240     // an additional indirection.
241     #define CL_PROVIDE(module)  \
242       extern "C" void cl_module__##module##__firstglobalfun () {}       \
243       extern "C" void cl_module__##module##__ctorend ();                \
244       extern "C" void cl_module__##module##__docallctors ()             \
245         __asm__ (ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX     \
246                      CL_GLOBAL_CONSTRUCTOR_SUFFIX(module));             \
247       extern "C" void cl_module__##module##__globalctors ()             \
248       { cl_module__##module##__docallctors(); }                         \
249       CL_GLOBALIZE_CTORDTOR_LABEL(                                      \
250                  ASM_UNDERSCORE_PREFIX CL_GLOBAL_CONSTRUCTOR_PREFIX     \
251                  CL_GLOBAL_CONSTRUCTOR_SUFFIX(module))                  \
252       static int cl_module__##module##__counter;                        \
253       struct cl_module__##module##__controller {                        \
254         inline cl_module__##module##__controller ()                     \
255           { if (cl_module__##module##__counter++)                       \
256               { CL_JUMP_TO(cl_module__##module##__ctorend); }           \
257           }                                                             \
258       };                                                                \
259       static cl_module__##module##__controller cl_module__##module##__ctordummy;
260     #define CL_PROVIDE_END(module)  \
261       struct cl_module__##module##__destroyer {                         \
262         inline cl_module__##module##__destroyer ()                      \
263           { CL_OUTPUT_LABEL (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__ctorend"); } \
264       };                                                                \
265       static cl_module__##module##__destroyer cl_module__##module##__dtordummy;
266     #define CL_REQUIRE(module)  \
267       extern "C" void cl_module__##module##__ctor ()                    \
268         __asm__ (ASM_UNDERSCORE_PREFIX "cl_module__" #module "__globalctors"); \
269       struct _CL_REQUIRE_CLASSNAME(module,__LINE__) {                   \
270         inline _CL_REQUIRE_CLASSNAME(module,__LINE__) ()                \
271           { cl_module__##module##__ctor (); }                           \
272       };                                                                \
273       static _CL_REQUIRE_CLASSNAME(module,__LINE__)                     \
274         _CL_REQUIRE_CLASSNAME(module##_requirer,__LINE__);
275   #endif
276   #define _CL_REQUIRE_CLASSNAME(module,line) __CL_REQUIRE_CLASSNAME(module,line)
277   #define __CL_REQUIRE_CLASSNAME(module,line) cl_module__##module##__##line
278 #else
279   #define CL_PROVIDE(module)
280   #define CL_PROVIDE_END(module)
281   #define CL_REQUIRE(module)
282 #endif
283
284 // Concatenation of macroexpanded tokens.
285 // Equivalent to CL_CONCAT in src/base/cl_macros.h which we do not want
286 // to expose, however.
287 #define CL_CONCATENATE_(xxx,yyy)  xxx##yyy
288 #define CL_CONCATENATE(xxx,yyy)  CL_CONCATENATE_(xxx,yyy)
289
290 // Sometimes a link time dependency is needed, but without requirements
291 // on initialization order.
292 //
293 // CL_FORCE_LINK(dummy,external_variable)
294 // forces a link time reference to the external_variable.
295 #include <cstdlib>
296 #if 0
297 // This definition does not work.  It gets optimized away by g++ 3.1.
298 #define CL_FORCE_LINK(dummy,external_variable) \
299   static const void* const dummy[] = { &dummy, &external_variable };
300 #else
301 #define CL_FORCE_LINK(dummy,external_variable) \
302   static const                                                          \
303   struct dummy {                                                        \
304     inline dummy () {                                                   \
305       if ((void*) &external_variable == (void*) this)                   \
306         abort();                                                        \
307     }                                                                   \
308   }                                                                     \
309   CL_CONCATENATE(dummy,_instance);
310 #endif
311
312 #endif /* _CL_MODULES_H */