~vcs-imports/kupfer/master-new

« back to all changes in this revision

Viewing changes to waflib/Tools/c_config.py

  • Committer: Ulrik Sverdrup
  • Date: 2012-02-26 17:50:05 UTC
  • mfrom: (2916.1.5)
  • Revision ID: git-v1:a1d52c4a74cd48e1b673e68977eba58b48928b7f
Merge branch 'full-waf'

* full-waf:
  Update NEWS
  wscript: Use .xz for distribution tarball
  wscript: Clean all .pyc files on distclean
  Update README for Waf being included in the repository and tarball
  Add waf-light and waflib from waf-1.6.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# encoding: utf-8
 
3
# Thomas Nagy, 2005-2010 (ita)
 
4
 
 
5
"""
 
6
C/C++/D configuration helpers
 
7
"""
 
8
 
 
9
import os, imp, sys, re, shlex, shutil
 
10
from waflib import Build, Utils, Configure, Task, Options, Logs, TaskGen, Errors, ConfigSet, Runner
 
11
from waflib.TaskGen import before_method, after_method, feature
 
12
from waflib.Configure import conf
 
13
 
 
14
WAF_CONFIG_H   = 'config.h'
 
15
"""default name for the config.h file"""
 
16
 
 
17
DEFKEYS = 'define_key'
 
18
INCKEYS = 'include_key'
 
19
 
 
20
cfg_ver = {
 
21
        'atleast-version': '>=',
 
22
        'exact-version': '==',
 
23
        'max-version': '<=',
 
24
}
 
25
 
 
26
SNIP_FUNCTION = '''
 
27
        int main() {
 
28
        void *p;
 
29
        p=(void*)(%s);
 
30
        return 0;
 
31
}
 
32
'''
 
33
"""Code template for checking for functions"""
 
34
 
 
35
SNIP_TYPE = '''
 
36
int main() {
 
37
        if ((%(type_name)s *) 0) return 0;
 
38
        if (sizeof (%(type_name)s)) return 0;
 
39
}
 
40
'''
 
41
"""Code template for checking for types"""
 
42
 
 
43
SNIP_CLASS = '''
 
44
int main() {
 
45
        if (
 
46
}
 
47
'''
 
48
 
 
49
SNIP_EMPTY_PROGRAM = '''
 
50
int main() {
 
51
        return 0;
 
52
}
 
53
'''
 
54
 
 
55
SNIP_FIELD = '''
 
56
int main() {
 
57
        char *off;
 
58
        off = (char*) &((%(type_name)s*)0)->%(field_name)s;
 
59
        return (size_t) off < sizeof(%(type_name)s);
 
60
}
 
61
'''
 
62
 
 
63
MACRO_TO_DESTOS = {
 
64
'__linux__'                                      : 'linux',
 
65
'__GNU__'                                        : 'gnu', # hurd
 
66
'__FreeBSD__'                                    : 'freebsd',
 
67
'__NetBSD__'                                     : 'netbsd',
 
68
'__OpenBSD__'                                    : 'openbsd',
 
69
'__sun'                                          : 'sunos',
 
70
'__hpux'                                         : 'hpux',
 
71
'__sgi'                                          : 'irix',
 
72
'_AIX'                                           : 'aix',
 
73
'__CYGWIN__'                                     : 'cygwin',
 
74
'__MSYS__'                                       : 'msys',
 
75
'_UWIN'                                          : 'uwin',
 
76
'_WIN64'                                         : 'win32',
 
77
'_WIN32'                                         : 'win32',
 
78
# Note about darwin: this is also tested with 'defined __APPLE__ && defined __MACH__' somewhere below in this file.
 
79
'__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__'  : 'darwin', 
 
80
'__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', # iphone
 
81
'__QNX__'                                        : 'qnx',
 
82
'__native_client__'                              : 'nacl' # google native client platform
 
83
}
 
84
 
 
85
MACRO_TO_DEST_CPU = {
 
86
'__x86_64__'  : 'x86_64',
 
87
'__i386__'    : 'x86',
 
88
'__ia64__'    : 'ia',
 
89
'__mips__'    : 'mips',
 
90
'__sparc__'   : 'sparc',
 
91
'__alpha__'   : 'alpha',
 
92
'__arm__'     : 'arm',
 
93
'__hppa__'    : 'hppa',
 
94
'__powerpc__' : 'powerpc',
 
95
}
 
96
 
 
97
@conf
 
98
def parse_flags(self, line, uselib, env=None, force_static=False):
 
99
        """
 
100
        Parse the flags from the input lines, and add them to the relevant use variables::
 
101
 
 
102
                def configure(conf):
 
103
                        conf.parse_flags('-O3', uselib_store='FOO')
 
104
                        # conf.env.CXXFLAGS_FOO = ['-O3']
 
105
                        # conf.env.CFLAGS_FOO = ['-O3']
 
106
 
 
107
        :param line: flags
 
108
        :type line: string
 
109
        :param uselib: where to add the flags
 
110
        :type uselib: string
 
111
        :param env: config set or conf.env by default
 
112
        :type env: :py:class:`waflib.ConfigSet.ConfigSet`
 
113
        """
 
114
 
 
115
        assert(isinstance(line, str))
 
116
 
 
117
        env = env or self.env
 
118
 
 
119
        # append_unique is not always possible
 
120
        # for example, apple flags may require both -arch i386 and -arch ppc
 
121
 
 
122
        app = env.append_value
 
123
        appu = env.append_unique
 
124
        #lst = shlex.split(line)
 
125
        # issue #811
 
126
        lex = shlex.shlex(line, posix=False)
 
127
        lex.whitespace_split = True
 
128
        lex.commenters = ''
 
129
        lst = list(lex)
 
130
 
 
131
        while lst:
 
132
                x = lst.pop(0)
 
133
                st = x[:2]
 
134
                ot = x[2:]
 
135
 
 
136
                if st == '-I' or st == '/I':
 
137
                        if not ot: ot = lst.pop(0)
 
138
                        appu('INCLUDES_' + uselib, [ot])
 
139
                elif st == '-include':
 
140
                        tmp = [x, lst.pop(0)]
 
141
                        app('CFLAGS', tmp)
 
142
                        app('CXXFLAGS', tmp)
 
143
                elif st == '-D' or (self.env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but..
 
144
                        if not ot: ot = lst.pop(0)
 
145
                        app('DEFINES_' + uselib, [ot])
 
146
                elif st == '-l':
 
147
                        if not ot: ot = lst.pop(0)
 
148
                        prefix = force_static and 'STLIB_' or 'LIB_'
 
149
                        appu(prefix + uselib, [ot])
 
150
                elif st == '-L':
 
151
                        if not ot: ot = lst.pop(0)
 
152
                        appu('LIBPATH_' + uselib, [ot])
 
153
                elif x == '-pthread' or x.startswith('+') or x.startswith('-std'):
 
154
                        app('CFLAGS_' + uselib, [x])
 
155
                        app('CXXFLAGS_' + uselib, [x])
 
156
                        app('LINKFLAGS_' + uselib, [x])
 
157
                elif x == '-framework':
 
158
                        appu('FRAMEWORK_' + uselib, [lst.pop(0)])
 
159
                elif x.startswith('-F'):
 
160
                        appu('FRAMEWORKPATH_' + uselib, [x[2:]])
 
161
                elif x.startswith('-Wl'):
 
162
                        app('LINKFLAGS_' + uselib, [x])
 
163
                elif x.startswith('-m') or x.startswith('-f') or x.startswith('-dynamic'):
 
164
                        app('CFLAGS_' + uselib, [x])
 
165
                        app('CXXFLAGS_' + uselib, [x])
 
166
                elif x.startswith('-bundle'):
 
167
                        app('LINKFLAGS_' + uselib, [x])
 
168
                elif x.startswith('-undefined'):
 
169
                        arg = lst.pop(0)
 
170
                        app('LINKFLAGS_' + uselib, [x, arg])
 
171
                elif x.startswith('-arch') or x.startswith('-isysroot'):
 
172
                        tmp = [x, lst.pop(0)]
 
173
                        app('CFLAGS_' + uselib, tmp)
 
174
                        app('CXXFLAGS_' + uselib, tmp)
 
175
                        app('LINKFLAGS_' + uselib, tmp)
 
176
                elif x.endswith('.a') or x.endswith('.so') or x.endswith('.dylib'):
 
177
                        appu('LINKFLAGS_' + uselib, [x]) # not cool, #762
 
178
 
 
179
@conf
 
180
def ret_msg(self, f, kw):
 
181
        if isinstance(f, str):
 
182
                return f
 
183
        return f(kw)
 
184
 
 
185
@conf
 
186
def validate_cfg(self, kw):
 
187
        """
 
188
        Search for the program *pkg-config* if missing, and validate the parameters to pass to
 
189
        :py:func:`waflib.Tools.c_config.exec_cfg`.
 
190
 
 
191
        :param path: the **-config program to use** (default is *pkg-config*)
 
192
        :type path: list of string
 
193
        :param msg: message to display to describe the test executed
 
194
        :type msg: string
 
195
        :param okmsg: message to display when the test is successful
 
196
        :type okmsg: string
 
197
        :param errmsg: message to display in case of error
 
198
        :type errmsg: string
 
199
        """
 
200
        if not 'path' in kw:
 
201
                if not self.env.PKGCONFIG:
 
202
                        self.find_program('pkg-config', var='PKGCONFIG')
 
203
                kw['path'] = self.env.PKGCONFIG
 
204
 
 
205
        # pkg-config version
 
206
        if 'atleast_pkgconfig_version' in kw:
 
207
                if not 'msg' in kw:
 
208
                        kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version']
 
209
                return
 
210
 
 
211
        if not 'okmsg' in kw:
 
212
                kw['okmsg'] = 'yes'
 
213
        if not 'errmsg' in kw:
 
214
                kw['errmsg'] = 'not found'
 
215
 
 
216
        if 'modversion' in kw:
 
217
                if not 'msg' in kw:
 
218
                        kw['msg'] = 'Checking for %r version' % kw['modversion']
 
219
                return
 
220
 
 
221
        # checking for the version of a module, for the moment, one thing at a time
 
222
        for x in cfg_ver.keys():
 
223
                y = x.replace('-', '_')
 
224
                if y in kw:
 
225
                        if not 'package' in kw:
 
226
                                raise ValueError('%s requires a package' % x)
 
227
 
 
228
                        if not 'msg' in kw:
 
229
                                kw['msg'] = 'Checking for %r %s %s' % (kw['package'], cfg_ver[x], kw[y])
 
230
                        return
 
231
 
 
232
        if not 'msg' in kw:
 
233
                kw['msg'] = 'Checking for %r' % (kw['package'] or kw['path'])
 
234
 
 
235
@conf
 
236
def exec_cfg(self, kw):
 
237
        """
 
238
        Execute the program *pkg-config*:
 
239
 
 
240
        * if atleast_pkgconfig_version is given, check that pkg-config has the version n and return
 
241
        * if modversion is given, then return the module version
 
242
        * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable
 
243
 
 
244
        :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests)
 
245
        :type atleast_pkgconfig_version: string
 
246
        :param package: package name, for example *gtk+-2.0*
 
247
        :type package: string
 
248
        :param uselib_store: if the test is successful, define HAVE\_*name*. It is also used to define *conf.env.FLAGS_name* variables.
 
249
        :type uselib_store: string
 
250
        :param modversion: if provided, return the version of the given module and define *name*\_VERSION
 
251
        :type modversion: string
 
252
        :param args: arguments to give to *package* when retrieving flags
 
253
        :type args: list of string
 
254
        :param variables: return the values of particular variables
 
255
        :type variables: list of string
 
256
        :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES)
 
257
        :type define_variable: dict(string: string)
 
258
        """
 
259
 
 
260
        # pkg-config version
 
261
        if 'atleast_pkgconfig_version' in kw:
 
262
                cmd = [kw['path'], '--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']]
 
263
                self.cmd_and_log(cmd)
 
264
                if not 'okmsg' in kw:
 
265
                        kw['okmsg'] = 'yes'
 
266
                return
 
267
 
 
268
        # checking for the version of a module
 
269
        for x in cfg_ver:
 
270
                y = x.replace('-', '_')
 
271
                if y in kw:
 
272
                        self.cmd_and_log([kw['path'], '--%s=%s' % (x, kw[y]), kw['package']])
 
273
                        if not 'okmsg' in kw:
 
274
                                kw['okmsg'] = 'yes'
 
275
                        self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
 
276
                        break
 
277
 
 
278
        # retrieving the version of a module
 
279
        if 'modversion' in kw:
 
280
                version = self.cmd_and_log([kw['path'], '--modversion', kw['modversion']]).strip()
 
281
                self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)
 
282
                return version
 
283
 
 
284
        lst = [kw['path']]
 
285
 
 
286
        defi = kw.get('define_variable', None)
 
287
        if not defi:
 
288
                defi = self.env.PKG_CONFIG_DEFINES or {}
 
289
        for key, val in defi.items():
 
290
                lst.append('--define-variable=%s=%s' % (key, val))
 
291
 
 
292
        if kw['package']:
 
293
                lst.extend(Utils.to_list(kw['package']))
 
294
 
 
295
        # retrieving variables of a module
 
296
        if 'variables' in kw:
 
297
                env = kw.get('env', self.env)
 
298
                uselib = kw.get('uselib_store', kw['package'].upper())
 
299
                vars = Utils.to_list(kw['variables'])
 
300
                for v in vars:
 
301
                        val = self.cmd_and_log(lst + ['--variable=' + v]).strip()
 
302
                        var = '%s_%s' % (uselib, v)
 
303
                        env[var] = val
 
304
                if not 'okmsg' in kw:
 
305
                        kw['okmsg'] = 'yes'
 
306
                return
 
307
 
 
308
        static = False
 
309
        if 'args' in kw:
 
310
                args = Utils.to_list(kw['args'])
 
311
                if '--static' in args or '--static-libs' in args:
 
312
                        static = True
 
313
                lst += args
 
314
        # so we assume the command-line will output flags to be parsed afterwards
 
315
        ret = self.cmd_and_log(lst)
 
316
        if not 'okmsg' in kw:
 
317
                kw['okmsg'] = 'yes'
 
318
 
 
319
        self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
 
320
        self.parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env), force_static=static)
 
321
        return ret
 
322
 
 
323
@conf
 
324
def check_cfg(self, *k, **kw):
 
325
        """
 
326
        Check for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
 
327
        Encapsulate the calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
 
328
 
 
329
        A few examples::
 
330
 
 
331
                def configure(conf):
 
332
                        conf.load('compiler_c')
 
333
                        conf.check_cfg(package='glib-2.0', args='--libs --cflags')
 
334
                        conf.check_cfg(package='glib-2.0', uselib_store='GLIB', atleast_version='2.10.0',
 
335
                                args='--cflags --libs')
 
336
                        conf.check_cfg(package='pango')
 
337
                        conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])
 
338
                        conf.check_cfg(package='pango',
 
339
                                args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'],
 
340
                                msg="Checking for 'pango 0.1.0'")
 
341
                        conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')
 
342
                        conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',
 
343
                                package='', uselib_store='OPEN_MPI', mandatory=False)
 
344
 
 
345
        """
 
346
        if k:
 
347
                lst = k[0].split()
 
348
                kw['package'] = lst[0]
 
349
                kw['args'] = ' '.join(lst[1:])
 
350
 
 
351
        self.validate_cfg(kw)
 
352
        if 'msg' in kw:
 
353
                self.start_msg(kw['msg'])
 
354
        ret = None
 
355
        try:
 
356
                ret = self.exec_cfg(kw)
 
357
        except self.errors.WafError as e:
 
358
                if 'errmsg' in kw:
 
359
                        self.end_msg(kw['errmsg'], 'YELLOW')
 
360
                if Logs.verbose > 1:
 
361
                        raise
 
362
                else:
 
363
                        self.fatal('The configuration failed')
 
364
        else:
 
365
                kw['success'] = ret
 
366
                if 'okmsg' in kw:
 
367
                        self.end_msg(self.ret_msg(kw['okmsg'], kw))
 
368
 
 
369
        return ret
 
370
 
 
371
@conf
 
372
def validate_c(self, kw):
 
373
        """
 
374
        pre-check the parameters that will be given to run_c_code
 
375
 
 
376
        :param env: an optional environment (modified -> provide a copy)
 
377
        :type env: :py:class:`waflib.ConfigSet.ConfigSet`
 
378
        :param compiler: c or cxx (tries to guess what is best)
 
379
        :type compiler: string
 
380
        :param type: cprogram, cshlib, cstlib - not required if *features are given directly*
 
381
        :type type: binary to create
 
382
        :param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib``
 
383
        :type feature: list of string
 
384
        :param fragment: provide a piece of code for the test (default is to let the system create one)
 
385
        :type fragment: string
 
386
        :param uselib_store: define variables after the test is executed (IMPORTANT!)
 
387
        :type uselib_store: string
 
388
        :param use: parameters to use for building (just like the normal *use* keyword)
 
389
        :type use: list of string
 
390
        :param define_name: define to set when the check is over
 
391
        :type define_name: string
 
392
        :param execute: execute the resulting binary
 
393
        :type execute: bool
 
394
        :param define_ret: if execute is set to True, use the execution output in both the define and the return value
 
395
        :type define_ret: bool
 
396
        :param header_name: check for a particular header
 
397
        :type header_name: string
 
398
        :param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers
 
399
        :type auto_add_header_name: bool
 
400
        """
 
401
 
 
402
        if not 'env' in kw:
 
403
                kw['env'] = self.env.derive()
 
404
        env = kw['env']
 
405
 
 
406
        if not 'compiler' in kw and not 'features' in kw:
 
407
                kw['compiler'] = 'c'
 
408
                if env['CXX_NAME'] and Task.classes.get('cxx', None):
 
409
                        kw['compiler'] = 'cxx'
 
410
                        if not self.env['CXX']:
 
411
                                self.fatal('a c++ compiler is required')
 
412
                else:
 
413
                        if not self.env['CC']:
 
414
                                self.fatal('a c compiler is required')
 
415
 
 
416
        if not 'compile_mode' in kw:
 
417
                kw['compile_mode'] = 'c'
 
418
                if 'cxx' in Utils.to_list(kw.get('features',[])) or kw.get('compiler', '') == 'cxx':
 
419
                        kw['compile_mode'] = 'cxx'
 
420
 
 
421
        if not 'type' in kw:
 
422
                kw['type'] = 'cprogram'
 
423
 
 
424
        if not 'features' in kw:
 
425
                kw['features'] = [kw['compile_mode'], kw['type']] # "cprogram c"
 
426
        else:
 
427
                kw['features'] = Utils.to_list(kw['features'])
 
428
 
 
429
        if not 'compile_filename' in kw:
 
430
                kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
 
431
 
 
432
 
 
433
        def to_header(dct):
 
434
                if 'header_name' in dct:
 
435
                        dct = Utils.to_list(dct['header_name'])
 
436
                        return ''.join(['#include <%s>\n' % x for x in dct])
 
437
                return ''
 
438
 
 
439
        #OSX
 
440
        if 'framework_name' in kw:
 
441
                fwkname = kw['framework_name']
 
442
                if not 'uselib_store' in kw:
 
443
                        kw['uselib_store'] = fwkname.upper()
 
444
 
 
445
                if not kw.get('no_header', False):
 
446
                        if not 'header_name' in kw:
 
447
                                kw['header_name'] = []
 
448
                        fwk = '%s/%s.h' % (fwkname, fwkname)
 
449
                        if kw.get('remove_dot_h', None):
 
450
                                fwk = fwk[:-2]
 
451
                        kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]
 
452
 
 
453
                kw['msg'] = 'Checking for framework %s' % fwkname
 
454
                kw['framework'] = fwkname
 
455
                #kw['frameworkpath'] = set it yourself
 
456
 
 
457
        if 'function_name' in kw:
 
458
                fu = kw['function_name']
 
459
                if not 'msg' in kw:
 
460
                        kw['msg'] = 'Checking for function %s' % fu
 
461
                kw['code'] = to_header(kw) + SNIP_FUNCTION % fu
 
462
                if not 'uselib_store' in kw:
 
463
                        kw['uselib_store'] = fu.upper()
 
464
                if not 'define_name' in kw:
 
465
                        kw['define_name'] = self.have_define(fu)
 
466
 
 
467
        elif 'type_name' in kw:
 
468
                tu = kw['type_name']
 
469
                if not 'header_name' in kw:
 
470
                        kw['header_name'] = 'stdint.h'
 
471
                if 'field_name' in kw:
 
472
                        field = kw['field_name']
 
473
                        kw['code'] = to_header(kw) + SNIP_FIELD % {'type_name' : tu, 'field_name' : field}
 
474
                        if not 'msg' in kw:
 
475
                                kw['msg'] = 'Checking for field %s in %s' % (field, tu)
 
476
                        if not 'define_name' in kw:
 
477
                                kw['define_name'] = self.have_define((tu + '_' + field).upper())
 
478
                else:
 
479
                        kw['code'] = to_header(kw) + SNIP_TYPE % {'type_name' : tu}
 
480
                        if not 'msg' in kw:
 
481
                                kw['msg'] = 'Checking for type %s' % tu
 
482
                        if not 'define_name' in kw:
 
483
                                kw['define_name'] = self.have_define(tu.upper())
 
484
 
 
485
        elif 'header_name' in kw:
 
486
                if not 'msg' in kw:
 
487
                        kw['msg'] = 'Checking for header %s' % kw['header_name']
 
488
 
 
489
                l = Utils.to_list(kw['header_name'])
 
490
                assert len(l)>0, 'list of headers in header_name is empty'
 
491
 
 
492
                kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM
 
493
 
 
494
                if not 'uselib_store' in kw:
 
495
                        kw['uselib_store'] = l[0].upper()
 
496
 
 
497
                if not 'define_name' in kw:
 
498
                        kw['define_name'] = self.have_define(l[0])
 
499
 
 
500
        if 'lib' in kw:
 
501
                if not 'msg' in kw:
 
502
                        kw['msg'] = 'Checking for library %s' % kw['lib']
 
503
                if not 'uselib_store' in kw:
 
504
                        kw['uselib_store'] = kw['lib'].upper()
 
505
 
 
506
        if 'stlib' in kw:
 
507
                if not 'msg' in kw:
 
508
                        kw['msg'] = 'Checking for static library %s' % kw['stlib']
 
509
                if not 'uselib_store' in kw:
 
510
                        kw['uselib_store'] = kw['stlib'].upper()
 
511
 
 
512
        if 'fragment' in kw:
 
513
                # an additional code fragment may be provided to replace the predefined code
 
514
                # in custom headers
 
515
                kw['code'] = kw['fragment']
 
516
                if not 'msg' in kw:
 
517
                        kw['msg'] = 'Checking for code snippet'
 
518
                if not 'errmsg' in kw:
 
519
                        kw['errmsg'] = 'no'
 
520
 
 
521
        for (flagsname,flagstype) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:
 
522
                if flagsname in kw:
 
523
                        if not 'msg' in kw:
 
524
                                kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])
 
525
                        if not 'errmsg' in kw:
 
526
                                kw['errmsg'] = 'no'
 
527
 
 
528
        if not 'execute' in kw:
 
529
                kw['execute'] = False
 
530
        if kw['execute']:
 
531
                kw['features'].append('test_exec')
 
532
 
 
533
        if not 'errmsg' in kw:
 
534
                kw['errmsg'] = 'not found'
 
535
 
 
536
        if not 'okmsg' in kw:
 
537
                kw['okmsg'] = 'yes'
 
538
 
 
539
        if not 'code' in kw:
 
540
                kw['code'] = SNIP_EMPTY_PROGRAM
 
541
 
 
542
        # if there are headers to append automatically to the next tests
 
543
        if self.env[INCKEYS]:
 
544
                kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code']
 
545
 
 
546
        if not kw.get('success'): kw['success'] = None
 
547
 
 
548
        if 'define_name' in kw:
 
549
                self.undefine(kw['define_name'])
 
550
 
 
551
        assert 'msg' in kw, 'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c'
 
552
 
 
553
@conf
 
554
def post_check(self, *k, **kw):
 
555
        "Set the variables after a test executed in :py:func:`waflib.Tools.c_config.check` was run successfully"
 
556
 
 
557
        is_success = 0
 
558
        if kw['execute']:
 
559
                if kw['success'] is not None:
 
560
                        if kw.get('define_ret', False):
 
561
                                is_success = kw['success']
 
562
                        else:
 
563
                                is_success = (kw['success'] == 0)
 
564
        else:
 
565
                is_success = (kw['success'] == 0)
 
566
 
 
567
        if 'define_name' in kw:
 
568
                # TODO simplify?
 
569
                if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
 
570
                        nm = kw['define_name']
 
571
                        if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):
 
572
                                self.define(kw['define_name'], is_success, quote=kw.get('quote', 1))
 
573
                        else:
 
574
                                self.define_cond(kw['define_name'], is_success)
 
575
                else:
 
576
                        self.define_cond(kw['define_name'], is_success)
 
577
 
 
578
        if 'header_name' in kw:
 
579
                if kw.get('auto_add_header_name', False):
 
580
                        self.env.append_value(INCKEYS, Utils.to_list(kw['header_name']))
 
581
 
 
582
        if is_success and 'uselib_store' in kw:
 
583
                from waflib.Tools import ccroot
 
584
 
 
585
                # TODO see get_uselib_vars from ccroot.py
 
586
                _vars = set([])
 
587
                for x in kw['features']:
 
588
                        if x in ccroot.USELIB_VARS:
 
589
                                _vars |= ccroot.USELIB_VARS[x]
 
590
 
 
591
                for k in _vars:
 
592
                        lk = k.lower()
 
593
                        if k == 'INCLUDES': lk = 'includes'
 
594
                        if k == 'DEFINES': lk = 'defines'
 
595
                        if lk in kw:
 
596
                                val = kw[lk]
 
597
                                # remove trailing slash
 
598
                                if isinstance(val, str):
 
599
                                        val = val.rstrip(os.path.sep)
 
600
                                self.env.append_unique(k + '_' + kw['uselib_store'], val)
 
601
        return is_success
 
602
 
 
603
@conf
 
604
def check(self, *k, **kw):
 
605
        """
 
606
        Perform a configuration test by calling :py:func:`waflib.Tools.c_config.run_c_code`.
 
607
        For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
 
608
        To force a specific compiler, prefer the methods :py:func:`waflib.Tools.c_config.check_cxx` or :py:func:`waflib.Tools.c_config.check_cc`
 
609
        """
 
610
        self.validate_c(kw)
 
611
        self.start_msg(kw['msg'])
 
612
        ret = None
 
613
        try:
 
614
                ret = self.run_c_code(*k, **kw)
 
615
        except self.errors.ConfigurationError as e:
 
616
                self.end_msg(kw['errmsg'], 'YELLOW')
 
617
                if Logs.verbose > 1:
 
618
                        raise
 
619
                else:
 
620
                        self.fatal('The configuration failed')
 
621
        else:
 
622
                kw['success'] = ret
 
623
                self.end_msg(self.ret_msg(kw['okmsg'], kw))
 
624
 
 
625
        ret = self.post_check(*k, **kw)
 
626
        if not ret:
 
627
                self.fatal('The configuration failed %r' % ret)
 
628
        return ret
 
629
 
 
630
class test_exec(Task.Task):
 
631
        """
 
632
        A task for executing a programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
 
633
        """
 
634
        color = 'PINK'
 
635
        def run(self):
 
636
                if getattr(self.generator, 'rpath', None):
 
637
                        if getattr(self.generator, 'define_ret', False):
 
638
                                self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()])
 
639
                        else:
 
640
                                self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()])
 
641
                else:
 
642
                        env = self.env.env or {}
 
643
                        env.update(dict(os.environ))
 
644
                        for var in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):
 
645
                                env[var] = self.inputs[0].parent.abspath() + os.path.pathsep + env.get(var, '')
 
646
                        if getattr(self.generator, 'define_ret', False):
 
647
                                self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()], env=env)
 
648
                        else:
 
649
                                self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()], env=env)
 
650
 
 
651
@feature('test_exec')
 
652
@after_method('apply_link')
 
653
def test_exec_fun(self):
 
654
        """
 
655
        The feature **test_exec** is used to create a task that will to execute the binary
 
656
        created (link task output) during the build. The exit status will be set
 
657
        on the build context, so only one program may have the feature *test_exec*.
 
658
        This is used by configuration tests::
 
659
 
 
660
                def configure(conf):
 
661
                        conf.check(execute=True)
 
662
        """
 
663
        self.create_task('test_exec', self.link_task.outputs[0])
 
664
 
 
665
CACHE_RESULTS = 1
 
666
COMPILE_ERRORS = 2
 
667
 
 
668
@conf
 
669
def run_c_code(self, *k, **kw):
 
670
        """
 
671
        Create a temporary build context to execute a build. A reference to that build
 
672
        context is kept on self.test_bld for debugging purposes, and you should not rely
 
673
        on it too much (read the note on the cache below).
 
674
        The parameters given in the arguments to this function are passed as arguments for
 
675
        a single task generator created in the build. Only three parameters are obligatory:
 
676
 
 
677
        :param features: features to pass to a task generator created in the build
 
678
        :type features: list of string
 
679
        :param compile_filename: file to create for the compilation (default: *test.c*)
 
680
        :type compile_filename: string
 
681
        :param code: code to write in the filename to compile
 
682
        :type code: string
 
683
 
 
684
        Though this function returns *0* by default, the build may set an attribute named *retval* on the
 
685
        build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.
 
686
 
 
687
        This function also provides a limited cache. To use it, provide the following option::
 
688
 
 
689
                def options(opt):
 
690
                        opt.add_option('--confcache', dest='confcache', default=0,
 
691
                                action='count', help='Use a configuration cache')
 
692
 
 
693
        And execute the configuration with the following command-line::
 
694
 
 
695
                $ waf configure --confcache
 
696
 
 
697
        """
 
698
 
 
699
        lst = [str(v) for (p, v) in kw.items() if p != 'env']
 
700
        h = Utils.h_list(lst)
 
701
        dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)
 
702
 
 
703
        try:
 
704
                os.makedirs(dir)
 
705
        except:
 
706
                pass
 
707
 
 
708
        try:
 
709
                os.stat(dir)
 
710
        except:
 
711
                self.fatal('cannot use the configuration test folder %r' % dir)
 
712
 
 
713
        cachemode = getattr(Options.options, 'confcache', None)
 
714
        if cachemode == CACHE_RESULTS:
 
715
                try:
 
716
                        proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_c_code'))
 
717
                        ret = proj['cache_run_c_code']
 
718
                except:
 
719
                        pass
 
720
                else:
 
721
                        if isinstance(ret, str) and ret.startswith('Test does not build'):
 
722
                                self.fatal(ret)
 
723
                        return ret
 
724
 
 
725
        bdir = os.path.join(dir, 'testbuild')
 
726
 
 
727
        if not os.path.exists(bdir):
 
728
                os.makedirs(bdir)
 
729
 
 
730
        self.test_bld = bld = Build.BuildContext(top_dir=dir, out_dir=bdir)
 
731
        bld.init_dirs()
 
732
        bld.progress_bar = 0
 
733
        bld.targets = '*'
 
734
 
 
735
        if kw['compile_filename']:
 
736
                node = bld.srcnode.make_node(kw['compile_filename'])
 
737
                node.write(kw['code'])
 
738
 
 
739
        bld.logger = self.logger
 
740
        bld.all_envs.update(self.all_envs) # not really necessary
 
741
        bld.env = kw['env']
 
742
 
 
743
        o = bld(features=kw['features'], source=kw['compile_filename'], target='testprog')
 
744
 
 
745
        for k, v in kw.items():
 
746
                setattr(o, k, v)
 
747
 
 
748
        self.to_log("==>\n%s\n<==" % kw['code'])
 
749
 
 
750
        # compile the program
 
751
        bld.targets = '*'
 
752
 
 
753
        ret = -1
 
754
        try:
 
755
                try:
 
756
                        bld.compile()
 
757
                except Errors.WafError:
 
758
                        ret = 'Test does not build: %s' % Utils.ex_stack()
 
759
                        self.fatal(ret)
 
760
                else:
 
761
                        ret = getattr(bld, 'retval', 0)
 
762
        finally:
 
763
                # cache the results each time
 
764
                proj = ConfigSet.ConfigSet()
 
765
                proj['cache_run_c_code'] = ret
 
766
                proj.store(os.path.join(dir, 'cache_run_c_code'))
 
767
 
 
768
        return ret
 
769
 
 
770
@conf
 
771
def check_cxx(self, *k, **kw):
 
772
        """
 
773
        Same as :py:func:`waflib.Tools.c_config.check` but default to the *c++* programming language
 
774
        """
 
775
        kw['compiler'] = 'cxx'
 
776
        return self.check(*k, **kw)
 
777
 
 
778
@conf
 
779
def check_cc(self, *k, **kw):
 
780
        """
 
781
        Same as :py:func:`waflib.Tools.c_config.check` but default to the *c* programming language
 
782
        """
 
783
        kw['compiler'] = 'c'
 
784
        return self.check(*k, **kw)
 
785
 
 
786
@conf
 
787
def define(self, key, val, quote=True):
 
788
        """
 
789
        Store a single define and its state into conf.env.DEFINES
 
790
 
 
791
        :param key: define name
 
792
        :type key: string
 
793
        :param val: value
 
794
        :type val: int or string
 
795
        :param quote: enclose strings in quotes (yes by default)
 
796
        :type quote: bool
 
797
        """
 
798
        assert key and isinstance(key, str)
 
799
 
 
800
        if isinstance(val, int) or isinstance(val, float):
 
801
                s = '%s=%s'
 
802
        else:
 
803
                s = quote and '%s="%s"' or '%s=%s'
 
804
        app = s % (key, str(val))
 
805
 
 
806
        ban = key + '='
 
807
        lst = self.env['DEFINES']
 
808
        for x in lst:
 
809
                if x.startswith(ban):
 
810
                        lst[lst.index(x)] = app
 
811
                        break
 
812
        else:
 
813
                self.env.append_value('DEFINES', app)
 
814
 
 
815
        self.env.append_unique(DEFKEYS, key)
 
816
 
 
817
@conf
 
818
def undefine(self, key):
 
819
        """
 
820
        Remove a define from conf.env.DEFINES
 
821
 
 
822
        :param key: define name
 
823
        :type key: string
 
824
        """
 
825
        assert key and isinstance(key, str)
 
826
 
 
827
        ban = key + '='
 
828
        lst = [x for x in self.env['DEFINES'] if not x.startswith(ban)]
 
829
        self.env['DEFINES'] = lst
 
830
        self.env.append_unique(DEFKEYS, key)
 
831
 
 
832
@conf
 
833
def define_cond(self, key, val):
 
834
        """
 
835
        Conditionally define a name::
 
836
 
 
837
                def configure(conf):
 
838
                        conf.define_cond('A', True)
 
839
                        # equivalent to:
 
840
                        # if val: conf.define('A', 1)
 
841
                        # else: conf.undefine('A')
 
842
 
 
843
        :param key: define name
 
844
        :type key: string
 
845
        :param val: value
 
846
        :type val: int or string
 
847
        """
 
848
        assert key and isinstance(key, str)
 
849
 
 
850
        if val:
 
851
                self.define(key, 1)
 
852
        else:
 
853
                self.undefine(key)
 
854
 
 
855
@conf
 
856
def is_defined(self, key):
 
857
        """
 
858
        :param key: define name
 
859
        :type key: string
 
860
        :return: True if the define is set
 
861
        :rtype: bool
 
862
        """
 
863
        assert key and isinstance(key, str)
 
864
 
 
865
        ban = key + '='
 
866
        for x in self.env['DEFINES']:
 
867
                if x.startswith(ban):
 
868
                        return True
 
869
        return False
 
870
 
 
871
@conf
 
872
def get_define(self, key):
 
873
        """
 
874
        :param key: define name
 
875
        :type key: string
 
876
        :return: the value of a previously stored define or None if it is not set
 
877
        """
 
878
        assert key and isinstance(key, str)
 
879
 
 
880
        ban = key + '='
 
881
        for x in self.env['DEFINES']:
 
882
                if x.startswith(ban):
 
883
                        return x[len(ban):]
 
884
        return None
 
885
 
 
886
@conf
 
887
def have_define(self, key):
 
888
        """
 
889
        :param key: define name
 
890
        :type key: string
 
891
        :return: the input key prefixed by *HAVE_* and substitute any invalid characters.
 
892
        :rtype: string
 
893
        """
 
894
        return self.__dict__.get('HAVE_PAT', 'HAVE_%s') % Utils.quote_define_name(key)
 
895
 
 
896
@conf
 
897
def write_config_header(self, configfile='', guard='', top=False, env=None, defines=True, headers=False, remove=True):
 
898
        """
 
899
        Write a configuration header containing defines and includes::
 
900
 
 
901
                def configure(cnf):
 
902
                        cnf.define('A', 1)
 
903
                        cnf.write_config_header('config.h')
 
904
 
 
905
        :param configfile: relative path to the file to create
 
906
        :type configfile: string
 
907
        :param env: config set to read the definitions from (default is conf.env)
 
908
        :type env: :py:class:`waflib.ConfigSet.ConfigSet`
 
909
        :param top: write the configuration header from the build directory (default is from the current path)
 
910
        :type top: bool
 
911
        :param defines: add the defines (yes by default)
 
912
        :type defines: bool
 
913
        :param headers: add #include in the file
 
914
        :type headers: bool
 
915
        :param remove: remove the defines after they are added (yes by default)
 
916
        :type remove: bool
 
917
        """
 
918
        if not configfile: configfile = WAF_CONFIG_H
 
919
        waf_guard = guard or '_%s_WAF' % Utils.quote_define_name(configfile)
 
920
 
 
921
        node = top and self.bldnode or self.path.get_bld()
 
922
        node = node.make_node(configfile)
 
923
        node.parent.mkdir()
 
924
 
 
925
        lst = ['/* WARNING! All changes made to this file will be lost! */\n']
 
926
        lst.append('#ifndef %s\n#define %s\n' % (waf_guard, waf_guard))
 
927
        lst.append(self.get_config_header(defines, headers))
 
928
        lst.append('\n#endif /* %s */\n' % waf_guard)
 
929
 
 
930
        node.write('\n'.join(lst))
 
931
 
 
932
        env = env or self.env
 
933
 
 
934
        # config files are not removed on "waf clean"
 
935
        env.append_unique(Build.CFG_FILES, [node.abspath()])
 
936
 
 
937
        if remove:
 
938
                for key in self.env[DEFKEYS]:
 
939
                        self.undefine(key)
 
940
                self.env[DEFKEYS] = []
 
941
 
 
942
@conf
 
943
def get_config_header(self, defines=True, headers=False):
 
944
        """
 
945
        Create the contents of a ``config.h`` file from the defines and includes
 
946
        set in conf.env.define_key / conf.env.include_key. No include guards are added.
 
947
 
 
948
        :param defines: write the defines values
 
949
        :type defines: bool
 
950
        :param headers: write the headers
 
951
        :type headers: bool
 
952
        :return: the contents of a ``config.h`` file
 
953
        :rtype: string
 
954
        """
 
955
        lst = []
 
956
        if headers:
 
957
                for x in self.env[INCKEYS]:
 
958
                        lst.append('#include <%s>' % x)
 
959
 
 
960
        if defines:
 
961
                for x in self.env[DEFKEYS]:
 
962
                        if self.is_defined(x):
 
963
                                val = self.get_define(x)
 
964
                                lst.append('#define %s %s' % (x, val))
 
965
                        else:
 
966
                                lst.append('/* #undef %s */' % x)
 
967
        return "\n".join(lst)
 
968
 
 
969
@conf
 
970
def cc_add_flags(conf):
 
971
        """
 
972
        Read the CFLAGS/CPPFLAGS from os.environ and add to conf.env.CFLAGS
 
973
        """
 
974
        conf.add_os_flags('CPPFLAGS', 'CFLAGS')
 
975
        conf.add_os_flags('CFLAGS')
 
976
 
 
977
@conf
 
978
def cxx_add_flags(conf):
 
979
        """
 
980
        Read the CXXFLAGS/CPPFLAGS and add to conf.env.CXXFLAGS
 
981
        """
 
982
        conf.add_os_flags('CPPFLAGS', 'CXXFLAGS')
 
983
        conf.add_os_flags('CXXFLAGS')
 
984
 
 
985
@conf
 
986
def link_add_flags(conf):
 
987
        """
 
988
        Read the LINKFLAGS/LDFLAGS and add to conf.env.LDFLAGS
 
989
        """
 
990
        conf.add_os_flags('LINKFLAGS')
 
991
        conf.add_os_flags('LDFLAGS', 'LINKFLAGS')
 
992
 
 
993
@conf
 
994
def cc_load_tools(conf):
 
995
        """
 
996
        Load the c tool
 
997
        """
 
998
        if not conf.env.DEST_OS:
 
999
                conf.env.DEST_OS = Utils.unversioned_sys_platform()
 
1000
        conf.load('c')
 
1001
 
 
1002
@conf
 
1003
def cxx_load_tools(conf):
 
1004
        """
 
1005
        Load the cxx tool
 
1006
        """
 
1007
        if not conf.env.DEST_OS:
 
1008
                conf.env.DEST_OS = Utils.unversioned_sys_platform()
 
1009
        conf.load('cxx')
 
1010
 
 
1011
@conf
 
1012
def get_cc_version(conf, cc, gcc=False, icc=False):
 
1013
        """
 
1014
        Run the preprocessor to determine the compiler version
 
1015
 
 
1016
        The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
 
1017
        """
 
1018
        cmd = cc + ['-dM', '-E', '-']
 
1019
        env = conf.env.env or None
 
1020
        try:
 
1021
                p = Utils.subprocess.Popen(cmd, stdin=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)
 
1022
                p.stdin.write('\n'.encode())
 
1023
                out = p.communicate()[0]
 
1024
        except:
 
1025
                conf.fatal('Could not determine the compiler version %r' % cmd)
 
1026
 
 
1027
        if not isinstance(out, str):
 
1028
                out = out.decode(sys.stdout.encoding)
 
1029
 
 
1030
        if gcc:
 
1031
                if out.find('__INTEL_COMPILER') >= 0:
 
1032
                        conf.fatal('The intel compiler pretends to be gcc')
 
1033
                if out.find('__GNUC__') < 0:
 
1034
                        conf.fatal('Could not determine the compiler type')
 
1035
 
 
1036
        if icc and out.find('__INTEL_COMPILER') < 0:
 
1037
                conf.fatal('Not icc/icpc')
 
1038
 
 
1039
        k = {}
 
1040
        if icc or gcc:
 
1041
                out = out.split('\n')
 
1042
                for line in out:
 
1043
                        lst = shlex.split(line)
 
1044
                        if len(lst)>2:
 
1045
                                key = lst[1]
 
1046
                                val = lst[2]
 
1047
                                k[key] = val
 
1048
 
 
1049
                def isD(var):
 
1050
                        return var in k
 
1051
 
 
1052
                def isT(var):
 
1053
                        return var in k and k[var] != '0'
 
1054
 
 
1055
                # Some documentation is available at http://predef.sourceforge.net
 
1056
                # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
 
1057
                if not conf.env.DEST_OS:
 
1058
                        conf.env.DEST_OS = ''
 
1059
                for i in MACRO_TO_DESTOS:
 
1060
                        if isD(i):
 
1061
                                conf.env.DEST_OS = MACRO_TO_DESTOS[i]
 
1062
                                break
 
1063
                else:
 
1064
                        if isD('__APPLE__') and isD('__MACH__'):
 
1065
                                conf.env.DEST_OS = 'darwin'
 
1066
                        elif isD('__unix__'): # unix must be tested last as it's a generic fallback
 
1067
                                conf.env.DEST_OS = 'generic'
 
1068
 
 
1069
                if isD('__ELF__'):
 
1070
                        conf.env.DEST_BINFMT = 'elf'
 
1071
                elif isD('__WINNT__') or isD('__CYGWIN__'):
 
1072
                        conf.env.DEST_BINFMT = 'pe'
 
1073
                        conf.env.LIBDIR = conf.env['PREFIX'] + '/bin'
 
1074
                elif isD('__APPLE__'):
 
1075
                        conf.env.DEST_BINFMT = 'mac-o'
 
1076
 
 
1077
                if not conf.env.DEST_BINFMT:
 
1078
                        # Infer the binary format from the os name.
 
1079
                        conf.env.DEST_BINFMT = Utils.destos_to_binfmt(conf.env.DEST_OS)
 
1080
 
 
1081
                for i in MACRO_TO_DEST_CPU:
 
1082
                        if isD(i):
 
1083
                                conf.env.DEST_CPU = MACRO_TO_DEST_CPU[i]
 
1084
                                break
 
1085
 
 
1086
                Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
 
1087
                if icc:
 
1088
                        ver = k['__INTEL_COMPILER']
 
1089
                        conf.env['CC_VERSION'] = (ver[:-2], ver[-2], ver[-1])
 
1090
                else:
 
1091
                        conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
 
1092
        return k
 
1093
 
 
1094
@conf
 
1095
def get_xlc_version(conf, cc):
 
1096
        """Get the compiler version"""
 
1097
 
 
1098
        version_re = re.compile(r"IBM XL C/C\+\+.*, V(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
 
1099
        cmd = cc + ['-qversion']
 
1100
 
 
1101
        try:
 
1102
                out, err = conf.cmd_and_log(cmd, output=0)
 
1103
        except Errors.WafError:
 
1104
                conf.fatal('Could not find xlc %r' % cmd)
 
1105
        if out: match = version_re(out)
 
1106
        else: match = version_re(err)
 
1107
        if not match:
 
1108
                conf.fatal('Could not determine the XLC version.')
 
1109
        k = match.groupdict()
 
1110
        conf.env['CC_VERSION'] = (k['major'], k['minor'])
 
1111
 
 
1112
# ============ the --as-needed flag should added during the configuration, not at runtime =========
 
1113
 
 
1114
@conf
 
1115
def add_as_needed(self):
 
1116
        """
 
1117
        Add ``--as-needed`` to the *LINKFLAGS*
 
1118
        """
 
1119
        if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME):
 
1120
                self.env.append_unique('LINKFLAGS', '--as-needed')
 
1121
 
 
1122
# ============ parallel configuration
 
1123
 
 
1124
class cfgtask(Task.TaskBase):
 
1125
        """
 
1126
        A task that executes configuration tests
 
1127
        make sure that the checks write to conf.env in a thread-safe manner
 
1128
 
 
1129
        for the moment it only executes conf.check
 
1130
        """
 
1131
        def display(self):
 
1132
                return ''
 
1133
 
 
1134
        def runnable_status(self):
 
1135
                return Task.RUN_ME
 
1136
 
 
1137
        def run(self):
 
1138
                conf = self.conf
 
1139
                bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())
 
1140
                bld.env = conf.env
 
1141
                bld.init_dirs()
 
1142
                bld.in_msg = 1 # suppress top-level start_msg
 
1143
                bld.logger = self.logger
 
1144
                try:
 
1145
                        bld.check(**self.args)
 
1146
                except:
 
1147
                        return 1
 
1148
 
 
1149
@conf
 
1150
def multicheck(self, *k, **kw):
 
1151
        """
 
1152
        Use tuples to perform parallel configuration tests
 
1153
        """
 
1154
        self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)))
 
1155
 
 
1156
        class par(object):
 
1157
                def __init__(self):
 
1158
                        self.keep = False
 
1159
                        self.cache_global = Options.cache_global
 
1160
                        self.nocache = Options.options.nocache
 
1161
                        self.returned_tasks = []
 
1162
                def total(self):
 
1163
                        return len(tasks)
 
1164
                def to_log(self, *k, **kw):
 
1165
                        return
 
1166
 
 
1167
        bld = par()
 
1168
        tasks = []
 
1169
        for dct in k:
 
1170
                x = cfgtask(bld=bld)
 
1171
                tasks.append(x)
 
1172
                x.args = dct
 
1173
                x.bld = bld
 
1174
                x.conf = self
 
1175
                x.args = dct
 
1176
 
 
1177
                # bind a logger that will keep the info in memory
 
1178
                x.logger = Logs.make_mem_logger(str(id(x)), self.logger)
 
1179
 
 
1180
        def it():
 
1181
                yield tasks
 
1182
                while 1:
 
1183
                        yield []
 
1184
        p = Runner.Parallel(bld, Options.options.jobs)
 
1185
        p.biter = it()
 
1186
        p.start()
 
1187
 
 
1188
        # flush the logs in order into the config.log
 
1189
        for x in tasks:
 
1190
                x.logger.memhandler.flush()
 
1191
 
 
1192
        for x in tasks:
 
1193
                if x.hasrun != Task.SUCCESS:
 
1194
                        self.end_msg(kw.get('errmsg', 'no'), color='YELLOW')
 
1195
                        self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, see the config.log for more information')
 
1196
 
 
1197
        self.end_msg('ok')
 
1198