From 0e169c157f05114eaa854e47f2148679cd7aa8db Mon Sep 17 00:00:00 2001 From: Alexander Afanasyev Date: Mon, 1 Apr 2013 22:34:50 +0200 Subject: [PATCH] Fix Python bindings and openflow for waf 1.7.10 upgrade and take care about boost requirements globally --- bindings/python/wscript | 48 +++++------- src/openflow/wscript | 41 ++++++---- src/wscript | 76 ++++++++++-------- waf-tools/boost.py | 166 +++++++++++++++++++++++++++++++--------- 4 files changed, 219 insertions(+), 112 deletions(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index 085f502b2..65ea56333 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -6,25 +6,17 @@ import subprocess import shutil import sys -import Task -import Options -import Configure -import TaskGen -import Logs -import Build -import Utils - +from waflib import Task, Options, Configure, TaskGen, Logs, Build, Utils, Errors from waflib.Errors import WafError +feature = TaskGen.feature +after = TaskGen.after + ## https://launchpad.net/pybindgen/ REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 809) REQUIRED_PYGCCXML_VERSION = (0, 9, 5) -from TaskGen import feature, after -import Task - - def add_to_python_path(path): if os.environ.get('PYTHONPATH', ''): @@ -38,7 +30,7 @@ def set_pybindgen_pythonpath(env): def options(opt): - opt.tool_options('python') + opt.load('python') opt.add_option('--disable-python', help=("Don't build Python bindings."), action="store_true", default=False, @@ -76,7 +68,7 @@ def configure(conf): available_modules.sort() all_modules_enabled = (enabled_modules == available_modules) - conf.check_tool('misc', tooldir=['waf-tools']) + conf.load('misc', tooldir=['waf-tools']) if sys.platform == 'cygwin': conf.report_optional_feature("python", "Python Bindings", False, @@ -91,20 +83,20 @@ def configure(conf): conf.env.PYTHON = Options.options.with_python try: - conf.check_tool('python') - except Configure.ConfigurationError, ex: + conf.load('python') + except Errors.ConfigurationError, ex: conf.report_optional_feature("python", "Python Bindings", False, "The python interpreter was not found") return try: conf.check_python_version((2,3)) - except Configure.ConfigurationError, ex: + except Errors.ConfigurationError, ex: conf.report_optional_feature("python", "Python Bindings", False, "The python found version is too low (2.3 required)") return try: conf.check_python_headers() - except Configure.ConfigurationError, ex: + except Errors.ConfigurationError, ex: conf.report_optional_feature("python", "Python Bindings", False, "Python library or headers missing") return @@ -161,7 +153,7 @@ def configure(conf): try: conf.check_python_module('pybindgen') - except Configure.ConfigurationError: + except Errors.ConfigurationError: Logs.warn("pybindgen missing => no python bindings") conf.report_optional_feature("python", "Python Bindings", False, "PyBindGen missing") @@ -197,9 +189,9 @@ int main () try: ret = conf.run_c_code(code=test_program, - env=conf.env.copy(), compile_filename='test.cc', + env=conf.env.derive(), compile_filename='test.cc', features='cxx cprogram', execute=False) - except Configure.ConfigurationError: + except Errors.ConfigurationError: ret = 1 conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes')) return not ret @@ -250,7 +242,7 @@ int main () ## Check for pygccxml try: conf.check_python_module('pygccxml') - except Configure.ConfigurationError: + except Errors.ConfigurationError: conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, "Missing 'pygccxml' Python module") return @@ -322,7 +314,7 @@ class apiscan_task(Task.TaskBase): """Uses gccxml to scan the file 'everything.h' and extract API definitions. """ after = 'gen_ns3_module_header ns3header' - before = 'cc cxx command' + before = 'cxx command' color = "BLUE" def __init__(self, curdirnode, env, bld, target, cflags, module): self.bld = bld @@ -393,7 +385,7 @@ class python_scan_task_collector(Task.TaskBase): """Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit """ after = 'apiscan' - before = 'cc cxx' + before = 'cxx' color = "BLUE" def __init__(self, curdirnode, env, bld): self.bld = bld @@ -415,7 +407,7 @@ class python_scan_task_collector(Task.TaskBase): class gen_ns3_compat_pymod_task(Task.Task): """Generates a 'ns3.py' compatibility module.""" - before = 'cc cxx' + before = 'cxx' color = 'BLUE' def run(self): @@ -437,8 +429,6 @@ def build(bld): return env = bld.env - curdir = bld.path.abspath() - set_pybindgen_pythonpath(env) if Options.options.apiscan: @@ -489,9 +479,7 @@ def build(bld): grp = bld.get_group(bld.current_group) grp.append(task) - bld.new_task_gen(features='copy', - source="ns__init__.py", - target='ns/__init__.py') + bld(features='copy', source="ns__init__.py", target='ns/__init__.py') bld.install_as('${PYTHONARCHDIR}/ns/__init__.py', 'ns__init__.py') diff --git a/src/openflow/wscript b/src/openflow/wscript index ff219c043..54e6c30ae 100644 --- a/src/openflow/wscript +++ b/src/openflow/wscript @@ -1,25 +1,21 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- import os -import Options +from waflib import Logs, Options from waflib.Errors import WafError def options(opt): opt.add_option('--with-openflow', help=('Path to OFSID source for NS-3 OpenFlow Integration support'), default='', dest='with_openflow') - opt.tool_options('boost', tooldir=["waf-tools"]) + +REQUIRED_BOOST_LIBS = ['system', 'signals', 'filesystem'] + +def required_boost_libs(conf): + conf.env['REQUIRED_BOOST_LIBS'] += REQUIRED_BOOST_LIBS def configure(conf): - try: - conf.check_tool('boost') - conf.check_boost(lib='signals filesystem') - if not conf.env.LIB_BOOST: - conf.check_boost(lib='signals filesystem', libpath="/usr/lib64") - except WafError: - conf.env['LIB_BOOST'] = [] - - if not conf.env.LIB_BOOST: + if not conf.env['LIB_BOOST']: conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False, "Required boost libraries not found") @@ -29,6 +25,25 @@ def configure(conf): return + present_boost_libs = [] + for boost_lib_name in conf.env['LIB_BOOST']: + if boost_lib_name.startswith("boost_"): + boost_lib_name = boost_lib_name[6:] + if boost_lib_name.endswith("-mt"): + boost_lib_name = boost_lib_name[:-3] + present_boost_libs.append(boost_lib_name) + + missing_boost_libs = [lib for lib in REQUIRED_BOOST_LIBS if lib not in present_boost_libs] + if missing_boost_libs != []: + conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False, + "Required boost libraries not found, missing: %s" % ', '.join(missing_boost_libs)) + + # Add this module to the list of modules that won't be built + # if they are enabled. + conf.env['MODULES_NOT_BUILT'].append('openflow') + + return + if Options.options.with_openflow: if os.path.isdir(Options.options.with_openflow): conf.msg("Checking for OpenFlow location", ("%s (given)" % Options.options.with_openflow)) @@ -142,7 +157,7 @@ def build(bld): obj.use.extend('OPENFLOW DL XML2'.split()) obj_test.use.extend('OPENFLOW DL XML2'.split()) - headers = bld.new_task_gen(features=['ns3header']) + headers = bld(features='ns3header') headers.module = 'openflow' headers.source = [ ] @@ -160,4 +175,4 @@ def build(bld): headers.source.append('helper/openflow-switch-helper.h') if bld.env['ENABLE_EXAMPLES'] and bld.env['ENABLE_OPENFLOW']: - bld.add_subdirs('examples') + bld.recurse('examples') diff --git a/src/wscript b/src/wscript index d9b567775..1f9a8a016 100644 --- a/src/wscript +++ b/src/wscript @@ -6,14 +6,8 @@ import shutil import types import warnings +from waflib import TaskGen, Task, Options, Build, Utils from waflib.Errors import WafError - -import TaskGen -import Task -import Options -import Build -import Utils - import wutils try: @@ -47,13 +41,26 @@ def options(opt): help=("Build only these modules (and dependencies)"), dest='enable_modules') - for module in all_modules: - opt.sub_options(module, mandatory=False) + opt.load('boost', tooldir=['waf-tools']) + for module in all_modules: + opt.recurse(module, mandatory=False) def configure(conf): + conf.env['REQUIRED_BOOST_LIBS'] = [] for module in all_modules: - conf.sub_config(module, mandatory=False) + conf.recurse (module, name="required_boost_libs", mandatory=False) + + if conf.env['REQUIRED_BOOST_LIBS'] is not []: + conf.load('boost') + conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), mandatory=False) + if not conf.env['LIB_BOOST']: + conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), libpath="/usr/lib64", mandatory=False) + if not conf.env['LIB_BOOST']: + conf.env['LIB_BOOST'] = [] + + for module in all_modules: + conf.recurse(module, mandatory=False) blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) conf.env.append_value('NS3_MODULE_PATH', blddir) @@ -75,10 +82,10 @@ def create_ns3_module(bld, name, dependencies=(), test=False): static = bool(bld.env.ENABLE_STATIC_NS3) # Create a separate library for this module. if static: - module = bld.new_task_gen(features=['cxx', 'cxxstlib', 'ns3module']) + module = bld(features='cxx cxxstlib ns3module') else: - module = bld.new_task_gen(features=['cxx', 'cxxshlib', 'ns3module']) - module.target = '%s/ns%s-%s%s' % (bld.srcnode.relpath_gen(module.path), wutils.VERSION, + module = bld(features='cxx cxxshlib ns3module') + module.target = '%s/ns%s-%s%s' % (bld.srcnode.path_from(module.path), wutils.VERSION, name, bld.env.BUILD_SUFFIX) linkflags = [] cxxflags = [] @@ -119,7 +126,7 @@ def create_ns3_module(bld, name, dependencies=(), test=False): module.use = ['ns3-' + dep for dep in dependencies] module.test = test module.is_ns3_module = True - module.ns3_dir_location = bld.path.relpath_gen(bld.srcnode) + module.ns3_dir_location = bld.path.path_from(bld.srcnode) module.env.append_value("INCLUDES", '#') @@ -133,7 +140,7 @@ def create_ns3_module(bld, name, dependencies=(), test=False): def apply_incpaths_ns3testlib(self): if not self.source: return - testdir = self.source[-1].parent.relpath_gen(self.bld.srcnode) + testdir = self.source[-1].parent.path_from(self.bld.srcnode) self.env.append_value("DEFINES", 'NS_TEST_SOURCEDIR="%s"' % (testdir,)) @@ -142,7 +149,7 @@ def create_ns3_module_test_library(bld, name): # the module being tested. library_name = name + "-test" library = bld.create_ns3_module(library_name, [name], test=True) - library.features.append("ns3testlib") + library.features += " ns3testlib" # Modify attributes for the test library that are different from a # normal module. @@ -154,7 +161,7 @@ def create_ns3_module_test_library(bld, name): bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', [(library.module_name, library.name)]) # Set the include path from the build directory to modules. - relative_path_from_build_to_here = bld.path.relpath_gen(bld.bldnode) + relative_path_from_build_to_here = bld.path.path_from(bld.bldnode) include_flag = '-I' + relative_path_from_build_to_here library.env.append_value('CXXFLAGS', include_flag) library.env.append_value('CCFLAGS', include_flag) @@ -162,9 +169,9 @@ def create_ns3_module_test_library(bld, name): return library def create_obj(bld, *args): - warnings.warn("(in %s) Use bld.new_task_gen(...) now, instead of bld.create_obj(...)" % str(bld.path), + warnings.warn("(in %s) Use bld(...) call now, instead of bld.create_obj(...)" % str(bld.path), DeprecationWarning, stacklevel=2) - return bld.new_task_gen(*args) + return bld(*args) def ns3_python_bindings(bld): @@ -197,23 +204,24 @@ def ns3_python_bindings(bld): #debug = ('PYBINDGEN_DEBUG' in os.environ) debug = True # XXX - source = [bld.srcnode.find_resource('bindings/python/ns3modulegen-modular.py').relpath_gen(bld.path), - "bindings/modulegen__%s.py" % apidefs] + source = [bld.srcnode.find_resource('bindings/python/ns3modulegen-modular.py'), + bld.path.find_resource("bindings/modulegen__%s.py" % apidefs)] - if bindings_dir.find_resource("modulegen_customizations.py") is not None: - source.append("bindings/modulegen_customizations.py") + modulegen_customizations = bindings_dir.find_resource("modulegen_customizations.py") + if modulegen_customizations is not None: + source.append(modulegen_customizations) + modulegen_local = bld.path.find_resource("bindings/modulegen_local.py") # the local customization file may or not exist - if bld.path.find_resource("bindings/modulegen_local.py"): + if modulegen_local is not None: source.append("bindings/modulegen_local.py") module_py_name = module.replace('-', '_') - module_target_dir = bld.srcnode.find_dir("bindings/python/ns").relpath_gen(bld.path) + module_target_dir = bld.srcnode.find_dir("bindings/python/ns").path_from(bld.path) # if bindings/.py exists, it becomes the module frontend, and the C extension befomes _ if bld.path.find_resource("bindings/%s.py" % (module_py_name,)) is not None: - bld.new_task_gen( - features='copy', + bld(features='copy', source=("bindings/%s.py" % (module_py_name,)), target=('%s/%s.py' % (module_target_dir, module_py_name))) extension_name = '_%s' % (module_py_name,) @@ -240,7 +248,7 @@ def ns3_python_bindings(bld): if was_enabled: features.append(name) - bindgen = bld.new_task_gen(features=['command'], source=source, target=target, command=argv) + bindgen = bld(features='command', source=source, target=target, command=argv) bindgen.env['FEATURES'] = ','.join(features) bindgen.dep_vars = ['FEATURES', "GCC_RTTI_ABI_COMPLETE"] bindgen.before = 'cxx' @@ -249,7 +257,7 @@ def ns3_python_bindings(bld): bindgen.install_path = None # generate the extension module - pymod = bld.new_task_gen(features='cxx cxxshlib pyext') + pymod = bld(features='cxx cxxshlib pyext') pymod.source = ['bindings/ns3module.cc'] pymod.target = '%s/%s' % (module_target_dir, extension_name) pymod.name = 'ns3module_%s' % module @@ -305,14 +313,14 @@ def build(bld): if not_built in all_modules: all_modules.remove(not_built) - bld.add_subdirs(list(all_modules)) + bld.recurse(list(all_modules)) for module in all_modules: - modheader = bld.new_task_gen(features=['ns3moduleheader']) + modheader = bld(features='ns3moduleheader') modheader.module = module.split('/')[-1] class ns3pcfile_task(Task.Task): - after = 'cc cxx' + after = 'cxx' def __str__(self): "string to display to the user" @@ -448,7 +456,7 @@ def apply_ns3header(self): class ns3header_task(Task.Task): - before = 'cc cxx gen_ns3_module_header' + before = 'cxx gen_ns3_module_header' color = 'BLUE' def __str__(self): @@ -517,7 +525,7 @@ class ns3header_task(Task.Task): class gen_ns3_module_header_task(Task.Task): - before = 'cc cxx' + before = 'cxx' after = 'ns3header' color = 'BLUE' diff --git a/waf-tools/boost.py b/waf-tools/boost.py index 2ca82e245..efbf598e0 100644 --- a/waf-tools/boost.py +++ b/waf-tools/boost.py @@ -9,34 +9,53 @@ # rewritten for waf 1.6.2, Sylvain Rouquette, 2011 ''' + +This is an extra tool, not bundled with the default waf binary. To add the boost tool to the waf file: $ ./waf-light --tools=compat15,boost or, if you have waf >= 1.6.2 $ ./waf update --files=boost -The wscript will look like: +When using this tool, the wscript will look like: -def options(opt): - opt.load('compiler_cxx boost') + def options(opt): + opt.load('compiler_cxx boost') -def configure(conf): - conf.load('compiler_cxx boost') - conf.check_boost(lib='system filesystem', mt=True, static=True) + def configure(conf): + conf.load('compiler_cxx boost') + conf.check_boost(lib='system filesystem') + + def build(bld): + bld(source='main.cpp', target='app', use='BOOST') + +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. +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: + - boost might also be compiled with /MT, which links the runtime statically. + 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. -def build(bld): - bld(source='main.cpp', target='app', use='BOOST') ''' import sys import re -from waflib import Utils, Logs +from waflib import Utils, Logs, Errors from waflib.Configure import conf from waflib.Errors import WafError -BOOST_LIBS = ('/usr/lib', '/usr/local/lib', - '/opt/local/lib', '/sw/lib', '/lib') -BOOST_INCLUDES = ('/usr/include', '/usr/local/include', - '/opt/local/include', '/sw/include') +BOOST_LIBS = ['/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 = ''' #include @@ -76,21 +95,23 @@ BOOST_TOOLSETS = { def options(opt): opt.add_option('--boost-includes', type='string', default='', dest='boost_includes', - help='''path to the boost directory where the includes are - e.g. /boost_1_45_0/include''') + help='''path to the boost includes root (~boost root) + e.g. /path/to/boost_1_47_0''') opt.add_option('--boost-libs', type='string', default='', dest='boost_libs', help='''path to the directory where the boost libs are - e.g. /boost_1_45_0/stage/lib''') + 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 static libraries') + 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), 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)") opt.add_option('--boost-toolset', type='string', default='', dest='boost_toolset', help='force a toolset e.g. msvc, vc90, \ @@ -117,8 +138,7 @@ def boost_get_version(self, dir): try: val = re_but.search(self.__boost_get_version_file(dir).read()).group(1) except: - val = self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[dir], - execute=True, define_ret=True) + val = self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[dir], execute=False, define_ret=True) return val @@ -130,10 +150,11 @@ def boost_get_includes(self, *k, **kw): for dir in BOOST_INCLUDES: if self.__boost_get_version_file(dir): return dir - if includes: - self.fatal('headers not found in %s' % includes) - else: - self.fatal('headers not found, use --boost-includes=/path/to/boost') + if kw.get('boost_mandatory', True): + if includes: + self.fatal('headers not found in %s' % includes) + else: + self.fatal('headers not found, please provide a --boost-includes argument (see help)') @conf @@ -176,10 +197,12 @@ def __boost_get_libs_path(self, *k, **kw): if libs: self.fatal('libs not found in %s' % libs) else: - self.fatal('libs not found, \ - use --boost-includes=/path/to/boost/lib') - return path, files + self.fatal('libs not found, please provide a --boost-libs argument (see help)') + self.to_log('Found the boost path in %r with the libraries:' % path) + for x in files: + self.to_log(' %r' % x) + return path, files @conf def boost_get_libs(self, *k, **kw): @@ -194,37 +217,40 @@ def boost_get_libs(self, *k, **kw): if kw.get('abi', None): t.append(kw['abi']) tags = t and '(-%s)+' % '-'.join(t) or '' - toolset = '(-%s[0-9]{0,3})+' % self.boost_get_toolset(kw.get('toolset', '')) + toolset = self.boost_get_toolset(kw.get('toolset', '')) + toolset_pat = '(-%s[0-9]{0,3})+' % toolset version = '(-%s)+' % self.env.BOOST_VERSION def find_lib(re_lib, files): for file in files: if re_lib.search(file.name): + self.to_log('Found boost lib %s' % file) return file return None def format_lib_name(name): - if name.startswith('lib'): + if name.startswith('lib') and self.env.CC_NAME != 'msvc': name = name[3:] - return name.split('.')[0] + 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, tags, py, version), + 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, tags, py), + '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.fatal('lib %s not found in %s' % (lib, path)) + self.fatal('lib %s not found in %s' % (lib, path.abspath())) return path.abspath(), libs @@ -232,10 +258,10 @@ def boost_get_libs(self, *k, **kw): @conf def check_boost(self, *k, **kw): """ - initialize boost + Initialize boost libraries to be used. - You can pass the same parameters as the command line (without "--boost-"), - but the command line has the priority. + Keywords: you can pass the same parameters as with the command line (without "--boost-"). + Note that the command line has the priority, and should preferably be used. """ if not self.env['CXX']: self.fatal('load a c++ compiler first, conf.load("compiler_cxx")') @@ -256,6 +282,8 @@ def check_boost(self, *k, **kw): except 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.end_msg(self.env.BOOST_VERSION) if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) @@ -269,6 +297,8 @@ def check_boost(self, *k, **kw): except 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 self.end_msg('ok') @@ -276,3 +306,69 @@ def check_boost(self, *k, **kw): Logs.pprint('CYAN', ' path : %s' % path) Logs.pprint('CYAN', ' libs : %s' % libs) + + def try_link(): + if 'system' in params['lib']: + self.check_cxx( + fragment="\n".join([ + '#include ', + 'int main() { boost::system::error_code c; }', + ]), + use=var, + execute=False, + ) + if 'thread' in params['lib']: + self.check_cxx( + fragment="\n".join([ + '#include ', + 'int main() { boost::thread t; }', + ]), + 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']: + # disable auto-linking feature, causing error LNK1181 + # because the code wants to be linked against + self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] + + # if no dlls are present, we guess the .lib files are not stubs + has_dlls = False + for x in Utils.listdir(path): + if x.endswith(self.env.cxxshlib_PATTERN % ''): + has_dlls = True + break + if not has_dlls: + self.env['STLIBPATH_%s' % var] = [path] + self.env['STLIB_%s' % var] = libs + del self.env['LIB_%s' % var] + del self.env['LIBPATH_%s' % var] + + # we attempt to play with some known-to-work CXXFLAGS combinations + for cxxflags in (['/MD', '/EHsc'], []): + self.env.stash() + self.env["CXXFLAGS_%s" % var] += cxxflags + try: + try_link() + self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var])) + e = None + break + except Errors.ConfigurationError as exc: + self.env.revert() + e = exc + + if e is not None: + self.fatal("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e) + else: + self.fatal("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain") + else: + self.start_msg('Checking for boost linkage') + try: + try_link() + except Errors.ConfigurationError as e: + self.fatal("Could not link against boost libraries using supplied options") + self.end_msg('ok') +