diff --git a/bindings/python/wscript b/bindings/python/wscript index 2a001b1cb..1087a4daa 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -192,13 +192,11 @@ int main () ''' % dict(type1=t1, type2=t2) try: - ret = conf.run_c_code(code=test_program, - env=conf.env.derive(), compile_filename='test.cc', - features='cxx cprogram', execute=False) + ret = conf.check(compiler='cxx', fragment=test_program, features='cxx') except Errors.ConfigurationError: - ret = 1 + ret = False conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes')) - return not ret + return ret uint64_is_long = test("uint64_t", "unsigned long") uint64_is_long_long = test("uint64_t", "unsigned long long") diff --git a/waf-tools/boost.py b/waf-tools/boost.py index 08162bb5b..d3c486906 100644 --- a/waf-tools/boost.py +++ b/waf-tools/boost.py @@ -30,18 +30,18 @@ When using this tool, the wscript will look like: Options are generated, in order to specify the location of boost includes/libraries. The `check_boost` configuration function allows to specify the used boost libraries. -It can also provide default arguments to the --boost-static and --boost-mt command-line arguments. +It can also provide default arguments to the --boost-mt command-line arguments. Everything will be packaged together in a BOOST component that you can use. When using MSVC, a lot of compilation flags need to match your BOOST build configuration: - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined. Errors: C4530 - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC - So before calling `conf.check_boost` you might want to disabling by adding: - conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB'] - Errors: + So before calling `conf.check_boost` you might want to disabling by adding + conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB'] + Errors: - boost might also be compiled with /MT, which links the runtime statically. - If you have problems with redefined symbols, + If you have problems with redefined symbols, self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc'] Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases. @@ -52,9 +52,10 @@ import sys import re from waflib import Utils, Logs, Errors from waflib.Configure import conf +from waflib.TaskGen import feature, after_method BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', - '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] + '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] BOOST_VERSION_FILE = 'boost/version.hpp' BOOST_VERSION_CODE = ''' @@ -111,14 +112,11 @@ def options(opt): default='', dest='boost_libs', help='''path to the directory where the boost libs are e.g. /path/to/boost_1_47_0/stage/lib''') - opt.add_option('--boost-static', action='store_true', - default=False, dest='boost_static', - help='link with static boost libraries (.lib/.a)') opt.add_option('--boost-mt', action='store_true', default=False, dest='boost_mt', help='select multi-threaded libraries') opt.add_option('--boost-abi', type='string', default='', dest='boost_abi', - help='''select libraries with tags (dgsyp, d for debug), + help='''select libraries with tags (gd for debug, static is automatically added), see doc Boost, Getting Started, chapter 6.1''') opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect', help="auto-detect boost linkage options (don't get used to it / might break other stuff)") @@ -135,6 +133,8 @@ def options(opt): @conf def __boost_get_version_file(self, d): + if not d: + return None dnode = self.root.find_dir(d) if dnode: return dnode.find_node(BOOST_VERSION_FILE) @@ -147,7 +147,7 @@ def boost_get_version(self, d): if node: try: txt = node.read() - except (OSError, IOError): + except EnvironmentError: Logs.error("Could not read the file %r" % node.abspath()) else: re_but = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"', re.M) @@ -161,7 +161,7 @@ def boost_get_includes(self, *k, **kw): includes = k and k[0] or kw.get('includes', None) if includes and self.__boost_get_version_file(includes): return includes - for d in Utils.to_list(self.environ.get('INCLUDE', '')) + BOOST_INCLUDES: + for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES: if self.__boost_get_version_file(d): return d if includes: @@ -196,7 +196,9 @@ def __boost_get_libs_path(self, *k, **kw): path = self.root.find_dir(libs) files = path.ant_glob('*boost_*') if not libs or not files: - for d in Utils.to_list(self.environ.get('LIB', [])) + BOOST_LIBS: + for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS: + if not d: + continue path = self.root.find_dir(d) if path: files = path.ant_glob('*boost_*') @@ -227,15 +229,10 @@ def boost_get_libs(self, *k, **kw): according to the parameters ''' path, files = self.__boost_get_libs_path(**kw) - t = [] - if kw.get('mt', False): - t.append('mt') - if kw.get('abi', None): - t.append(kw['abi']) - tags = t and '(-%s)+' % '-'.join(t) or '' + files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True) toolset = self.boost_get_toolset(kw.get('toolset', '')) - toolset_pat = '(-%s[0-9]{0,3})+' % toolset - version = '(-%s)+' % self.env.BOOST_VERSION + toolset_pat = '(-%s[0-9]{0,3})' % toolset + version = '-%s' % self.env.BOOST_VERSION def find_lib(re_lib, files): for file in files: @@ -249,27 +246,49 @@ def boost_get_libs(self, *k, **kw): name = name[3:] return name[:name.rfind('.')] - libs = [] - for lib in Utils.to_list(k and k[0] or kw.get('lib', None)): - py = (lib == 'python') and '(-py%s)+' % kw['python'] or '' - # Trying libraries, from most strict match to least one - for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version), - 'boost_%s%s%s%s' % (lib, tags, py, version), - 'boost_%s%s%s' % (lib, tags, version), - # Give up trying to find the right version - 'boost_%s%s%s%s' % (lib, toolset_pat, tags, py), - 'boost_%s%s%s' % (lib, tags, py), - 'boost_%s%s' % (lib, tags)]: - self.to_log('Trying pattern %s' % pattern) - file = find_lib(re.compile(pattern), files) - if file: - libs.append(format_lib_name(file.name)) - break - else: - self.end_msg('lib %s not found in %s' % (lib, path.abspath())) - self.fatal('The configuration failed') + def match_libs(lib_names, is_static): + libs = [] + lib_names = Utils.to_list(lib_names) + if not lib_names: + return libs + t = [] + if kw.get('mt', False): + t.append('-mt') + if kw.get('abi', None): + t.append('%s%s' % (is_static and '-s' or '-', kw['abi'])) + elif is_static: + t.append('-s') + tags_pat = t and ''.join(t) or '' + ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN + ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN - return path.abspath(), libs + for lib in lib_names: + if lib == 'python': + # for instance, with python='27', + # accepts '-py27', '-py2', '27' and '2' + # but will reject '-py3', '-py26', '26' and '3' + tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python']) + else: + tags = tags_pat + # Trying libraries, from most strict match to least one + for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext), + 'boost_%s%s%s%s$' % (lib, tags, version, ext), + # Give up trying to find the right version + 'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext), + 'boost_%s%s%s$' % (lib, tags, ext), + 'boost_%s%s$' % (lib, ext), + 'boost_%s' % lib]: + self.to_log('Trying pattern %s' % pattern) + file = find_lib(re.compile(pattern), files) + if file: + libs.append(format_lib_name(file.name)) + break + else: + self.end_msg('lib %s not found in %s' % (lib, path.abspath())) + self.fatal('The configuration failed') + return libs + + return path.abspath(), match_libs(kw.get('lib', None), False), match_libs(kw.get('stlib', None), True) @conf @@ -283,7 +302,10 @@ def check_boost(self, *k, **kw): if not self.env['CXX']: self.fatal('load a c++ compiler first, conf.load("compiler_cxx")') - params = {'lib': k and k[0] or kw.get('lib', None)} + params = { + 'lib': k and k[0] or kw.get('lib', None), + 'stlib': kw.get('stlib', None) + } for key, value in self.options.__dict__.items(): if not key.startswith('boost_'): continue @@ -293,47 +315,41 @@ def check_boost(self, *k, **kw): var = kw.get('uselib_store', 'BOOST') self.start_msg('Checking boost includes') - try: - self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) - self.env.BOOST_VERSION = self.boost_get_version(inc) - except Errors.WafError: - self.end_msg("not found", 'YELLOW') - raise - #self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) - #self.env.BOOST_VERSION = self.boost_get_version(inc) + self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) + self.env.BOOST_VERSION = self.boost_get_version(inc) self.end_msg(self.env.BOOST_VERSION) if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) - if not params['lib']: + if not params['lib'] and not params['stlib']: return + if 'static' in kw or 'static' in params: + Logs.warn('boost: static parameter is deprecated, use stlib instead.') self.start_msg('Checking boost libs') - try: - suffix = params.get('static', None) and 'ST' or '' - path, libs = self.boost_get_libs(**params) - except Errors.WafError: - self.end_msg("not found", 'YELLOW') - raise - #suffix = params.get('static', None) and 'ST' or '' - #path, libs = self.boost_get_libs(**params) - self.env['%sLIBPATH_%s' % (suffix, var)] = [path] - self.env['%sLIB_%s' % (suffix, var)] = libs + path, libs, stlibs = self.boost_get_libs(**params) + self.env['LIBPATH_%s' % var] = [path] + self.env['STLIBPATH_%s' % var] = [path] + self.env['LIB_%s' % var] = libs + self.env['STLIB_%s' % var] = stlibs self.end_msg('ok') if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % path) - Logs.pprint('CYAN', ' libs : %s' % libs) + Logs.pprint('CYAN', ' shared libs : %s' % libs) + Logs.pprint('CYAN', ' static libs : %s' % stlibs) def try_link(): - if 'system' in params['lib']: + if (params['lib'] and 'system' in params['lib']) or \ + params['stlib'] and 'system' in params['stlib']: self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False) - if 'thread' in params['lib']: + if (params['lib'] and 'thread' in params['lib']) or \ + params['stlib'] and 'thread' in params['stlib']: self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False) if params.get('linkage_autodetect', False): self.start_msg("Attempting to detect boost linkage flags") toolset = self.boost_get_toolset(kw.get('toolset', '')) - if toolset in ['vc']: + if toolset in ('vc',): # disable auto-linking feature, causing error LNK1181 # because the code wants to be linked against self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] @@ -378,3 +394,18 @@ def check_boost(self, *k, **kw): self.fatal('The configuration failed') self.end_msg('ok') + +@feature('cxx') +@after_method('apply_link') +def install_boost(self): + if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'): + return + install_boost.done = True + inst_to = getattr(self, 'install_path', '${BINDIR}') + for lib in self.env.LIB_BOOST: + try: + file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST) + self.bld.install_files(inst_to, self.bld.root.find_node(file)) + except: + continue +install_boost.done = False diff --git a/waf-tools/command.py b/waf-tools/command.py index 9f2c0c5a2..b3161f97c 100644 --- a/waf-tools/command.py +++ b/waf-tools/command.py @@ -21,8 +21,8 @@ class command_task(Task.Task): def __str__(self): "string to display to the user" env = self.env - src_str = ' '.join([a.nice_path(env) for a in self.inputs]) - tgt_str = ' '.join([a.nice_path(env) for a in self.outputs]) + src_str = ' '.join([a.bldpath() for a in self.inputs]) + tgt_str = ' '.join([a.bldpath() for a in self.outputs]) if self.outputs: sep = ' -> ' else: diff --git a/waf-tools/misc.py b/waf-tools/misc.py index 71b5fa62c..61f98a58b 100644 --- a/waf-tools/misc.py +++ b/waf-tools/misc.py @@ -32,7 +32,7 @@ def copy_func(tsk): outfile = tsk.outputs[0].abspath() try: shutil.copy2(infile, outfile) - except (OSError, IOError): + except EnvironmentError: return 1 else: if tsk.chmod: os.chmod(outfile, tsk.chmod)