1#!/usr/bin/env python 2# encoding: utf-8 3# Thomas Nagy, 2016-2018 (ita) 4 5""" 6Various configuration tests. 7""" 8 9from waflib import Task 10from waflib.Configure import conf 11from waflib.TaskGen import feature, before_method, after_method 12 13LIB_CODE = ''' 14#ifdef _MSC_VER 15#define testEXPORT __declspec(dllexport) 16#else 17#define testEXPORT 18#endif 19testEXPORT int lib_func(void) { return 9; } 20''' 21 22MAIN_CODE = ''' 23#ifdef _MSC_VER 24#define testEXPORT __declspec(dllimport) 25#else 26#define testEXPORT 27#endif 28testEXPORT int lib_func(void); 29int 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') 37def 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 59def 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 79INLINE_CODE = ''' 80typedef int foo_t; 81static %s foo_t static_foo () {return 0; } 82%s foo_t foo () { 83 return 0; 84} 85''' 86INLINE_VALUES = ['inline', '__inline__', '__inline'] 87 88@conf 89def 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 126LARGE_FRAGMENT = '''#include <unistd.h> 127int main(int argc, char **argv) { 128 (void)argc; (void)argv; 129 return !(sizeof(off_t) >= 8); 130} 131''' 132 133@conf 134def 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 182ENDIAN_FRAGMENT = ''' 183#ifdef _MSC_VER 184#define testshlib_EXPORT __declspec(dllexport) 185#else 186#define testshlib_EXPORT 187#endif 188 189short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; 190short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; 191int testshlib_EXPORT use_ascii (int i) { 192 return ascii_mm[i] + ascii_ii[i]; 193} 194short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; 195short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; 196int use_ebcdic (int i) { 197 return ebcdic_mm[i] + ebcdic_ii[i]; 198} 199extern int foo; 200''' 201 202class grep_for_endianness(Task.Task): 203 """ 204 Task that reads a binary and tries to determine the endianness 205 """ 206 color = 'PINK' 207 def run(self): 208 txt = self.inputs[0].read(flags='rb').decode('latin-1') 209 if txt.find('LiTTleEnDian') > -1: 210 self.generator.tmp.append('little') 211 elif txt.find('BIGenDianSyS') > -1: 212 self.generator.tmp.append('big') 213 else: 214 return -1 215 216@feature('grep_for_endianness') 217@after_method('apply_link') 218def grep_for_endianness_fun(self): 219 """ 220 Used by the endianness configuration test 221 """ 222 self.create_task('grep_for_endianness', self.link_task.outputs[0]) 223 224@conf 225def check_endianness(self): 226 """ 227 Executes a configuration test to determine the endianness 228 """ 229 tmp = [] 230 def check_msg(self): 231 return tmp[0] 232 233 self.check(fragment=ENDIAN_FRAGMENT, features='c cshlib grep_for_endianness', 234 msg='Checking for endianness', define='ENDIANNESS', tmp=tmp, 235 okmsg=check_msg, confcache=None) 236 return tmp[0] 237 238