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