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
16 'atleast-version': '>=',
17 'exact-version': '==',
31 if ((%(type_name)s *) 0) return 0;
32 if (sizeof (%(type_name)s)) return 0;
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
)
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
)
55 if not ot
: ot
= lst
.pop(0)
56 app('CXXDEFINES_' + uselib
, ot
)
57 app('CCDEFINES_' + uselib
, ot
)
59 if not ot
: ot
= lst
.pop(0)
60 app('LIB_' + uselib
, ot
)
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
)
96 def ret_msg(self
, f
, kw
):
97 """execute a function, when provided"""
98 if isinstance(f
, str):
103 def validate_cfg(self
, kw
):
105 kw
['path'] = 'pkg-config --errors-to-stdout --print-errors'
108 if 'atleast_pkgconfig_version' in kw
:
110 kw
['msg'] = 'Checking for pkg-config version >= %s' % kw
['atleast_pkgconfig_version']
113 # pkg-config --modversion
114 if 'modversion' in kw
:
117 if 'variables' in kw
:
119 kw
['msg'] = 'Checking for %s variables' % kw
['package']
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('-', '_')
126 if not 'package' in kw
:
127 raise ValueError('%s requires a package' % x
)
130 kw
['msg'] = 'Checking for %s %s %s' % (kw
['package'], cfg_ver
[x
], kw
[y
])
134 kw
['msg'] = 'Checking for %s' % (kw
['package'] or kw
['path'])
135 if not 'okmsg' in kw
:
137 if not 'errmsg' in kw
:
138 kw
['errmsg'] = 'not found'
141 def cmd_and_log(self
, cmd
, kw
):
142 Logs
.debug('runner: %s\n' % cmd
)
144 self
.log
.write('%s\n' % cmd
)
147 p
= Utils
.pproc
.Popen(cmd
, stdout
=Utils
.pproc
.PIPE
, stderr
=Utils
.pproc
.PIPE
, shell
=True)
148 (out
, err
) = p
.communicate()
150 self
.log
.write('error %r' % e
)
153 # placeholder, don't touch
162 if not kw
.get('errmsg', ''):
163 if kw
.get('mandatory', False):
164 kw
['errmsg'] = out
.strip()
171 def exec_cfg(self
, kw
):
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
:
181 # checking for the version of a module
183 y
= x
.replace('-', '_')
185 self
.cmd_and_log('%s --%s=%s %s' % (kw
['path'], x
, kw
[y
], kw
['package']), kw
)
186 if not 'okmsg' in kw
:
188 self
.define(self
.have_define(kw
.get('uselib_store', kw
['package'])), 1, 0)
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
)
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'])
203 val
= self
.cmd_and_log('%s --variable=%s %s' % (kw
['path'], v
, kw
['package']), kw
).strip()
204 var
= '%s_%s' % (uselib
, v
)
206 if not 'okmsg' in kw
:
213 defi
= kw
.get('define_variable', None)
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
224 ret
= self
.cmd_and_log(cmd
, kw
)
225 if not 'okmsg' in kw
:
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
))
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
)
242 self
.check_message_1(kw
['msg'])
245 ret
= self
.exec_cfg(kw
)
246 except Configure
.ConfigurationError
, e
:
248 self
.check_message_2(kw
['errmsg'], 'YELLOW')
249 if 'mandatory' in kw
and kw
['mandatory']:
253 self
.fatal('the configuration failed (see %r)' % self
.log
.name
)
257 self
.check_message_2(self
.ret_msg(kw
['okmsg'], kw
))
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
277 def validate_c(self
, kw
):
278 """validate the parameters for the test method"""
281 kw
['env'] = self
.env
.copy()
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')
291 if not self
.env
['CC']:
292 self
.fatal('a c compiler is required')
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'
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
])
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 '')
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):
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']
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
:
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
:
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])
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
:
380 kw
['msg'] = 'Checking for static library %s' % kw
['staticlib']
381 if not 'uselib_store' in kw
:
382 kw
['uselib_store'] = kw
['staticlib'].upper()
385 # an additional code fragment may be provided to replace the predefined code
387 kw
['code'] = kw
['fragment']
389 kw
['msg'] = 'Checking for custom code'
390 if not 'errmsg' in kw
:
393 for (flagsname
,flagstype
) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:
396 kw
['msg'] = 'Checking for %s flags %s' % (flagstype
, kw
[flagsname
])
397 if not 'errmsg' in kw
:
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
:
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'
417 def post_check(self
, *k
, **kw
):
418 "set the variables after a test was run successfully"
422 if kw
['success'] is not None:
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
:
431 if isinstance(key
, str):
433 self
.define(kw
['define_name'], key
, quote
=kw
.get('quote', 1))
435 self
.define_cond(kw
['define_name'], True)
437 self
.define_cond(kw
['define_name'], False)
439 self
.define_cond(kw
['define_name'], is_success
)
441 if is_success
and 'uselib_store' in kw
:
443 for k
in set(cc
.g_cc_flag_vars
).union(cxx
.g_cxx_flag_vars
):
445 # inconsistency: includes -> CPPPATH
446 if k
== 'CPPPATH': lk
= 'includes'
447 if k
== 'CXXDEFINES': lk
= 'defines'
448 if k
== 'CCDEFINES': lk
= 'defines'
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
)
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
461 self
.check_message_1(kw
['msg'])
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']:
471 self
.fatal('the configuration failed (see %r)' % self
.log
.name
)
474 self
.check_message_2(self
.ret_msg(kw
['okmsg'], kw
))
476 self
.post_check(*k
, **kw
)
477 if not kw
.get('execute', False):
482 def run_c_code(self
, *k
, **kw
):
483 test_f_name
= kw
['compile_filename']
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
506 self
.fatal('cannot create a configuration test folder %r' % dir)
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
):
520 dest
= open(os
.path
.join(dir, test_f_name
), 'w')
521 dest
.write(kw
['code'])
524 back
= os
.path
.abspath('.')
526 bld
= Build
.BuildContext()
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
)
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():
546 self
.log
.write("==>\n%s\n<==\n" % kw
['code'])
548 # compile the program
551 except Utils
.WafError
:
552 ret
= Utils
.ex_stack()
556 # chdir before returning
560 self
.log
.write('command returned %r' % ret
)
563 # if we need to run the program, try to get its result
564 # keep the name of the program to 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()
576 w('returncode %r' % proc
.returncode
)
579 self
.fatal(Utils
.ex_stack())
585 def check_cxx(self
, *k
, **kw
):
586 kw
['compiler'] = 'cxx'
587 return self
.check(*k
, **kw
)
590 def check_cc(self
, *k
, **kw
):
591 kw
['compiler'] = 'cc'
592 return self
.check(*k
, **kw
)
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
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):
609 tbl
[define
] = '"%s"' % repr('"'+value
)[2:-1].replace('"', '\\"')
612 elif isinstance(value
, int):
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
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()
632 # add later to make reconfiguring faster
633 self
.env
[DEFINES
] = tbl
634 self
.env
[define
] = value
637 def define_cond(self
, name
, value
):
638 """Conditionally define a name.
639 Formally equivalent to: if value: define(name, 1) else: undefine(name)"""
646 def is_defined(self
, key
):
647 defines
= self
.env
[DEFINES
]
655 return value
!= UNDEFINED
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
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
)
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
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)
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
)
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."""
705 tbl
= self
.env
[DEFINES
] or Utils
.ordered_dict()
706 for key
in tbl
.allkeys
:
709 config_header
.append('#define %s' % key
)
710 elif value
is UNDEFINED
:
711 config_header
.append('/* #undef %s */' % key
)
713 config_header
.append('#define %s %s' % (key
, value
))
714 return "\n".join(config_header
)
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']
728 def cc_add_flags(conf
):
729 conf
.add_os_flags('CFLAGS', 'CCFLAGS')
730 conf
.add_os_flags('CPPFLAGS')
733 def cxx_add_flags(conf
):
734 conf
.add_os_flags('CXXFLAGS')
735 conf
.add_os_flags('CPPFLAGS')
738 def link_add_flags(conf
):
739 conf
.add_os_flags('LINKFLAGS')
740 conf
.add_os_flags('LDFLAGS', 'LINKFLAGS')
743 def cc_load_tools(conf
):
744 conf
.check_tool('cc')
747 def cxx_load_tools(conf
):
748 conf
.check_tool('cxx')