3 # Thomas Nagy, 2005-2008 (ita)
6 c/c++ configuration routines
9 import os, imp, sys, shlex, shutil
11 import Build, Utils, Configure, Task, Options, Logs, TaskGen
12 from Constants import *
13 from Configure import conf, conftest
17 'atleast-version': '>=',
18 'exact-version': '==',
32 if ((%(type_name)s *) 0) return 0;
33 if (sizeof (%(type_name)s)) return 0;
43 def parse_flags(line, uselib, env):
44 """pkg-config still has bugs on some platforms, and there are many -config programs, parsing flags is necessary :-/"""
46 lst = shlex.split(line)
51 app = env.append_value
52 if st == '-I' or st == '/I':
53 if not ot: ot = lst.pop(0)
54 app('CPPPATH_' + uselib, ot)
56 if not ot: ot = lst.pop(0)
57 app('CXXDEFINES_' + uselib, ot)
58 app('CCDEFINES_' + uselib, ot)
60 if not ot: ot = lst.pop(0)
61 app('LIB_' + uselib, ot)
63 if not ot: ot = lst.pop(0)
64 if not ccroot.is_standard_libpath(env, ot):
65 app('LIBPATH_' + uselib, ot)
66 elif x == '-pthread' or x.startswith('+'):
67 app('CCFLAGS_' + uselib, x)
68 app('CXXFLAGS_' + uselib, x)
69 app('LINKFLAGS_' + uselib, x)
70 elif x == '-framework':
71 app('FRAMEWORK_' + uselib, lst.pop(0))
72 elif x.startswith('-F'):
73 app('FRAMEWORKPATH_' + uselib, x[2:])
74 elif x.startswith('-std'):
75 app('CCFLAGS_' + uselib, x)
76 app('CXXFLAGS_' + uselib, x)
77 app('LINKFLAGS_' + uselib, x)
79 # NOTE on special treatment of -Wl,-R and -Wl,-rpath:
81 # It is important to not put a library provided RPATH
82 # into the LINKFLAGS but in the RPATH instead, since
83 # the provided LINKFLAGS get prepended to our own internal
84 # RPATH later, and hence can potentially lead to linking
85 # in too old versions of our internal libs.
87 elif x.startswith('-Wl,-R'):
88 if not ccroot.is_standard_libpath(env,x[6:]):
89 app('RPATH_' + uselib, x[6:])
90 elif x.startswith('-Wl,-rpath,'):
91 if not ccroot.is_standard_libpath(env, x[11:]):
92 app('RPATH_' + uselib, x[11:])
93 elif x.startswith('-Wl'):
94 app('LINKFLAGS_' + uselib, x)
95 elif x.startswith('-m') or x.startswith('-f'):
96 app('CCFLAGS_' + uselib, x)
97 app('CXXFLAGS_' + uselib, x)
100 def ret_msg(self, f, kw):
101 """execute a function, when provided"""
102 if isinstance(f, str):
107 def validate_cfg(self, kw):
109 kw['path'] = 'pkg-config --errors-to-stdout --print-errors'
112 if 'atleast_pkgconfig_version' in kw:
114 kw['msg'] = 'Checking for pkg-config version >= %s' % kw['atleast_pkgconfig_version']
117 # pkg-config --modversion
118 if 'modversion' in kw:
121 if 'variables' in kw:
123 kw['msg'] = 'Checking for %s variables' % kw['package']
126 # checking for the version of a module, for the moment, one thing at a time
127 for x in cfg_ver.keys():
128 y = x.replace('-', '_')
130 if not 'package' in kw:
131 raise ValueError('%s requires a package' % x)
134 kw['msg'] = 'Checking for %s %s %s' % (kw['package'], cfg_ver[x], kw[y])
138 kw['msg'] = 'Checking for %s' % (kw['package'] or kw['path'])
139 if not 'okmsg' in kw:
141 if not 'errmsg' in kw:
142 kw['errmsg'] = 'not found'
145 def cmd_and_log(self, cmd, kw):
146 Logs.debug('runner: %s\n' % cmd)
148 self.log.write('%s\n' % cmd)
151 p = Utils.pproc.Popen(cmd, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE, shell=True)
152 (out, err) = p.communicate()
154 self.log.write('error %r' % e)
157 # placeholder, don't touch
166 if not kw.get('errmsg', ''):
167 if kw.get('mandatory', False):
168 kw['errmsg'] = out.strip()
175 def exec_cfg(self, kw):
178 if 'atleast_pkgconfig_version' in kw:
179 cmd = '%s --atleast-pkgconfig-version=%s' % (kw['path'], kw['atleast_pkgconfig_version'])
180 self.cmd_and_log(cmd, kw)
181 if not 'okmsg' in kw:
185 # checking for the version of a module
187 y = x.replace('-', '_')
189 self.cmd_and_log('%s --%s=%s %s' % (kw['path'], x, kw[y], kw['package']), kw)
190 if not 'okmsg' in kw:
192 self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
195 # retrieving the version of a module
196 if 'modversion' in kw:
197 version = self.cmd_and_log('%s --modversion %s' % (kw['path'], kw['modversion']), kw).strip()
198 self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)
201 # retrieving variables of a module
202 if 'variables' in kw:
203 env = kw.get('env', self.env)
204 uselib = kw.get('uselib_store', kw['package'].upper())
205 vars = Utils.to_list(kw['variables'])
207 val = self.cmd_and_log('%s --variable=%s %s' % (kw['path'], v, kw['package']), kw).strip()
208 var = '%s_%s' % (uselib, v)
210 if not 'okmsg' in kw:
217 defi = kw.get('define_variable', None)
219 defi = self.env.PKG_CONFIG_DEFINES or {}
220 for key, val in defi.iteritems():
221 lst.append('--define-variable=%s=%s' % (key, val))
223 lst.append(kw.get('args', ''))
224 lst.append(kw['package'])
226 # so we assume the command-line will output flags to be parsed afterwards
228 ret = self.cmd_and_log(cmd, kw)
229 if not 'okmsg' in kw:
232 self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
233 parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env))
237 def check_cfg(self, *k, **kw):
239 for pkg-config mostly, but also all the -config tools
240 conf.check_cfg(path='mpicc', args='--showme:compile --showme:link', package='', uselib_store='OPEN_MPI')
241 conf.check_cfg(package='dbus-1', variables='system_bus_default_address session_bus_services_dir')
244 self.validate_cfg(kw)
246 self.check_message_1(kw['msg'])
249 ret = self.exec_cfg(kw)
250 except Configure.ConfigurationError, e:
252 self.check_message_2(kw['errmsg'], 'YELLOW')
253 if 'mandatory' in kw and kw['mandatory']:
257 self.fatal('the configuration failed (see %r)' % self.log.name)
261 self.check_message_2(self.ret_msg(kw['okmsg'], kw))
265 # the idea is the following: now that we are certain
266 # that all the code here is only for c or c++, it is
267 # easy to put all the logic in one function
269 # this should prevent code duplication (ita)
271 # env: an optional environment (modified -> provide a copy)
272 # compiler: cc or cxx - it tries to guess what is best
273 # type: cprogram, cshlib, cstaticlib
274 # code: a c code to execute
275 # uselib_store: where to add the variables
276 # uselib: parameters to use for building
277 # define: define to set, like FOO in #define FOO, if not set, add /* #undef FOO */
278 # execute: True or False - will return the result of the execution
281 def validate_c(self, kw):
282 """validate the parameters for the test method"""
285 kw['env'] = self.env.copy()
288 if not 'compiler' in kw:
289 kw['compiler'] = 'cc'
290 if env['CXX_NAME'] and Task.TaskBase.classes.get('cxx', None):
291 kw['compiler'] = 'cxx'
292 if not self.env['CXX']:
293 self.fatal('a c++ compiler is required')
295 if not self.env['CC']:
296 self.fatal('a c compiler is required')
299 kw['type'] = 'cprogram'
301 assert not(kw['type'] != 'cprogram' and kw.get('execute', 0)), 'can only execute programs'
304 #if kw['type'] != 'program' and kw.get('execute', 0):
305 # raise ValueError, 'can only execute programs'
308 if 'header_name' in dct:
309 dct = Utils.to_list(dct['header_name'])
310 return ''.join(['#include <%s>\n' % x for x in dct])
314 if not 'compile_mode' in kw:
315 kw['compile_mode'] = (kw['compiler'] == 'cxx') and 'cxx' or 'cc'
317 if not 'compile_filename' in kw:
318 kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
321 if 'framework_name' in kw:
322 try: TaskGen.task_gen.create_task_macapp
323 except AttributeError: self.fatal('frameworks require the osx tool')
325 fwkname = kw['framework_name']
326 if not 'uselib_store' in kw:
327 kw['uselib_store'] = fwkname.upper()
329 if not kw.get('no_header', False):
330 if not 'header_name' in kw:
331 kw['header_name'] = []
332 fwk = '%s/%s.h' % (fwkname, fwkname)
333 if kw.get('remove_dot_h', None):
335 kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]
337 kw['msg'] = 'Checking for framework %s' % fwkname
338 kw['framework'] = fwkname
339 #kw['frameworkpath'] = set it yourself
341 if 'function_name' in kw:
342 fu = kw['function_name']
344 kw['msg'] = 'Checking for function %s' % fu
345 kw['code'] = to_header(kw) + SNIP1 % fu
346 if not 'uselib_store' in kw:
347 kw['uselib_store'] = fu.upper()
348 if not 'define_name' in kw:
349 kw['define_name'] = self.have_define(fu)
351 elif 'type_name' in kw:
354 kw['msg'] = 'Checking for type %s' % tu
355 if not 'header_name' in kw:
356 kw['header_name'] = 'stdint.h'
357 kw['code'] = to_header(kw) + SNIP2 % {'type_name' : tu}
358 if not 'define_name' in kw:
359 kw['define_name'] = self.have_define(tu.upper())
361 elif 'header_name' in kw:
363 kw['msg'] = 'Checking for header %s' % kw['header_name']
365 l = Utils.to_list(kw['header_name'])
366 assert len(l)>0, 'list of headers in header_name is empty'
368 kw['code'] = to_header(kw) + SNIP3
370 if not 'uselib_store' in kw:
371 kw['uselib_store'] = l[0].upper()
373 if not 'define_name' in kw:
374 kw['define_name'] = self.have_define(l[0])
378 kw['msg'] = 'Checking for library %s' % kw['lib']
379 if not 'uselib_store' in kw:
380 kw['uselib_store'] = kw['lib'].upper()
382 if 'staticlib' in kw:
384 kw['msg'] = 'Checking for static library %s' % kw['staticlib']
385 if not 'uselib_store' in kw:
386 kw['uselib_store'] = kw['staticlib'].upper()
389 # an additional code fragment may be provided to replace the predefined code
391 kw['code'] = kw['fragment']
393 kw['msg'] = 'Checking for custom code'
394 if not 'errmsg' in kw:
397 for (flagsname,flagstype) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:
400 kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])
401 if not 'errmsg' in kw:
404 if not 'execute' in kw:
405 kw['execute'] = False
407 if not 'errmsg' in kw:
408 kw['errmsg'] = 'not found'
410 if not 'okmsg' in kw:
416 if not kw.get('success'): kw['success'] = None
418 assert 'msg' in kw, 'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c'
421 def post_check(self, *k, **kw):
422 "set the variables after a test was run successfully"
426 if kw['success'] is not None:
429 is_success = (kw['success'] == 0)
431 if 'define_name' in kw:
432 if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
435 if isinstance(key, str):
437 self.define(kw['define_name'], key, quote=kw.get('quote', 1))
439 self.define_cond(kw['define_name'], True)
441 self.define_cond(kw['define_name'], False)
443 self.define_cond(kw['define_name'], is_success)
445 if is_success and 'uselib_store' in kw:
447 for k in set(cc.g_cc_flag_vars).union(cxx.g_cxx_flag_vars):
449 # inconsistency: includes -> CPPPATH
450 if k == 'CPPPATH': lk = 'includes'
451 if k == 'CXXDEFINES': lk = 'defines'
452 if k == 'CCDEFINES': lk = 'defines'
455 # remove trailing slash
456 if isinstance(val, str):
457 val = val.rstrip(os.path.sep)
458 self.env.append_unique(k + '_' + kw['uselib_store'], val)
461 def check(self, *k, **kw):
462 # so this will be the generic function
463 # it will be safer to use check_cxx or check_cc
465 self.check_message_1(kw['msg'])
468 ret = self.run_c_code(*k, **kw)
469 except Configure.ConfigurationError, e:
470 self.check_message_2(kw['errmsg'], 'YELLOW')
471 if 'mandatory' in kw and kw['mandatory']:
475 self.fatal('the configuration failed (see %r)' % self.log.name)
478 self.check_message_2(self.ret_msg(kw['okmsg'], kw))
480 self.post_check(*k, **kw)
481 if not kw.get('execute', False):
486 def run_c_code(self, *k, **kw):
487 test_f_name = kw['compile_filename']
491 # make certain to use a fresh folder - necessary for win32
492 dir = os.path.join(self.blddir, '.conf_check_%d' % k)
494 # if the folder already exists, remove it
510 self.fatal('cannot create a configuration test folder %r' % dir)
515 self.fatal('cannot use the configuration test folder %r' % dir)
517 bdir = os.path.join(dir, 'testbuild')
519 if not os.path.exists(bdir):
524 dest = open(os.path.join(dir, test_f_name), 'w')
525 dest.write(kw['code'])
528 back = os.path.abspath('.')
530 bld = Build.BuildContext()
532 bld.all_envs.update(self.all_envs)
533 bld.all_envs['default'] = env
534 bld.lst_variants = bld.all_envs.keys()
535 bld.load_dirs(dir, bdir)
539 bld.rescan(bld.srcnode)
541 if not 'features' in kw:
542 # conf.check(features='cc cprogram pyext', ...)
543 kw['features'] = [kw['compile_mode'], kw['type']] # "cprogram cc"
545 o = bld(features=kw['features'], source=test_f_name, target='testprog')
547 for k, v in kw.iteritems():
550 self.log.write("==>\n%s\n<==\n" % kw['code'])
552 # compile the program
555 except Utils.WafError:
556 ret = Utils.ex_stack()
560 # chdir before returning
564 self.log.write('command returned %r' % ret)
567 # if we need to run the program, try to get its result
568 # keep the name of the program to execute
570 lastprog = o.link_task.outputs[0].abspath(env)
572 args = Utils.to_list(kw.get('exec_args', []))
573 proc = Utils.pproc.Popen([lastprog] + args, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE)
574 (out, err) = proc.communicate()
580 w('returncode %r' % proc.returncode)
583 self.fatal(Utils.ex_stack())
589 def check_cxx(self, *k, **kw):
590 kw['compiler'] = 'cxx'
591 return self.check(*k, **kw)
594 def check_cc(self, *k, **kw):
595 kw['compiler'] = 'cc'
596 return self.check(*k, **kw)
599 def define(self, define, value, quote=1):
600 """store a single define and its state into an internal list for later
601 writing to a config header file. Value can only be
602 a string or int; other types not supported. String
603 values will appear properly quoted in the generated
605 assert define and isinstance(define, str)
607 # ordered_dict is for writing the configuration header in order
608 tbl = self.env[DEFINES] or Utils.ordered_dict()
610 # the user forgot to tell if the value is quoted or not
611 if isinstance(value, str):
613 tbl[define] = '"%s"' % repr('"'+value)[2:-1].replace('"', '\\"')
616 elif isinstance(value, int):
619 raise TypeError('define %r -> %r must be a string or an int' % (define, value))
621 # add later to make reconfiguring faster
622 self.env[DEFINES] = tbl
623 self.env[define] = value # <- not certain this is necessary
626 def undefine(self, define):
627 """store a single define and its state into an internal list
628 for later writing to a config header file"""
629 assert define and isinstance(define, str)
631 tbl = self.env[DEFINES] or Utils.ordered_dict()
636 # add later to make reconfiguring faster
637 self.env[DEFINES] = tbl
638 self.env[define] = value
641 def define_cond(self, name, value):
642 """Conditionally define a name.
643 Formally equivalent to: if value: define(name, 1) else: undefine(name)"""
650 def is_defined(self, key):
651 defines = self.env[DEFINES]
659 return value != UNDEFINED
662 def get_define(self, define):
663 "get the value of a previously stored define"
664 try: return self.env[DEFINES][define]
665 except KeyError: return None
668 def have_define(self, name):
669 "prefix the define with 'HAVE_' and make sure it has valid characters."
670 return self.__dict__.get('HAVE_PAT', 'HAVE_%s') % Utils.quote_define_name(name)
673 def write_config_header(self, configfile='', env='', guard='', top=False):
674 "save the defines into a file"
675 if not configfile: configfile = WAF_CONFIG_H
676 waf_guard = guard or '_%s_WAF' % Utils.quote_define_name(configfile)
678 # configfile -> absolute path
679 # there is a good reason to concatenate first and to split afterwards
680 if not env: env = self.env
684 diff = Utils.diff_path(self.srcdir, self.curdir)
685 full = os.sep.join([self.blddir, env.variant(), diff, configfile])
686 full = os.path.normpath(full)
687 (dir, base) = os.path.split(full)
689 try: os.makedirs(dir)
692 dest = open(full, 'w')
693 dest.write('/* Configuration header created by Waf - do not edit */\n')
694 dest.write('#ifndef %s\n#define %s\n\n' % (waf_guard, waf_guard))
696 dest.write(self.get_config_header())
698 # config files are not removed on "waf clean"
699 env.append_unique(CFG_FILES, os.path.join(diff, configfile))
701 dest.write('\n#endif /* %s */\n' % waf_guard)
705 def get_config_header(self):
706 """Fill-in the contents of the config header. Override when you need to write your own config header."""
709 tbl = self.env[DEFINES] or Utils.ordered_dict()
710 for key in tbl.allkeys:
713 config_header.append('#define %s' % key)
714 elif value is UNDEFINED:
715 config_header.append('/* #undef %s */' % key)
717 config_header.append('#define %s %s' % (key, value))
718 return "\n".join(config_header)
724 if v['CPP']: cpp = v['CPP']
725 elif 'CPP' in conf.environ: cpp = conf.environ['CPP']
726 if not cpp: cpp = conf.find_program('cpp', var='CPP')
727 #if not cpp: cpp = v['CC']
728 #if not cpp: cpp = v['CXX']
732 def cc_add_flags(conf):
733 conf.add_os_flags('CFLAGS', 'CCFLAGS')
734 conf.add_os_flags('CPPFLAGS')
737 def cxx_add_flags(conf):
738 conf.add_os_flags('CXXFLAGS')
739 conf.add_os_flags('CPPFLAGS')
742 def link_add_flags(conf):
743 conf.add_os_flags('LINKFLAGS')
744 conf.add_os_flags('LDFLAGS', 'LINKFLAGS')
747 def cc_load_tools(conf):
748 conf.check_tool('cc')
751 def cxx_load_tools(conf):
752 conf.check_tool('cxx')