waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

c_tests.py (6123B)


      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 #ifdef _MSC_VER
    184 #define testshlib_EXPORT __declspec(dllexport)
    185 #else
    186 #define testshlib_EXPORT
    187 #endif
    188 
    189 short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
    190 short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
    191 int testshlib_EXPORT use_ascii (int i) {
    192 	return ascii_mm[i] + ascii_ii[i];
    193 }
    194 short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
    195 short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
    196 int use_ebcdic (int i) {
    197 	return ebcdic_mm[i] + ebcdic_ii[i];
    198 }
    199 extern int foo;
    200 '''
    201 
    202 class 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')
    218 def 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
    225 def 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