libcli: SMB2: Pure SMB2-only negprot fix to make us behave as a Windows client does.
[Samba.git] / buildtools / wafadmin / Tools / config_c.py
blobd0bc61773625576cec1d0b1eec2635086d04c2e7
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2005-2008 (ita)
5 """
6 c/c++ configuration routines
7 """
9 import os, imp, sys, shlex, shutil
10 from Utils import md5
11 import Build, Utils, Configure, Task, Options, Logs, TaskGen
12 from Constants import *
13 from Configure import conf, conftest
15 cfg_ver = {
16 'atleast-version': '>=',
17 'exact-version': '==',
18 'max-version': '<=',
21 SNIP1 = '''
22 int main() {
23 void *p;
24 p=(void*)(%s);
25 return 0;
27 '''
29 SNIP2 = '''
30 int main() {
31 if ((%(type_name)s *) 0) return 0;
32 if (sizeof (%(type_name)s)) return 0;
34 '''
36 SNIP3 = '''
37 int main() {
38 return 0;
40 '''
42 def parse_flags(line, uselib, env):
43 """pkg-config still has bugs on some platforms, and there are many -config programs, parsing flags is necessary :-/"""
45 lst = shlex.split(line)
46 while lst:
47 x = lst.pop(0)
48 st = x[:2]
49 ot = x[2:]
50 app = env.append_value
51 if st == '-I' or st == '/I':
52 if not ot: ot = lst.pop(0)
53 app('CPPPATH_' + uselib, ot)
54 elif st == '-D':
55 if not ot: ot = lst.pop(0)
56 app('CXXDEFINES_' + uselib, ot)
57 app('CCDEFINES_' + uselib, ot)
58 elif st == '-l':
59 if not ot: ot = lst.pop(0)
60 app('LIB_' + uselib, ot)
61 elif st == '-L':
62 if not ot: ot = lst.pop(0)
63 app('LIBPATH_' + uselib, ot)
64 elif x == '-pthread' or x.startswith('+'):
65 app('CCFLAGS_' + uselib, x)
66 app('CXXFLAGS_' + uselib, x)
67 app('LINKFLAGS_' + uselib, x)
68 elif x == '-framework':
69 app('FRAMEWORK_' + uselib, lst.pop(0))
70 elif x.startswith('-F'):
71 app('FRAMEWORKPATH_' + uselib, x[2:])
72 elif x.startswith('-std'):
73 app('CCFLAGS_' + uselib, x)
74 app('CXXFLAGS_' + uselib, x)
75 app('LINKFLAGS_' + uselib, x)
77 # NOTE on special treatment of -Wl,-R and -Wl,-rpath:
79 # It is important to not put a library provided RPATH
80 # into the LINKFLAGS but in the RPATH instead, since
81 # the provided LINKFLAGS get prepended to our own internal
82 # RPATH later, and hence can potentially lead to linking
83 # in too old versions of our internal libs.
85 elif x.startswith('-Wl,-R'):
86 app('RPATH_' + uselib, x[6:])
87 elif x.startswith('-Wl,-rpath,'):
88 app('RPATH_' + uselib, x[11:])
89 elif x.startswith('-Wl'):
90 app('LINKFLAGS_' + uselib, x)
91 elif x.startswith('-m') or x.startswith('-f'):
92 app('CCFLAGS_' + uselib, x)
93 app('CXXFLAGS_' + uselib, x)
95 @conf
96 def ret_msg(self, f, kw):
97 """execute a function, when provided"""
98 if isinstance(f, str):
99 return f
100 return f(kw)
102 @conf
103 def validate_cfg(self, kw):
104 if not 'path' in kw:
105 kw['path'] = 'pkg-config --errors-to-stdout --print-errors'
107 # pkg-config version
108 if 'atleast_pkgconfig_version' in kw:
109 if not 'msg' in kw:
110 kw['msg'] = 'Checking for pkg-config version >= %s' % kw['atleast_pkgconfig_version']
111 return
113 # pkg-config --modversion
114 if 'modversion' in kw:
115 return
117 if 'variables' in kw:
118 if not 'msg' in kw:
119 kw['msg'] = 'Checking for %s variables' % kw['package']
120 return
122 # checking for the version of a module, for the moment, one thing at a time
123 for x in cfg_ver.keys():
124 y = x.replace('-', '_')
125 if y in kw:
126 if not 'package' in kw:
127 raise ValueError('%s requires a package' % x)
129 if not 'msg' in kw:
130 kw['msg'] = 'Checking for %s %s %s' % (kw['package'], cfg_ver[x], kw[y])
131 return
133 if not 'msg' in kw:
134 kw['msg'] = 'Checking for %s' % (kw['package'] or kw['path'])
135 if not 'okmsg' in kw:
136 kw['okmsg'] = 'yes'
137 if not 'errmsg' in kw:
138 kw['errmsg'] = 'not found'
140 @conf
141 def cmd_and_log(self, cmd, kw):
142 Logs.debug('runner: %s\n' % cmd)
143 if self.log:
144 self.log.write('%s\n' % cmd)
146 try:
147 p = Utils.pproc.Popen(cmd, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE, shell=True)
148 (out, err) = p.communicate()
149 except OSError, e:
150 self.log.write('error %r' % e)
151 self.fatal(str(e))
153 # placeholder, don't touch
154 out = str(out)
155 err = str(err)
157 if self.log:
158 self.log.write(out)
159 self.log.write(err)
161 if p.returncode:
162 if not kw.get('errmsg', ''):
163 if kw.get('mandatory', False):
164 kw['errmsg'] = out.strip()
165 else:
166 kw['errmsg'] = 'no'
167 self.fatal('fail')
168 return out
170 @conf
171 def exec_cfg(self, kw):
173 # pkg-config version
174 if 'atleast_pkgconfig_version' in kw:
175 cmd = '%s --atleast-pkgconfig-version=%s' % (kw['path'], kw['atleast_pkgconfig_version'])
176 self.cmd_and_log(cmd, kw)
177 if not 'okmsg' in kw:
178 kw['okmsg'] = 'yes'
179 return
181 # checking for the version of a module
182 for x in cfg_ver:
183 y = x.replace('-', '_')
184 if y in kw:
185 self.cmd_and_log('%s --%s=%s %s' % (kw['path'], x, kw[y], kw['package']), kw)
186 if not 'okmsg' in kw:
187 kw['okmsg'] = 'yes'
188 self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
189 break
191 # retrieving the version of a module
192 if 'modversion' in kw:
193 version = self.cmd_and_log('%s --modversion %s' % (kw['path'], kw['modversion']), kw).strip()
194 self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)
195 return version
197 # retrieving variables of a module
198 if 'variables' in kw:
199 env = kw.get('env', self.env)
200 uselib = kw.get('uselib_store', kw['package'].upper())
201 vars = Utils.to_list(kw['variables'])
202 for v in vars:
203 val = self.cmd_and_log('%s --variable=%s %s' % (kw['path'], v, kw['package']), kw).strip()
204 var = '%s_%s' % (uselib, v)
205 env[var] = val
206 if not 'okmsg' in kw:
207 kw['okmsg'] = 'yes'
208 return
210 lst = [kw['path']]
213 defi = kw.get('define_variable', None)
214 if not defi:
215 defi = self.env.PKG_CONFIG_DEFINES or {}
216 for key, val in defi.iteritems():
217 lst.append('--define-variable=%s=%s' % (key, val))
219 lst.append(kw.get('args', ''))
220 lst.append(kw['package'])
222 # so we assume the command-line will output flags to be parsed afterwards
223 cmd = ' '.join(lst)
224 ret = self.cmd_and_log(cmd, kw)
225 if not 'okmsg' in kw:
226 kw['okmsg'] = 'yes'
228 self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
229 parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env))
230 return ret
232 @conf
233 def check_cfg(self, *k, **kw):
235 for pkg-config mostly, but also all the -config tools
236 conf.check_cfg(path='mpicc', args='--showme:compile --showme:link', package='', uselib_store='OPEN_MPI')
237 conf.check_cfg(package='dbus-1', variables='system_bus_default_address session_bus_services_dir')
240 self.validate_cfg(kw)
241 if 'msg' in kw:
242 self.check_message_1(kw['msg'])
243 ret = None
244 try:
245 ret = self.exec_cfg(kw)
246 except Configure.ConfigurationError, e:
247 if 'errmsg' in kw:
248 self.check_message_2(kw['errmsg'], 'YELLOW')
249 if 'mandatory' in kw and kw['mandatory']:
250 if Logs.verbose > 1:
251 raise
252 else:
253 self.fatal('the configuration failed (see %r)' % self.log.name)
254 else:
255 kw['success'] = ret
256 if 'okmsg' in kw:
257 self.check_message_2(self.ret_msg(kw['okmsg'], kw))
259 return ret
261 # the idea is the following: now that we are certain
262 # that all the code here is only for c or c++, it is
263 # easy to put all the logic in one function
265 # this should prevent code duplication (ita)
267 # env: an optional environment (modified -> provide a copy)
268 # compiler: cc or cxx - it tries to guess what is best
269 # type: cprogram, cshlib, cstaticlib
270 # code: a c code to execute
271 # uselib_store: where to add the variables
272 # uselib: parameters to use for building
273 # define: define to set, like FOO in #define FOO, if not set, add /* #undef FOO */
274 # execute: True or False - will return the result of the execution
276 @conf
277 def validate_c(self, kw):
278 """validate the parameters for the test method"""
280 if not 'env' in kw:
281 kw['env'] = self.env.copy()
283 env = kw['env']
284 if not 'compiler' in kw:
285 kw['compiler'] = 'cc'
286 if env['CXX_NAME'] and Task.TaskBase.classes.get('cxx', None):
287 kw['compiler'] = 'cxx'
288 if not self.env['CXX']:
289 self.fatal('a c++ compiler is required')
290 else:
291 if not self.env['CC']:
292 self.fatal('a c compiler is required')
294 if not 'type' in kw:
295 kw['type'] = 'cprogram'
297 assert not(kw['type'] != 'cprogram' and kw.get('execute', 0)), 'can only execute programs'
300 #if kw['type'] != 'program' and kw.get('execute', 0):
301 # raise ValueError, 'can only execute programs'
303 def to_header(dct):
304 if 'header_name' in dct:
305 dct = Utils.to_list(dct['header_name'])
306 return ''.join(['#include <%s>\n' % x for x in dct])
307 return ''
309 # set the file name
310 if not 'compile_mode' in kw:
311 kw['compile_mode'] = (kw['compiler'] == 'cxx') and 'cxx' or 'cc'
313 if not 'compile_filename' in kw:
314 kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
316 #OSX
317 if 'framework_name' in kw:
318 try: TaskGen.task_gen.create_task_macapp
319 except AttributeError: self.fatal('frameworks require the osx tool')
321 fwkname = kw['framework_name']
322 if not 'uselib_store' in kw:
323 kw['uselib_store'] = fwkname.upper()
325 if not kw.get('no_header', False):
326 if not 'header_name' in kw:
327 kw['header_name'] = []
328 fwk = '%s/%s.h' % (fwkname, fwkname)
329 if kw.get('remove_dot_h', None):
330 fwk = fwk[:-2]
331 kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]
333 kw['msg'] = 'Checking for framework %s' % fwkname
334 kw['framework'] = fwkname
335 #kw['frameworkpath'] = set it yourself
337 if 'function_name' in kw:
338 fu = kw['function_name']
339 if not 'msg' in kw:
340 kw['msg'] = 'Checking for function %s' % fu
341 kw['code'] = to_header(kw) + SNIP1 % fu
342 if not 'uselib_store' in kw:
343 kw['uselib_store'] = fu.upper()
344 if not 'define_name' in kw:
345 kw['define_name'] = self.have_define(fu)
347 elif 'type_name' in kw:
348 tu = kw['type_name']
349 if not 'msg' in kw:
350 kw['msg'] = 'Checking for type %s' % tu
351 if not 'header_name' in kw:
352 kw['header_name'] = 'stdint.h'
353 kw['code'] = to_header(kw) + SNIP2 % {'type_name' : tu}
354 if not 'define_name' in kw:
355 kw['define_name'] = self.have_define(tu.upper())
357 elif 'header_name' in kw:
358 if not 'msg' in kw:
359 kw['msg'] = 'Checking for header %s' % kw['header_name']
361 l = Utils.to_list(kw['header_name'])
362 assert len(l)>0, 'list of headers in header_name is empty'
364 kw['code'] = to_header(kw) + SNIP3
366 if not 'uselib_store' in kw:
367 kw['uselib_store'] = l[0].upper()
369 if not 'define_name' in kw:
370 kw['define_name'] = self.have_define(l[0])
372 if 'lib' in kw:
373 if not 'msg' in kw:
374 kw['msg'] = 'Checking for library %s' % kw['lib']
375 if not 'uselib_store' in kw:
376 kw['uselib_store'] = kw['lib'].upper()
378 if 'staticlib' in kw:
379 if not 'msg' in kw:
380 kw['msg'] = 'Checking for static library %s' % kw['staticlib']
381 if not 'uselib_store' in kw:
382 kw['uselib_store'] = kw['staticlib'].upper()
384 if 'fragment' in kw:
385 # an additional code fragment may be provided to replace the predefined code
386 # in custom headers
387 kw['code'] = kw['fragment']
388 if not 'msg' in kw:
389 kw['msg'] = 'Checking for custom code'
390 if not 'errmsg' in kw:
391 kw['errmsg'] = 'no'
393 for (flagsname,flagstype) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:
394 if flagsname in kw:
395 if not 'msg' in kw:
396 kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])
397 if not 'errmsg' in kw:
398 kw['errmsg'] = 'no'
400 if not 'execute' in kw:
401 kw['execute'] = False
403 if not 'errmsg' in kw:
404 kw['errmsg'] = 'not found'
406 if not 'okmsg' in kw:
407 kw['okmsg'] = 'yes'
409 if not 'code' in kw:
410 kw['code'] = SNIP3
412 if not kw.get('success'): kw['success'] = None
414 assert 'msg' in kw, 'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c'
416 @conf
417 def post_check(self, *k, **kw):
418 "set the variables after a test was run successfully"
420 is_success = False
421 if kw['execute']:
422 if kw['success'] is not None:
423 is_success = True
424 else:
425 is_success = (kw['success'] == 0)
427 if 'define_name' in kw:
428 if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
429 if kw['execute']:
430 key = kw['success']
431 if isinstance(key, str):
432 if key:
433 self.define(kw['define_name'], key, quote=kw.get('quote', 1))
434 else:
435 self.define_cond(kw['define_name'], True)
436 else:
437 self.define_cond(kw['define_name'], False)
438 else:
439 self.define_cond(kw['define_name'], is_success)
441 if is_success and 'uselib_store' in kw:
442 import cc, cxx
443 for k in set(cc.g_cc_flag_vars).union(cxx.g_cxx_flag_vars):
444 lk = k.lower()
445 # inconsistency: includes -> CPPPATH
446 if k == 'CPPPATH': lk = 'includes'
447 if k == 'CXXDEFINES': lk = 'defines'
448 if k == 'CCDEFINES': lk = 'defines'
449 if lk in kw:
450 val = kw[lk]
451 # remove trailing slash
452 if isinstance(val, str):
453 val = val.rstrip(os.path.sep)
454 self.env.append_unique(k + '_' + kw['uselib_store'], val)
456 @conf
457 def check(self, *k, **kw):
458 # so this will be the generic function
459 # it will be safer to use check_cxx or check_cc
460 self.validate_c(kw)
461 self.check_message_1(kw['msg'])
462 ret = None
463 try:
464 ret = self.run_c_code(*k, **kw)
465 except Configure.ConfigurationError, e:
466 self.check_message_2(kw['errmsg'], 'YELLOW')
467 if 'mandatory' in kw and kw['mandatory']:
468 if Logs.verbose > 1:
469 raise
470 else:
471 self.fatal('the configuration failed (see %r)' % self.log.name)
472 else:
473 kw['success'] = ret
474 self.check_message_2(self.ret_msg(kw['okmsg'], kw))
476 self.post_check(*k, **kw)
477 if not kw.get('execute', False):
478 return ret == 0
479 return ret
481 @conf
482 def run_c_code(self, *k, **kw):
483 test_f_name = kw['compile_filename']
485 k = 0
486 while k < 10000:
487 # make certain to use a fresh folder - necessary for win32
488 dir = os.path.join(self.blddir, '.conf_check_%d' % k)
490 # if the folder already exists, remove it
491 try:
492 shutil.rmtree(dir)
493 except OSError:
494 pass
496 try:
497 os.stat(dir)
498 except OSError:
499 break
501 k += 1
503 try:
504 os.makedirs(dir)
505 except:
506 self.fatal('cannot create a configuration test folder %r' % dir)
508 try:
509 os.stat(dir)
510 except:
511 self.fatal('cannot use the configuration test folder %r' % dir)
513 bdir = os.path.join(dir, 'testbuild')
515 if not os.path.exists(bdir):
516 os.makedirs(bdir)
518 env = kw['env']
520 dest = open(os.path.join(dir, test_f_name), 'w')
521 dest.write(kw['code'])
522 dest.close()
524 back = os.path.abspath('.')
526 bld = Build.BuildContext()
527 bld.log = self.log
528 bld.all_envs.update(self.all_envs)
529 bld.all_envs['default'] = env
530 bld.lst_variants = bld.all_envs.keys()
531 bld.load_dirs(dir, bdir)
533 os.chdir(dir)
535 bld.rescan(bld.srcnode)
537 if not 'features' in kw:
538 # conf.check(features='cc cprogram pyext', ...)
539 kw['features'] = [kw['compile_mode'], kw['type']] # "cprogram cc"
541 o = bld(features=kw['features'], source=test_f_name, target='testprog')
543 for k, v in kw.iteritems():
544 setattr(o, k, v)
546 self.log.write("==>\n%s\n<==\n" % kw['code'])
548 # compile the program
549 try:
550 bld.compile()
551 except Utils.WafError:
552 ret = Utils.ex_stack()
553 else:
554 ret = 0
556 # chdir before returning
557 os.chdir(back)
559 if ret:
560 self.log.write('command returned %r' % ret)
561 self.fatal(str(ret))
563 # if we need to run the program, try to get its result
564 # keep the name of the program to execute
565 if kw['execute']:
566 lastprog = o.link_task.outputs[0].abspath(env)
568 args = Utils.to_list(kw.get('exec_args', []))
569 proc = Utils.pproc.Popen([lastprog] + args, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE)
570 (out, err) = proc.communicate()
571 w = self.log.write
572 w(str(out))
573 w('\n')
574 w(str(err))
575 w('\n')
576 w('returncode %r' % proc.returncode)
577 w('\n')
578 if proc.returncode:
579 self.fatal(Utils.ex_stack())
580 ret = out
582 return ret
584 @conf
585 def check_cxx(self, *k, **kw):
586 kw['compiler'] = 'cxx'
587 return self.check(*k, **kw)
589 @conf
590 def check_cc(self, *k, **kw):
591 kw['compiler'] = 'cc'
592 return self.check(*k, **kw)
594 @conf
595 def define(self, define, value, quote=1):
596 """store a single define and its state into an internal list for later
597 writing to a config header file. Value can only be
598 a string or int; other types not supported. String
599 values will appear properly quoted in the generated
600 header file."""
601 assert define and isinstance(define, str)
603 # ordered_dict is for writing the configuration header in order
604 tbl = self.env[DEFINES] or Utils.ordered_dict()
606 # the user forgot to tell if the value is quoted or not
607 if isinstance(value, str):
608 if quote:
609 tbl[define] = '"%s"' % repr('"'+value)[2:-1].replace('"', '\\"')
610 else:
611 tbl[define] = value
612 elif isinstance(value, int):
613 tbl[define] = value
614 else:
615 raise TypeError('define %r -> %r must be a string or an int' % (define, value))
617 # add later to make reconfiguring faster
618 self.env[DEFINES] = tbl
619 self.env[define] = value # <- not certain this is necessary
621 @conf
622 def undefine(self, define):
623 """store a single define and its state into an internal list
624 for later writing to a config header file"""
625 assert define and isinstance(define, str)
627 tbl = self.env[DEFINES] or Utils.ordered_dict()
629 value = UNDEFINED
630 tbl[define] = value
632 # add later to make reconfiguring faster
633 self.env[DEFINES] = tbl
634 self.env[define] = value
636 @conf
637 def define_cond(self, name, value):
638 """Conditionally define a name.
639 Formally equivalent to: if value: define(name, 1) else: undefine(name)"""
640 if value:
641 self.define(name, 1)
642 else:
643 self.undefine(name)
645 @conf
646 def is_defined(self, key):
647 defines = self.env[DEFINES]
648 if not defines:
649 return False
650 try:
651 value = defines[key]
652 except KeyError:
653 return False
654 else:
655 return value != UNDEFINED
657 @conf
658 def get_define(self, define):
659 "get the value of a previously stored define"
660 try: return self.env[DEFINES][define]
661 except KeyError: return None
663 @conf
664 def have_define(self, name):
665 "prefix the define with 'HAVE_' and make sure it has valid characters."
666 return self.__dict__.get('HAVE_PAT', 'HAVE_%s') % Utils.quote_define_name(name)
668 @conf
669 def write_config_header(self, configfile='', env='', guard='', top=False):
670 "save the defines into a file"
671 if not configfile: configfile = WAF_CONFIG_H
672 waf_guard = guard or '_%s_WAF' % Utils.quote_define_name(configfile)
674 # configfile -> absolute path
675 # there is a good reason to concatenate first and to split afterwards
676 if not env: env = self.env
677 if top:
678 diff = ''
679 else:
680 diff = Utils.diff_path(self.srcdir, self.curdir)
681 full = os.sep.join([self.blddir, env.variant(), diff, configfile])
682 full = os.path.normpath(full)
683 (dir, base) = os.path.split(full)
685 try: os.makedirs(dir)
686 except: pass
688 dest = open(full, 'w')
689 dest.write('/* Configuration header created by Waf - do not edit */\n')
690 dest.write('#ifndef %s\n#define %s\n\n' % (waf_guard, waf_guard))
692 dest.write(self.get_config_header())
694 # config files are not removed on "waf clean"
695 env.append_unique(CFG_FILES, os.path.join(diff, configfile))
697 dest.write('\n#endif /* %s */\n' % waf_guard)
698 dest.close()
700 @conf
701 def get_config_header(self):
702 """Fill-in the contents of the config header. Override when you need to write your own config header."""
703 config_header = []
705 tbl = self.env[DEFINES] or Utils.ordered_dict()
706 for key in tbl.allkeys:
707 value = tbl[key]
708 if value is None:
709 config_header.append('#define %s' % key)
710 elif value is UNDEFINED:
711 config_header.append('/* #undef %s */' % key)
712 else:
713 config_header.append('#define %s %s' % (key, value))
714 return "\n".join(config_header)
716 @conftest
717 def find_cpp(conf):
718 v = conf.env
719 cpp = []
720 if v['CPP']: cpp = v['CPP']
721 elif 'CPP' in conf.environ: cpp = conf.environ['CPP']
722 if not cpp: cpp = conf.find_program('cpp', var='CPP')
723 #if not cpp: cpp = v['CC']
724 #if not cpp: cpp = v['CXX']
725 v['CPP'] = cpp
727 @conftest
728 def cc_add_flags(conf):
729 conf.add_os_flags('CFLAGS', 'CCFLAGS')
730 conf.add_os_flags('CPPFLAGS')
732 @conftest
733 def cxx_add_flags(conf):
734 conf.add_os_flags('CXXFLAGS')
735 conf.add_os_flags('CPPFLAGS')
737 @conftest
738 def link_add_flags(conf):
739 conf.add_os_flags('LINKFLAGS')
740 conf.add_os_flags('LDFLAGS', 'LINKFLAGS')
742 @conftest
743 def cc_load_tools(conf):
744 conf.check_tool('cc')
746 @conftest
747 def cxx_load_tools(conf):
748 conf.check_tool('cxx')