diff options
Diffstat (limited to 'buildtools/wafadmin/3rdparty/boost.py')
-rw-r--r-- | buildtools/wafadmin/3rdparty/boost.py | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/buildtools/wafadmin/3rdparty/boost.py b/buildtools/wafadmin/3rdparty/boost.py new file mode 100644 index 0000000000..e690a4e274 --- /dev/null +++ b/buildtools/wafadmin/3rdparty/boost.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# partially based on boost.py written by Gernot Vormayr +# written by Ruediger Sonderfeld <ruediger@c-plusplus.de>, 2008 +# modified by Bjoern Michaelsen, 2008 +# modified by Luca Fossati, 2008 +# rewritten for waf 1.5.1, Thomas Nagy, 2008 +# +#def set_options(opt): +# opt.tool_options('boost') +# # ... +# +#def configure(conf): +# # ... (e.g. conf.check_tool('g++')) +# conf.check_tool('boost') +# conf.check_boost(lib='signals filesystem', static='onlystatic', score_version=(-1000, 1000), tag_minscore=1000) +# +#def build(bld): +# bld(source='main.c', target='bar', uselib="BOOST BOOST_SYSTEM") +# +#ISSUES: +# * find_includes should be called only once! +# * support mandatory + +######## boost update ########### +## ITA: * the method get_boost_version_number does work +## * the rest of the code has not really been tried +# * make certain a demo is provided (in demos/adv for example) + +# TODO: bad and underdocumented code -> boost.py will be removed in waf 1.6 to be rewritten later + +import os.path, glob, types, re, sys +import Configure, config_c, Options, Utils, Logs +from Logs import warn, debug +from Configure import conf + +boost_code = ''' +#include <iostream> +#include <boost/version.hpp> +int main() { std::cout << BOOST_VERSION << std::endl; } +''' + +boost_libpath = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] +boost_cpppath = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] + +STATIC_NOSTATIC = 'nostatic' +STATIC_BOTH = 'both' +STATIC_ONLYSTATIC = 'onlystatic' + +is_versiontag = re.compile('^\d+_\d+_?\d*$') +is_threadingtag = re.compile('^mt$') +is_abitag = re.compile('^[sgydpn]+$') +is_toolsettag = re.compile('^(acc|borland|como|cw|dmc|darwin|gcc|hp_cxx|intel|kylix|vc|mgw|qcc|sun|vacpp)\d*$') +is_pythontag=re.compile('^py[0-9]{2}$') + +def set_options(opt): + opt.add_option('--boost-includes', type='string', default='', dest='boostincludes', help='path to the boost directory where the includes are e.g. /usr/local/include/boost-1_35') + opt.add_option('--boost-libs', type='string', default='', dest='boostlibs', help='path to the directory where the boost libs are e.g. /usr/local/lib') + +def string_to_version(s): + version = s.split('.') + if len(version) < 3: return 0 + return int(version[0])*100000 + int(version[1])*100 + int(version[2]) + +def version_string(version): + major = version / 100000 + minor = version / 100 % 1000 + minor_minor = version % 100 + if minor_minor == 0: + return "%d_%d" % (major, minor) + else: + return "%d_%d_%d" % (major, minor, minor_minor) + +def libfiles(lib, pattern, lib_paths): + result = [] + for lib_path in lib_paths: + libname = pattern % ('boost_%s[!_]*' % lib) + result += glob.glob(os.path.join(lib_path, libname)) + return result + +@conf +def get_boost_version_number(self, dir): + """silently retrieve the boost version number""" + try: + return self.run_c_code(compiler='cxx', code=boost_code, includes=dir, execute=1, env=self.env.copy(), type='cprogram', compile_mode='cxx', compile_filename='test.cpp') + except Configure.ConfigurationError, e: + return -1 + +def set_default(kw, var, val): + if not var in kw: + kw[var] = val + +def tags_score(tags, kw): + """ + checks library tags + + see http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html 6.1 + """ + score = 0 + needed_tags = { + 'threading': kw['tag_threading'], + 'abi': kw['tag_abi'], + 'toolset': kw['tag_toolset'], + 'version': kw['tag_version'], + 'python': kw['tag_python'] + } + + if kw['tag_toolset'] is None: + v = kw['env'] + toolset = v['CXX_NAME'] + if v['CXX_VERSION']: + version_no = v['CXX_VERSION'].split('.') + toolset += version_no[0] + if len(version_no) > 1: + toolset += version_no[1] + needed_tags['toolset'] = toolset + + found_tags = {} + for tag in tags: + if is_versiontag.match(tag): found_tags['version'] = tag + if is_threadingtag.match(tag): found_tags['threading'] = tag + if is_abitag.match(tag): found_tags['abi'] = tag + if is_toolsettag.match(tag): found_tags['toolset'] = tag + if is_pythontag.match(tag): found_tags['python'] = tag + + for tagname in needed_tags.iterkeys(): + if needed_tags[tagname] is not None and tagname in found_tags: + if re.compile(needed_tags[tagname]).match(found_tags[tagname]): + score += kw['score_' + tagname][0] + else: + score += kw['score_' + tagname][1] + return score + +@conf +def validate_boost(self, kw): + ver = kw.get('version', '') + + for x in 'min_version max_version version'.split(): + set_default(kw, x, ver) + + set_default(kw, 'lib', '') + kw['lib'] = Utils.to_list(kw['lib']) + + set_default(kw, 'env', self.env) + + set_default(kw, 'libpath', boost_libpath) + set_default(kw, 'cpppath', boost_cpppath) + + for x in 'tag_threading tag_version tag_toolset'.split(): + set_default(kw, x, None) + set_default(kw, 'tag_abi', '^[^d]*$') + + set_default(kw, 'python', str(sys.version_info[0]) + str(sys.version_info[1]) ) + set_default(kw, 'tag_python', '^py' + kw['python'] + '$') + + set_default(kw, 'score_threading', (10, -10)) + set_default(kw, 'score_abi', (10, -10)) + set_default(kw, 'score_python', (10,-10)) + set_default(kw, 'score_toolset', (1, -1)) + set_default(kw, 'score_version', (100, -100)) + + set_default(kw, 'score_min', 0) + set_default(kw, 'static', STATIC_NOSTATIC) + set_default(kw, 'found_includes', False) + set_default(kw, 'min_score', 0) + + set_default(kw, 'errmsg', 'not found') + set_default(kw, 'okmsg', 'ok') + +@conf +def find_boost_includes(self, kw): + """ + check every path in kw['cpppath'] for subdir + that either starts with boost- or is named boost. + + Then the version is checked and selected accordingly to + min_version/max_version. The highest possible version number is + selected! + + If no versiontag is set the versiontag is set accordingly to the + selected library and CPPPATH_BOOST is set. + """ + boostPath = getattr(Options.options, 'boostincludes', '') + if boostPath: + boostPath = [os.path.normpath(os.path.expandvars(os.path.expanduser(boostPath)))] + else: + boostPath = Utils.to_list(kw['cpppath']) + + min_version = string_to_version(kw.get('min_version', '')) + max_version = string_to_version(kw.get('max_version', '')) or (sys.maxint - 1) + + version = 0 + for include_path in boostPath: + boost_paths = [p for p in glob.glob(os.path.join(include_path, 'boost*')) if os.path.isdir(p)] + debug('BOOST Paths: %r' % boost_paths) + for path in boost_paths: + pathname = os.path.split(path)[-1] + ret = -1 + if pathname == 'boost': + path = include_path + ret = self.get_boost_version_number(path) + elif pathname.startswith('boost-'): + ret = self.get_boost_version_number(path) + ret = int(ret) + + if ret != -1 and ret >= min_version and ret <= max_version and ret > version: + boost_path = path + version = ret + if not version: + self.fatal('boost headers not found! (required version min: %s max: %s)' + % (kw['min_version'], kw['max_version'])) + return False + + found_version = version_string(version) + versiontag = '^' + found_version + '$' + if kw['tag_version'] is None: + kw['tag_version'] = versiontag + elif kw['tag_version'] != versiontag: + warn('boost header version %r and tag_version %r do not match!' % (versiontag, kw['tag_version'])) + env = self.env + env['CPPPATH_BOOST'] = boost_path + env['BOOST_VERSION'] = found_version + self.found_includes = 1 + ret = 'Version %s (%s)' % (found_version, boost_path) + return ret + +@conf +def find_boost_library(self, lib, kw): + + def find_library_from_list(lib, files): + lib_pattern = re.compile('.*boost_(.*?)\..*') + result = (None, None) + resultscore = kw['min_score'] - 1 + for file in files: + m = lib_pattern.search(file, 1) + if m: + libname = m.group(1) + libtags = libname.split('-')[1:] + currentscore = tags_score(libtags, kw) + if currentscore > resultscore: + result = (libname, file) + resultscore = currentscore + return result + + lib_paths = getattr(Options.options, 'boostlibs', '') + if lib_paths: + lib_paths = [os.path.normpath(os.path.expandvars(os.path.expanduser(lib_paths)))] + else: + lib_paths = Utils.to_list(kw['libpath']) + + v = kw.get('env', self.env) + + (libname, file) = (None, None) + if kw['static'] in [STATIC_NOSTATIC, STATIC_BOTH]: + st_env_prefix = 'LIB' + files = libfiles(lib, v['shlib_PATTERN'], lib_paths) + (libname, file) = find_library_from_list(lib, files) + if libname is None and kw['static'] in [STATIC_ONLYSTATIC, STATIC_BOTH]: + st_env_prefix = 'STATICLIB' + staticLibPattern = v['staticlib_PATTERN'] + if self.env['CC_NAME'] == 'msvc': + staticLibPattern = 'lib' + staticLibPattern + files = libfiles(lib, staticLibPattern, lib_paths) + (libname, file) = find_library_from_list(lib, files) + if libname is not None: + v['LIBPATH_BOOST_' + lib.upper()] = [os.path.split(file)[0]] + if self.env['CC_NAME'] == 'msvc' and os.path.splitext(file)[1] == '.lib': + v[st_env_prefix + '_BOOST_' + lib.upper()] = ['libboost_'+libname] + else: + v[st_env_prefix + '_BOOST_' + lib.upper()] = ['boost_'+libname] + return + self.fatal('lib boost_' + lib + ' not found!') + +@conf +def check_boost(self, *k, **kw): + """ + This should be the main entry point + +- min_version +- max_version +- version +- include_path +- lib_path +- lib +- toolsettag - None or a regexp +- threadingtag - None or a regexp +- abitag - None or a regexp +- versiontag - WARNING: you should rather use version or min_version/max_version +- static - look for static libs (values: + 'nostatic' or STATIC_NOSTATIC - ignore static libs (default) + 'both' or STATIC_BOTH - find static libs, too + 'onlystatic' or STATIC_ONLYSTATIC - find only static libs +- score_version +- score_abi +- scores_threading +- score_toolset + * the scores are tuples (match_score, nomatch_score) + match_score is the added to the score if the tag is matched + nomatch_score is added when a tag is found and does not match +- min_score + """ + + if not self.env['CXX']: + self.fatal('load a c++ compiler tool first, for example conf.check_tool("g++")') + self.validate_boost(kw) + ret = None + try: + if not kw.get('found_includes', None): + self.check_message_1(kw.get('msg_includes', 'boost headers')) + ret = self.find_boost_includes(kw) + + except Configure.ConfigurationError, e: + if 'errmsg' in kw: + self.check_message_2(kw['errmsg'], 'YELLOW') + if 'mandatory' in kw: + if Logs.verbose > 1: + raise + else: + self.fatal('the configuration failed (see %r)' % self.log.name) + else: + if 'okmsg' in kw: + self.check_message_2(kw.get('okmsg_includes', ret)) + + for lib in kw['lib']: + self.check_message_1('library boost_'+lib) + try: + self.find_boost_library(lib, kw) + except Configure.ConfigurationError, e: + ret = False + if 'errmsg' in kw: + self.check_message_2(kw['errmsg'], 'YELLOW') + if 'mandatory' in kw: + if Logs.verbose > 1: + raise + else: + self.fatal('the configuration failed (see %r)' % self.log.name) + else: + if 'okmsg' in kw: + self.check_message_2(kw['okmsg']) + + return ret + |