waf: upgrade to 2.0.18
[metze/samba/wip.git] / third_party / waf / waflib / Tools / c_tests.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2016-2018 (ita)
4
5 """
6 Various configuration tests.
7 """
8
9 from waflib import Task
10 from waflib.Configure import conf
11 from waflib.TaskGen import feature, before_method, after_method
12
13 LIB_CODE = '''
14 #ifdef _MSC_VER
15 #define testEXPORT __declspec(dllexport)
16 #else
17 #define testEXPORT
18 #endif
19 testEXPORT int lib_func(void) { return 9; }
20 '''
21
22 MAIN_CODE = '''
23 #ifdef _MSC_VER
24 #define testEXPORT __declspec(dllimport)
25 #else
26 #define testEXPORT
27 #endif
28 testEXPORT int lib_func(void);
29 int main(int argc, char **argv) {
30         (void)argc; (void)argv;
31         return !(lib_func() == 9);
32 }
33 '''
34
35 @feature('link_lib_test')
36 @before_method('process_source')
37 def link_lib_test_fun(self):
38         """
39         The configuration test :py:func:`waflib.Configure.run_build` declares a unique task generator,
40         so we need to create other task generators from here to check if the linker is able to link libraries.
41         """
42         def write_test_file(task):
43                 task.outputs[0].write(task.generator.code)
44
45         rpath = []
46         if getattr(self, 'add_rpath', False):
47                 rpath = [self.bld.path.get_bld().abspath()]
48
49         mode = self.mode
50         m = '%s %s' % (mode, mode)
51         ex = self.test_exec and 'test_exec' or ''
52         bld = self.bld
53         bld(rule=write_test_file, target='test.' + mode, code=LIB_CODE)
54         bld(rule=write_test_file, target='main.' + mode, code=MAIN_CODE)
55         bld(features='%sshlib' % m, source='test.' + mode, target='test')
56         bld(features='%sprogram %s' % (m, ex), source='main.' + mode, target='app', use='test', rpath=rpath)
57
58 @conf
59 def check_library(self, mode=None, test_exec=True):
60         """
61         Checks if libraries can be linked with the current linker. Uses :py:func:`waflib.Tools.c_tests.link_lib_test_fun`.
62
63         :param mode: c or cxx or d
64         :type mode: string
65         """
66         if not mode:
67                 mode = 'c'
68                 if self.env.CXX:
69                         mode = 'cxx'
70         self.check(
71                 compile_filename = [],
72                 features = 'link_lib_test',
73                 msg = 'Checking for libraries',
74                 mode = mode,
75                 test_exec = test_exec)
76
77 ########################################################################################
78
79 INLINE_CODE = '''
80 typedef int foo_t;
81 static %s foo_t static_foo () {return 0; }
82 %s foo_t foo () {
83         return 0;
84 }
85 '''
86 INLINE_VALUES = ['inline', '__inline__', '__inline']
87
88 @conf
89 def check_inline(self, **kw):
90         """
91         Checks for the right value for inline macro.
92         Define INLINE_MACRO to 1 if the define is found.
93         If the inline macro is not 'inline', add a define to the ``config.h`` (#define inline __inline__)
94
95         :param define_name: define INLINE_MACRO by default to 1 if the macro is defined
96         :type define_name: string
97         :param features: by default *c* or *cxx* depending on the compiler present
98         :type features: list of string
99         """
100         self.start_msg('Checking for inline')
101
102         if not 'define_name' in kw:
103                 kw['define_name'] = 'INLINE_MACRO'
104         if not 'features' in kw:
105                 if self.env.CXX:
106                         kw['features'] = ['cxx']
107                 else:
108                         kw['features'] = ['c']
109
110         for x in INLINE_VALUES:
111                 kw['fragment'] = INLINE_CODE % (x, x)
112
113                 try:
114                         self.check(**kw)
115                 except self.errors.ConfigurationError:
116                         continue
117                 else:
118                         self.end_msg(x)
119                         if x != 'inline':
120                                 self.define('inline', x, quote=False)
121                         return x
122         self.fatal('could not use inline functions')
123
124 ########################################################################################
125
126 LARGE_FRAGMENT = '''#include <unistd.h>
127 int main(int argc, char **argv) {
128         (void)argc; (void)argv;
129         return !(sizeof(off_t) >= 8);
130 }
131 '''
132
133 @conf
134 def check_large_file(self, **kw):
135         """
136         Checks for large file support and define the macro HAVE_LARGEFILE
137         The test is skipped on win32 systems (DEST_BINFMT == pe).
138
139         :param define_name: define to set, by default *HAVE_LARGEFILE*
140         :type define_name: string
141         :param execute: execute the test (yes by default)
142         :type execute: bool
143         """
144         if not 'define_name' in kw:
145                 kw['define_name'] = 'HAVE_LARGEFILE'
146         if not 'execute' in kw:
147                 kw['execute'] = True
148
149         if not 'features' in kw:
150                 if self.env.CXX:
151                         kw['features'] = ['cxx', 'cxxprogram']
152                 else:
153                         kw['features'] = ['c', 'cprogram']
154
155         kw['fragment'] = LARGE_FRAGMENT
156
157         kw['msg'] = 'Checking for large file support'
158         ret = True
159         try:
160                 if self.env.DEST_BINFMT != 'pe':
161                         ret = self.check(**kw)
162         except self.errors.ConfigurationError:
163                 pass
164         else:
165                 if ret:
166                         return True
167
168         kw['msg'] = 'Checking for -D_FILE_OFFSET_BITS=64'
169         kw['defines'] = ['_FILE_OFFSET_BITS=64']
170         try:
171                 ret = self.check(**kw)
172         except self.errors.ConfigurationError:
173                 pass
174         else:
175                 self.define('_FILE_OFFSET_BITS', 64)
176                 return ret
177
178         self.fatal('There is no support for large files')
179
180 ########################################################################################
181
182 ENDIAN_FRAGMENT = '''
183 short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
184 short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
185 int use_ascii (int i) {
186         return ascii_mm[i] + ascii_ii[i];
187 }
188 short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
189 short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
190 int use_ebcdic (int i) {
191         return ebcdic_mm[i] + ebcdic_ii[i];
192 }
193 extern int foo;
194 '''
195
196 class grep_for_endianness(Task.Task):
197         """
198         Task that reads a binary and tries to determine the endianness
199         """
200         color = 'PINK'
201         def run(self):
202                 txt = self.inputs[0].read(flags='rb').decode('latin-1')
203                 if txt.find('LiTTleEnDian') > -1:
204                         self.generator.tmp.append('little')
205                 elif txt.find('BIGenDianSyS') > -1:
206                         self.generator.tmp.append('big')
207                 else:
208                         return -1
209
210 @feature('grep_for_endianness')
211 @after_method('process_source')
212 def grep_for_endianness_fun(self):
213         """
214         Used by the endianness configuration test
215         """
216         self.create_task('grep_for_endianness', self.compiled_tasks[0].outputs[0])
217
218 @conf
219 def check_endianness(self):
220         """
221         Executes a configuration test to determine the endianness
222         """
223         tmp = []
224         def check_msg(self):
225                 return tmp[0]
226         self.check(fragment=ENDIAN_FRAGMENT, features='c grep_for_endianness',
227                 msg='Checking for endianness', define='ENDIANNESS', tmp=tmp,
228                 okmsg=check_msg, confcache=None)
229         return tmp[0]
230