From c3059b6e68c98fd0ca13629a3230ea9f78eecec5 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 8 Sep 2011 16:13:40 +0100 Subject: [PATCH 01/17] Upgrade to waf-1.6.7, work in progress --- bindings/python/wscript | 121 +++----- src/aodv/wscript | 2 +- src/applications/wscript | 2 +- src/bridge/wscript | 2 +- src/click/wscript | 10 +- src/config-store/wscript | 2 +- src/core/wscript | 42 ++- src/csma-layout/wscript | 2 +- src/csma/wscript | 2 +- src/dsdv/wscript | 2 +- src/emu/examples/wscript | 2 +- src/emu/wscript | 5 +- src/energy/wscript | 2 +- src/flow-monitor/wscript | 2 +- src/internet/wscript | 14 +- src/lte/wscript | 2 +- src/mesh/wscript | 2 +- src/mobility/wscript | 2 +- src/mpi/wscript | 4 +- src/netanim/wscript | 2 +- src/network/wscript | 2 +- src/nix-vector-routing/wscript | 2 +- src/olsr/wscript | 2 +- src/openflow/wscript | 4 +- src/point-to-point-layout/wscript | 2 +- src/point-to-point/wscript | 2 +- src/propagation/wscript | 2 +- src/spectrum/wscript | 2 +- src/stats/wscript | 4 +- src/tap-bridge/examples/wscript | 2 +- src/tap-bridge/wscript | 4 +- src/template/wscript | 2 +- src/test/ns3tcp/wscript | 2 +- src/test/ns3wifi/wscript | 2 +- src/test/wscript | 2 +- src/tools/wscript | 2 +- src/topology-read/wscript | 2 +- src/uan/wscript | 2 +- src/virtual-net-device/wscript | 2 +- src/visualizer/wscript | 2 +- src/wifi/wscript | 2 +- src/wimax/wscript | 2 +- src/wscript | 470 ++++++++++++++---------------- utils/wscript | 4 +- waf | Bin 91757 -> 85720 bytes waf-tools/boost.py | 269 +++++++++++++++++ waf-tools/command.py | 49 ++-- waf-tools/misc.py | 416 ++++++++++++++++++++++++++ waf-tools/pkgconfig.py | 37 ++- wscript | 400 ++++++++++++++----------- wutils.py | 35 ++- 51 files changed, 1317 insertions(+), 637 deletions(-) create mode 100644 waf-tools/boost.py create mode 100644 waf-tools/misc.py diff --git a/bindings/python/wscript b/bindings/python/wscript index 3dc3e33fe..bcbb57b36 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -2,7 +2,7 @@ import types import re import os -import pproc as subprocess +import subprocess import shutil import sys @@ -21,17 +21,17 @@ REQUIRED_PYGCCXML_VERSION = (0, 9, 5) from TaskGen import feature, after -import Task, ccroot -from python import _get_python_variables # this comes from wafadmin/Tools/python.py +import Task +#from python import _get_python_variables # this comes from wafadmin/Tools/python.py - -# Patch a bug in waf-1.5.16's python detection, see -# https://www.nsnam.org/bugzilla/show_bug.cgi?id=1250 -import python -python.FRAG_2 = """ -#include -""" + python.FRAG_2 -del python +if 0: + # Patch a bug in waf-1.5.16's python detection, see + # https://www.nsnam.org/bugzilla/show_bug.cgi?id=1250 + import python + python.FRAG_2 = """ + #include + """ + python.FRAG_2 + del python @@ -86,7 +86,7 @@ def configure(conf): available_modules.sort() all_modules_enabled = (enabled_modules == available_modules) - conf.check_tool('misc') + conf.check_tool('misc', tooldir=['waf-tools']) if sys.platform == 'cygwin': conf.report_optional_feature("python", "Python Bindings", False, @@ -104,16 +104,17 @@ def configure(conf): return - # alternative code to computing PYTHONDIR, that is more correct than the one in waf 1.5.16 - if 'PYTHONDIR' in conf.environ: - pydir = conf.environ['PYTHONDIR'] - else: - (pydir,) = _get_python_variables(conf.env['PYTHON'], - ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r)" % conf.env['PREFIX']], - ['from distutils.sysconfig import get_python_lib']) - if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist - conf.define('PYTHONDIR', pydir) - conf.env['PYTHONDIR'] = pydir + if 0: + # alternative code to computing PYTHONDIR, that is more correct than the one in waf 1.5.16 + if 'PYTHONDIR' in conf.environ: + pydir = conf.environ['PYTHONDIR'] + else: + (pydir,) = _get_python_variables(conf.env['PYTHON'], + ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r)" % conf.env['PREFIX']], + ['from distutils.sysconfig import get_python_lib']) + if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist + conf.define('PYTHONDIR', pydir) + conf.env['PYTHONDIR'] = pydir # -fvisibility=hidden optimization @@ -125,7 +126,7 @@ def configure(conf): # Check for the location of pybindgen if Options.options.with_pybindgen is not None: if os.path.isdir(Options.options.with_pybindgen): - conf.check_message("pybindgen location", '', True, ("%s (given)" % Options.options.with_pybindgen)) + conf.msg("Checking for pybindgen location", ("%s (given)" % Options.options.with_pybindgen)) conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen) else: # ns-3-dev uses ../pybindgen, while ns-3 releases use ../REQUIRED_PYBINDGEN_VERSION @@ -133,15 +134,15 @@ def configure(conf): pybindgen_release_str = "pybindgen-" + '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION]) pybindgen_release_dir = os.path.join('..', pybindgen_release_str) if os.path.isdir(pybindgen_dir): - conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_dir)) + conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_dir)) conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_dir) elif os.path.isdir(pybindgen_release_dir): - conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_release_dir)) + conf.msg("Checking for pybindgen location", ("%s (guessed)" % pybindgen_release_dir)) conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_release_dir) del pybindgen_dir del pybindgen_release_dir if not conf.env['WITH_PYBINDGEN']: - conf.check_message("pybindgen location", '', False) + conf.msg("pybindgen location", False) # Check for pybindgen @@ -155,15 +156,13 @@ def configure(conf): "PyBindGen missing") return else: - out = subprocess.Popen([conf.env['PYTHON'], "-c", + out = subprocess.Popen([conf.env['PYTHON'][0], "-c", "import pybindgen.version; " "print '.'.join([str(x) for x in pybindgen.version.__version__])"], stdout=subprocess.PIPE).communicate()[0] pybindgen_version_str = out.strip() pybindgen_version = tuple([int(x) for x in pybindgen_version_str.split('.')]) - conf.check_message('pybindgen', 'version', - (pybindgen_version == REQUIRED_PYBINDGEN_VERSION), - pybindgen_version_str) + conf.msg('Checking for pybindgen version', pybindgen_version_str) if not (pybindgen_version == REQUIRED_PYBINDGEN_VERSION): Logs.warn("pybindgen (found %s), (need %s)" % (pybindgen_version_str, @@ -188,10 +187,10 @@ int main () try: ret = conf.run_c_code(code=test_program, env=conf.env.copy(), compile_filename='test.cc', - compile_mode='cxx',type='cprogram', execute=False) + features='cxx cprogram', execute=False) except Configure.ConfigurationError: ret = 1 - conf.check_message_custom('types %s and %s' % (t1, t2), 'equivalency', (ret and 'no' or 'yes')) + conf.msg('Checking for types %s and %s equivalence' % (t1, t2), (ret and 'no' or 'yes')) return not ret uint64_is_long = test("uint64_t", "unsigned long") @@ -208,7 +207,7 @@ int main () else: msg = conf.env['PYTHON_BINDINGS_APIDEFS'] - conf.check_message_custom('the apidefs that can be used for Python bindings', '', msg) + conf.msg('Checking for the apidefs that can be used for Python bindings', msg) if conf.env['PYTHON_BINDINGS_APIDEFS'] is None: conf.report_optional_feature("python", "Python Bindings", False, @@ -230,9 +229,9 @@ int main () return 0; } """ - gcc_rtti_abi = conf.check(fragment=fragment, msg="Checking for internal GCC cxxabi", - okmsg="complete", errmsg='incomplete', - mandatory=False) + gcc_rtti_abi = conf.check_nonfatal(fragment=fragment, msg="Checking for internal GCC cxxabi", + okmsg="complete", errmsg='incomplete', + mandatory=False) conf.env["GCC_RTTI_ABI_COMPLETE"] = str(bool(gcc_rtti_abi)) @@ -245,14 +244,12 @@ int main () "Missing 'pygccxml' Python module") return - out = subprocess.Popen([conf.env['PYTHON'], "-c", + out = subprocess.Popen([conf.env['PYTHON'][0], "-c", "import pygccxml; print pygccxml.__version__"], stdout=subprocess.PIPE).communicate()[0] pygccxml_version_str = out.strip() pygccxml_version = tuple([int(x) for x in pygccxml_version_str.split('.')]) - conf.check_message('pygccxml', 'version', - (pygccxml_version >= REQUIRED_PYGCCXML_VERSION), - pygccxml_version_str) + conf.msg('Checking for pygccxml version', pygccxml_version_str) if not (pygccxml_version >= REQUIRED_PYGCCXML_VERSION): Logs.warn("pygccxml (found %s) is too old (need %s) => " "automatic scanning of API definitions will not be possible" % @@ -275,7 +272,7 @@ int main () m = re.match( "^GCC-XML version (\d\.\d(\.\d)?)$", gccxml_version_line) gccxml_version = m.group(1) gccxml_version_ok = ([int(s) for s in gccxml_version.split('.')] >= [0, 9]) - conf.check_message('gccxml', 'version', True, gccxml_version) + conf.msg('Checking for gccxml version', gccxml_version) if not gccxml_version_ok: Logs.warn("gccxml too old, need version >= 0.9; automatic scanning of API definitions will not be possible") conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, @@ -311,7 +308,7 @@ def get_module_path(bld, module): class apiscan_task(Task.TaskBase): """Uses gccxml to scan the file 'everything.h' and extract API definitions. """ - after = 'gen_ns3_module_header_task ns3header_task' + after = 'gen_ns3_module_header ns3header' before = 'cc cxx gchx' color = "BLUE" def __init__(self, curdirnode, env, bld, target, cflags, module): @@ -378,47 +375,11 @@ def get_modules_and_headers(bld): -class python_scan_task(Task.TaskBase): - """Uses gccxml to scan the file 'everything.h' and extract API definitions. - """ - after = 'gen_everything_h_task' - before = 'cc cxx gchx' - color = "BLUE" - def __init__(self, curdirnode, env, bld, target, cflags): - self.bld = bld - super(python_scan_task, self).__init__(generator=self) - self.curdirnode = curdirnode - self.env = env - self.target = target - self.cflags = cflags - - def display(self): - return 'python-scan-%s\n' % (self.target,) - - def run(self): - defsdir = os.path.join(self.curdirnode.abspath(), 'apidefs', self.target) - try: - os.mkdir(defsdir) - except OSError: - pass - argv = [ - self.env['PYTHON'], - os.path.join(self.curdirnode.abspath(), 'ns3modulescan.py'), # scanning script - self.curdirnode.find_dir('../..').abspath(self.env), # include path (where the ns3 include dir is) - self.curdirnode.find_or_declare('everything.h').abspath(self.env), - os.path.join(defsdir, 'ns3modulegen_generated.py'), # output file - self.cflags, - ] - scan = subprocess.Popen(argv, stdin=subprocess.PIPE) - print >> scan.stdin, repr(get_modules_and_headers(self.bld)) - scan.stdin.close() - retval = scan.wait() - return retval class python_scan_task_collector(Task.TaskBase): """Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit """ - after = 'python_scan_task apiscan_task' + after = 'apiscan' before = 'cc cxx' color = "BLUE" def __init__(self, curdirnode, env, bld): @@ -512,7 +473,7 @@ def build(bld): if env['ENABLE_PYTHON_BINDINGS']: - task = gen_ns3_compat_pymod_task(env) + task = gen_ns3_compat_pymod_task(env=env) task.set_outputs(bld.path.find_or_declare("ns3.py")) task.dep_vars = ['PYTHON_MODULES_BUILT'] diff --git a/src/aodv/wscript b/src/aodv/wscript index cdb113ccf..6209a5b26 100644 --- a/src/aodv/wscript +++ b/src/aodv/wscript @@ -23,7 +23,7 @@ def build(bld): 'test/loopback.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'aodv' headers.source = [ 'model/aodv-id-cache.h', diff --git a/src/applications/wscript b/src/applications/wscript index 695abf946..684d1ce90 100644 --- a/src/applications/wscript +++ b/src/applications/wscript @@ -32,7 +32,7 @@ def build(bld): 'test/udp-client-server-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'applications' headers.source = [ 'model/bulk-send-application.h', diff --git a/src/bridge/wscript b/src/bridge/wscript index 5d3c8a744..8ff5e22af 100644 --- a/src/bridge/wscript +++ b/src/bridge/wscript @@ -7,7 +7,7 @@ def build(bld): 'model/bridge-channel.cc', 'helper/bridge-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'bridge' headers.source = [ 'model/bridge-net-device.h', diff --git a/src/click/wscript b/src/click/wscript index a600b78ee..955bb2637 100644 --- a/src/click/wscript +++ b/src/click/wscript @@ -12,16 +12,16 @@ def set_options(opt): def configure(conf): if Options.options.with_nsclick: if os.path.isdir(Options.options.with_nsclick): - conf.check_message("libnsclick.so location", '', True, ("%s (given)" % Options.options.with_nsclick)) + conf.msg("libnsclick.so location", ("%s (given)" % Options.options.with_nsclick)) conf.env['WITH_NSCLICK'] = os.path.abspath(Options.options.with_nsclick) else: nsclick_dir = os.path.join('..','click') if os.path.isdir(nsclick_dir): - conf.check_message("click location", '', True, ("%s (guessed)" % nsclick_dir)) + conf.msg("click location", ("%s (guessed)" % nsclick_dir)) conf.env['WITH_NSCLICK'] = os.path.abspath(nsclick_dir) del nsclick_dir if not conf.env['WITH_NSCLICK']: - conf.check_message("click location", '', False) + conf.msg("click location", False) conf.report_optional_feature("nsclick", "NS-3 Click Integration", False, "nsclick not enabled (see option --with-nsclick)") @@ -68,7 +68,7 @@ int main() conf.env['CPPPATH_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'include'))] - conf.env['NSCLICK'] = conf.check(fragment=test_code, lib='nsclick', uselib='NSCLICK DL') + conf.env['NSCLICK'] = conf.check_nonfatal(fragment=test_code, lib='nsclick', uselib='NSCLICK DL') conf.report_optional_feature("nsclick", "NS-3 Click Integration", conf.env['NSCLICK'], "nsclick library not found") if conf.env['NSCLICK']: @@ -101,7 +101,7 @@ def build(bld): module.uselib = 'NSCLICK DL' module_test.uselib = 'NSCLICK DL' - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'click' headers.source = [ 'model/ipv4-click-routing.h', diff --git a/src/config-store/wscript b/src/config-store/wscript index 49f016caa..c52b51e7a 100644 --- a/src/config-store/wscript +++ b/src/config-store/wscript @@ -29,7 +29,7 @@ def build(bld): 'model/raw-text-config.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'config-store' headers.source = [ 'model/file-config.h', diff --git a/src/core/wscript b/src/core/wscript index 74e8afe51..0c6483ab5 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -15,9 +15,8 @@ def set_options(opt): def configure(conf): - a = conf.check(type_name='uint128_t', define_name='HAVE_UINT128_T') - b = conf.check(type_name='__uint128_t', define_name='HAVE___UINT128_T') - + a = conf.check_nonfatal(type_name='uint128_t', define_name='HAVE_UINT128_T') + b = conf.check_nonfatal(type_name='__uint128_t', define_name='HAVE___UINT128_T') if Options.options.int64x64_as_double: conf.define('INT64X64_USE_DOUBLE', 1) @@ -32,20 +31,20 @@ def configure(conf): conf.env['INT64X64_USE_CAIRO'] = 1 highprec = 'cairo 128-bit integer' - conf.check_message_custom('high precision time', 'implementation', highprec) + conf.msg('Checking high precision time implementation', highprec) - conf.check(header_name='stdint.h', define_name='HAVE_STDINT_H') - conf.check(header_name='inttypes.h', define_name='HAVE_INTTYPES_H') - conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') - conf.check(header_name='sys/types.h', define_name='HAVE_SYS_TYPES_H') - conf.check(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H') - conf.check(header_name='dirent.h', define_name='HAVE_DIRENT_H') + conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H') + conf.check_nonfatal(header_name='inttypes.h', define_name='HAVE_INTTYPES_H') + conf.check_nonfatal(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') + conf.check_nonfatal(header_name='sys/types.h', define_name='HAVE_SYS_TYPES_H') + conf.check_nonfatal(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H') + conf.check_nonfatal(header_name='dirent.h', define_name='HAVE_DIRENT_H') - if conf.check(header_name='stdlib.h'): + if conf.check_nonfatal(header_name='stdlib.h'): conf.define('HAVE_STDLIB_H', 1) conf.define('HAVE_GETENV', 1) - conf.check(header_name='signal.h', define_name='HAVE_SIGNAL_H') + conf.check_nonfatal(header_name='signal.h', define_name='HAVE_SIGNAL_H') # Check for POSIX threads test_env = conf.env.copy() @@ -62,10 +61,9 @@ int main () return 0; } """ - have_pthread = conf.check(header_name='pthread.h', define_name='HAVE_PTHREAD_H', - env=test_env, fragment=fragment, - errmsg='Could not find pthread support (build/config.log for details)', - mandatory=False) + have_pthread = conf.check_nonfatal(header_name='pthread.h', define_name='HAVE_PTHREAD_H', + env=test_env, fragment=fragment, + errmsg='Could not find pthread support (build/config.log for details)') if have_pthread: # darwin accepts -pthread but prints a warning saying it is ignored if Options.platform != 'darwin' and Options.platform != 'cygwin': @@ -79,12 +77,12 @@ int main () conf.env['ENABLE_THREADING'], " include not detected") - conf.check(header_name='stdint.h', define_name='HAVE_STDINT_H') - conf.check(header_name='inttypes.h', define_name='HAVE_INTTYPES_H') + conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H') + conf.check_nonfatal(header_name='inttypes.h', define_name='HAVE_INTTYPES_H') - conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') + conf.check_nonfatal(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') - if not conf.check(lib='rt', uselib='RT', define_name='HAVE_RT'): + if not conf.check_nonfatal(lib='rt', uselib='RT', define_name='HAVE_RT'): conf.report_optional_feature("RealTime", "Real Time Simulator", False, "librt is not available") else: @@ -170,7 +168,7 @@ def build(bld): 'test/watchdog-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'core' headers.source = [ 'model/nstime.h', @@ -252,7 +250,7 @@ def build(bld): ]) - env = bld.env_of_name('default') + env = bld.env if env['INT64X64_USE_DOUBLE']: headers.source.extend(['model/int64x64-double.h']) elif env['INT64X64_USE_128']: diff --git a/src/csma-layout/wscript b/src/csma-layout/wscript index 79f0062e9..c692d3511 100644 --- a/src/csma-layout/wscript +++ b/src/csma-layout/wscript @@ -5,7 +5,7 @@ def build(bld): obj.source = [ 'model/csma-star-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'csma-layout' headers.source = [ 'model/csma-star-helper.h', diff --git a/src/csma/wscript b/src/csma/wscript index c5d10af5a..3b6294c21 100644 --- a/src/csma/wscript +++ b/src/csma/wscript @@ -8,7 +8,7 @@ def build(bld): 'model/csma-channel.cc', 'helper/csma-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'csma' headers.source = [ 'model/backoff.h', diff --git a/src/dsdv/wscript b/src/dsdv/wscript index 36fc14574..9790a83cd 100644 --- a/src/dsdv/wscript +++ b/src/dsdv/wscript @@ -16,7 +16,7 @@ def build(bld): 'test/dsdv-testcase.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'dsdv' headers.source = [ 'model/dsdv-rtable.h', diff --git a/src/emu/examples/wscript b/src/emu/examples/wscript index 3a2f70452..56e917589 100644 --- a/src/emu/examples/wscript +++ b/src/emu/examples/wscript @@ -1,7 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - env = bld.env_of_name('default') + env = bld.env if env['ENABLE_EMU']: obj = bld.create_ns3_program('emu-udp-echo', ['emu', 'internet', 'applications']) obj.source = 'emu-udp-echo.cc' diff --git a/src/emu/wscript b/src/emu/wscript index 97fa4cb9f..b48b012b8 100644 --- a/src/emu/wscript +++ b/src/emu/wscript @@ -15,7 +15,8 @@ def configure(conf): "needs threading support which is not available") if conf.env['ENABLE_EMU']: - blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant())) + #blddir = conf.bldnode.abspath() + blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) emucreatordir = os.path.abspath(os.path.join(blddir, "src/emu")) conf.env.append_value('NS3_EXECUTABLE_PATH', emucreatordir) else: @@ -35,7 +36,7 @@ def build(bld): 'helper/emu-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'emu' headers.source = [ 'model/emu-net-device.h', diff --git a/src/energy/wscript b/src/energy/wscript index 6892a3183..db582dcc3 100644 --- a/src/energy/wscript +++ b/src/energy/wscript @@ -25,7 +25,7 @@ def build(bld): 'test/li-ion-energy-source-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'energy' headers.source = [ 'model/wifi-radio-energy-model.h', diff --git a/src/flow-monitor/wscript b/src/flow-monitor/wscript index 29586c948..13fcabded 100644 --- a/src/flow-monitor/wscript +++ b/src/flow-monitor/wscript @@ -17,7 +17,7 @@ def build(bld): 'test/histogram-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'flow-monitor' headers.source = ["model/%s" % s for s in [ 'flow-monitor.h', diff --git a/src/internet/wscript b/src/internet/wscript index 554b975fa..6a699ea9a 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -32,23 +32,23 @@ def configure(conf): # Check for the location of NSC if Options.options.with_nsc: if os.path.isdir(Options.options.with_nsc): - conf.check_message("NSC location", '', True, ("%s (given)" % Options.options.with_nsc)) + conf.msg("NSC location", ("%s (given)" % Options.options.with_nsc)) conf.env['WITH_NSC'] = os.path.abspath(Options.options.with_nsc) else: # ns-3-dev uses ../nsc, while ns-3 releases use ../NSC_RELEASE_NAME nsc_dir = os.path.join('..', "nsc") nsc_release_dir = os.path.join('..', NSC_RELEASE_NAME) if os.path.isdir(nsc_dir): - conf.check_message("NSC location", '', True, ("%s (guessed)" % nsc_dir)) + conf.msg("NSC location",("%s (guessed)" % nsc_dir)) conf.env['WITH_NSC'] = os.path.abspath(nsc_dir) elif os.path.isdir(nsc_release_dir): - conf.check_message("NSC location", '', True, ("%s (guessed)" % nsc_release_dir)) + conf.msg("NSC location", ("%s (guessed)" % nsc_release_dir)) conf.env['WITH_NSC'] = os.path.abspath(nsc_release_dir) del nsc_dir del nsc_release_dir if not conf.env['WITH_NSC']: - conf.check_message("NSC location", '', False) + conf.msg("NSC location", False) conf.report_optional_feature("nsc", "Network Simulation Cradle", False, "NSC not found (see option --with-nsc)") return @@ -61,9 +61,9 @@ def configure(conf): if arch in ('x86_64', 'i686', 'i586', 'i486', 'i386'): conf.env['NSC_ENABLED'] = True conf.env.append_value('CXXDEFINES', 'NETWORK_SIMULATION_CRADLE') - conf.check(mandatory=True, lib='dl', define_name='HAVE_DL', uselib='DL') + conf.check_nonfatal(mandatory=True, lib='dl', define_name='HAVE_DL', uselib='DL') ok = True - conf.check_message('NSC supported architecture', arch, ok) + conf.msg('NSC supported architecture ' + arch, ok) if not ok: conf.env['NSC_ENABLED'] = False @@ -205,7 +205,7 @@ def build(bld): 'test/udp-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'internet' headers.source = [ 'model/udp-header.h', diff --git a/src/lte/wscript b/src/lte/wscript index b1e8aba31..3608ff50b 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -47,7 +47,7 @@ def build(bld): 'test/lte-propagation-loss-model-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'lte' headers.source = [ 'model/lte-spectrum-phy.h', diff --git a/src/mesh/wscript b/src/mesh/wscript index 6ce45246c..79011c8e5 100644 --- a/src/mesh/wscript +++ b/src/mesh/wscript @@ -53,7 +53,7 @@ def build(bld): 'test/flame/regression.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'mesh' headers.source = [ 'model/mesh-information-element.h', diff --git a/src/mobility/wscript b/src/mobility/wscript index da6f3fbd1..3225b2028 100644 --- a/src/mobility/wscript +++ b/src/mobility/wscript @@ -30,7 +30,7 @@ def build(bld): 'test/waypoint-mobility-model-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'mobility' headers.source = [ 'model/box.h', diff --git a/src/mpi/wscript b/src/mpi/wscript index c70fa1375..173470d00 100644 --- a/src/mpi/wscript +++ b/src/mpi/wscript @@ -29,7 +29,7 @@ def configure(conf): def build(bld): - env = bld.env_of_name('default') + env = bld.env sim = bld.create_ns3_module('mpi', ['core', 'network']) sim.source = [ 'model/distributed-simulator-impl.cc', @@ -37,7 +37,7 @@ def build(bld): 'model/mpi-receiver.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'mpi' headers.source = [ 'model/distributed-simulator-impl.h', diff --git a/src/netanim/wscript b/src/netanim/wscript index 22f86dcd4..d630ed5b1 100644 --- a/src/netanim/wscript +++ b/src/netanim/wscript @@ -8,7 +8,7 @@ def build (bld) : 'helper/animation-interface-helper.cc', ] - headers = bld.new_task_gen ('ns3header') + headers = bld.new_task_gen (features=['ns3header']) headers.module = 'netanim' headers.source = [ 'model/animation-interface.h', diff --git a/src/network/wscript b/src/network/wscript index 5d06dff81..d36cfe41e 100644 --- a/src/network/wscript +++ b/src/network/wscript @@ -67,7 +67,7 @@ def build(bld): 'test/sequence-number-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'network' headers.source = [ 'model/address.h', diff --git a/src/nix-vector-routing/wscript b/src/nix-vector-routing/wscript index e0332a872..660631a2f 100644 --- a/src/nix-vector-routing/wscript +++ b/src/nix-vector-routing/wscript @@ -8,7 +8,7 @@ def build(bld): 'helper/ipv4-nix-vector-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'nix-vector-routing' headers.source = [ 'model/ipv4-nix-vector-routing.h', diff --git a/src/olsr/wscript b/src/olsr/wscript index bbe0427c2..ed2c4811e 100644 --- a/src/olsr/wscript +++ b/src/olsr/wscript @@ -20,7 +20,7 @@ def build(bld): 'test/tc-regression-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'olsr' headers.source = [ 'model/olsr-routing-protocol.h', diff --git a/src/openflow/wscript b/src/openflow/wscript index 1c3c3939c..99b8f959f 100644 --- a/src/openflow/wscript +++ b/src/openflow/wscript @@ -7,7 +7,7 @@ def set_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') + opt.tool_options('boost', tooldir=["waf-tools"]) def configure(conf): conf.check_tool('boost') @@ -146,7 +146,7 @@ def build(bld): obj.uselib = 'OPENFLOW DL XML2' obj_test.uselib = 'OPENFLOW DL XML2' - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'openflow' headers.source = [ ] diff --git a/src/point-to-point-layout/wscript b/src/point-to-point-layout/wscript index 4ab18b42d..d29d04ec6 100644 --- a/src/point-to-point-layout/wscript +++ b/src/point-to-point-layout/wscript @@ -9,7 +9,7 @@ def build(bld): 'model/point-to-point-star.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'point-to-point-layout' headers.source = [ 'model/point-to-point-dumbbell.h', diff --git a/src/point-to-point/wscript b/src/point-to-point/wscript index ce8faa742..f3b4ba8e6 100644 --- a/src/point-to-point/wscript +++ b/src/point-to-point/wscript @@ -16,7 +16,7 @@ def build(bld): 'test/point-to-point-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'point-to-point' headers.source = [ 'model/point-to-point-net-device.h', diff --git a/src/propagation/wscript b/src/propagation/wscript index df7d068e4..094a7de82 100644 --- a/src/propagation/wscript +++ b/src/propagation/wscript @@ -15,7 +15,7 @@ def build(bld): 'test/propagation-loss-model-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'propagation' headers.source = [ 'model/propagation-delay-model.h', diff --git a/src/spectrum/wscript b/src/spectrum/wscript index 49e205fb7..0ba4d8f4d 100644 --- a/src/spectrum/wscript +++ b/src/spectrum/wscript @@ -39,7 +39,7 @@ def build(bld): 'test/spectrum-ideal-phy-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'spectrum' headers.source = [ 'model/spectrum-model.h', diff --git a/src/stats/wscript b/src/stats/wscript index a4d4c5085..13d632dba 100644 --- a/src/stats/wscript +++ b/src/stats/wscript @@ -1,7 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def configure(conf): - conf.env['SQLITE_STATS'] = conf.check(lib='sqlite3', define_name='SQLITE3', uselib='SQLITE3') + conf.env['SQLITE_STATS'] = conf.check_nonfatal(lib='sqlite3', define_name='SQLITE3', uselib='SQLITE3') conf.report_optional_feature("SqliteDataOutput", "SQlite stats data output", conf.env['SQLITE_STATS'], "library 'sqlite3' not found") @@ -23,7 +23,7 @@ def build(bld): 'test/basic-data-calculators-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'stats' headers.source = [ 'model/data-calculator.h', diff --git a/src/tap-bridge/examples/wscript b/src/tap-bridge/examples/wscript index fa63e92c6..aeca10764 100644 --- a/src/tap-bridge/examples/wscript +++ b/src/tap-bridge/examples/wscript @@ -1,7 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - env = bld.env_of_name('default') + env = bld.env if env['ENABLE_TAP']: obj = bld.create_ns3_program('tap-csma', ['csma', 'tap-bridge', 'internet', 'wifi']) obj.source = 'tap-csma.cc' diff --git a/src/tap-bridge/wscript b/src/tap-bridge/wscript index 4ee038ab5..913843232 100644 --- a/src/tap-bridge/wscript +++ b/src/tap-bridge/wscript @@ -15,7 +15,7 @@ def configure(conf): "needs threading support which is not available") if conf.env['ENABLE_TAP']: - blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant())) + blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) tapcreatordir = os.path.abspath(os.path.join(blddir, "src/tap-bridge")) conf.env.append_value('NS3_EXECUTABLE_PATH', tapcreatordir) else: @@ -34,7 +34,7 @@ def build(bld): 'model/tap-encode-decode.cc', 'helper/tap-bridge-helper.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'tap-bridge' headers.source = [ 'model/tap-bridge.h', diff --git a/src/template/wscript b/src/template/wscript index 00c30d4f5..787bdb7dd 100644 --- a/src/template/wscript +++ b/src/template/wscript @@ -27,7 +27,7 @@ def build(bld): ] # Make headers be installed for this module. - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'template' # Set the C++ header files for this module. diff --git a/src/test/ns3tcp/wscript b/src/test/ns3tcp/wscript index 514353eab..5fe1f7488 100644 --- a/src/test/ns3tcp/wscript +++ b/src/test/ns3tcp/wscript @@ -16,7 +16,7 @@ def build(bld): return ns3tcp = bld.create_ns3_module('ns3tcp', ['internet', 'point-to-point', 'csma', 'applications']) - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'ns3tcp' headers.source = [ 'ns3tcp.h', diff --git a/src/test/ns3wifi/wscript b/src/test/ns3wifi/wscript index 13feb446c..68d431725 100644 --- a/src/test/ns3wifi/wscript +++ b/src/test/ns3wifi/wscript @@ -16,7 +16,7 @@ def build(bld): return ns3wifi = bld.create_ns3_module('ns3wifi', ['internet', 'mobility', 'propagation', 'wifi', 'applications']) - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'ns3wifi' headers.source = [ 'ns3wifi.h', diff --git a/src/test/wscript b/src/test/wscript index 56e15765d..ab4d0420f 100644 --- a/src/test/wscript +++ b/src/test/wscript @@ -20,7 +20,7 @@ def build(bld): return test = bld.create_ns3_module('test', ['internet', 'mobility', 'applications', 'csma', 'bridge', 'config-store', 'tools', 'point-to-point', 'csma-layout', 'flow-monitor']) - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'test' test_test = bld.create_ns3_module_test_library('test') diff --git a/src/tools/wscript b/src/tools/wscript index 31f096317..b036ee29e 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -14,7 +14,7 @@ def build(bld): 'test/event-garbage-collector-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'tools' headers.source = [ 'model/average.h', diff --git a/src/topology-read/wscript b/src/topology-read/wscript index d50441e1b..8e69e8651 100644 --- a/src/topology-read/wscript +++ b/src/topology-read/wscript @@ -15,7 +15,7 @@ def build(bld): 'test/rocketfuel-topology-reader-test-suite.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'topology-read' headers.source = [ 'model/topology-reader.h', diff --git a/src/uan/wscript b/src/uan/wscript index 2030ee156..2ae8f189c 100644 --- a/src/uan/wscript +++ b/src/uan/wscript @@ -32,7 +32,7 @@ def build(bld): 'test/uan-test.cc', 'test/uan-energy-model-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'uan' headers.source = [ 'model/uan-channel.h', diff --git a/src/virtual-net-device/wscript b/src/virtual-net-device/wscript index 2b462afc2..590e3a845 100644 --- a/src/virtual-net-device/wscript +++ b/src/virtual-net-device/wscript @@ -6,7 +6,7 @@ def build(bld): module.source = [ 'model/virtual-net-device.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'virtual-net-device' headers.source = [ 'model/virtual-net-device.h', diff --git a/src/visualizer/wscript b/src/visualizer/wscript index 9dea2216e..dbfbd5e62 100644 --- a/src/visualizer/wscript +++ b/src/visualizer/wscript @@ -13,7 +13,7 @@ def build(bld): if 'visualizer' in bld.env['MODULES_NOT_BUILT']: return - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'visualizer' headers.source = [ ] diff --git a/src/wifi/wscript b/src/wifi/wscript index 0784c8ee2..39a2f2c3a 100644 --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -75,7 +75,7 @@ def build(bld): 'test/wifi-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'wifi' headers.source = [ 'model/wifi-information-element.h', diff --git a/src/wimax/wscript b/src/wimax/wscript index 5f96e2a35..9a586fd05 100644 --- a/src/wimax/wscript +++ b/src/wimax/wscript @@ -63,7 +63,7 @@ def build(bld): 'test/wimax-fragmentation-test.cc', ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen(features=['ns3header']) headers.module = 'wimax' headers.source = [ 'model/wimax-channel.h', diff --git a/src/wscript b/src/wscript index 8a81ba89e..e53a6cce1 100644 --- a/src/wscript +++ b/src/wscript @@ -11,10 +11,10 @@ import Task import Options import Build import Utils -import Constants +#import Constants -import ccroot -ccroot.USE_TOP_LEVEL = True +#import ccroot +#ccroot.USE_TOP_LEVEL = True import wutils @@ -94,7 +94,7 @@ def configure(conf): conf.sub_config('stats') conf.sub_config('visualizer') - blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant())) + blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) conf.env.append_value('NS3_MODULE_PATH', blddir) if Options.options.enable_rpath: conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),)) @@ -103,169 +103,146 @@ def configure(conf): conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] -class ns3module_taskgen(TaskGen.task_gen): - def __init__(self, *args, **kwargs): - super(ns3module_taskgen, self).__init__(*args, **kwargs) - self.libs = [] +# class ns3module_taskgen(TaskGen.task_gen): +# def __init__(self, *args, **kwargs): +# super(ns3module_taskgen, self).__init__(*args, **kwargs) +# self.libs = [] - def apply(self): - static_enabled = False - shared_enabled = True - bld = self.bld - if bld.env['ENABLE_STATIC_NS3']: - static_enabled = True - shared_enabled = False - if bld.env['ENABLE_SHARED_AND_STATIC_NS3']: - static_enabled = True - shared_enabled = True +# def apply(self): +# print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +# static_enabled = False +# shared_enabled = True +# bld = self.bld +# if bld.env['ENABLE_STATIC_NS3']: +# static_enabled = True +# shared_enabled = False +# if bld.env['ENABLE_SHARED_AND_STATIC_NS3']: +# static_enabled = True +# shared_enabled = True - assert self.name.startswith("ns3-") - name = self.name.split("ns3-")[1] +# assert self.name.startswith("ns3-") +# name = self.name.split("ns3-")[1] - if static_enabled: - static = self._create_ns3_module(self.bld, name, self.dependencies, True) - self.libs.append(static) - else: - static = None +# if static_enabled: +# static = self._create_ns3_module(self.bld, name, self.dependencies, True) +# self.libs.append(static) +# else: +# static = None - if shared_enabled: - shared = self._create_ns3_module(self.bld, name, self.dependencies, False) - self.libs.append(shared) - else: - shared = None +# if shared_enabled: +# shared = self._create_ns3_module(self.bld, name, self.dependencies, False) +# self.libs.append(shared) +# else: +# shared = None - if static is not None and shared is None: - static.name = self.name + "--lib" - static.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] +# if static is not None and shared is None: +# static.name = self.name + "--lib" +# static.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] - elif shared is not None and static is None: - shared.name = self.name + "--lib" - shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] - else: - shared.name = self.name + "--lib" - shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] - static.name = self.name + "--static" - static.uselib_local = ['ns3-%s--static' % (dep,) for dep in self.dependencies] +# elif shared is not None and static is None: +# shared.name = self.name + "--lib" +# shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] +# else: +# shared.name = self.name + "--lib" +# shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] +# static.name = self.name + "--static" +# static.uselib_local = ['ns3-%s--static' % (dep,) for dep in self.dependencies] - if not self.test: - pcfile = bld.new_task_gen('ns3pcfile') - pcfile.module = self +# if not self.test: +# pcfile = bld.new_task_gen('ns3pcfile') +# pcfile.module = self - def _create_ns3_module(self, bld, name, dependencies, static): +# def _create_ns3_module(self, bld, name, dependencies, static): - # FIXME: env modifications are overwritten by parent caller +# # FIXME: env modifications are overwritten by parent caller - # Create a separate library for this module. - if static: - module = bld.new_task_gen('cxx', 'cstaticlib') - else: - module = bld.new_task_gen('cxx', 'cshlib') - - module.source = self.source - module.env = self.env.copy() - features = list(self.features) - features.remove("ns3module") - module.features.extend(features) - module.path = self.path - module.uselib = self.uselib - module.target = 'ns3-' + name - if hasattr(self, 'includes'): - module.includes = self.includes - if hasattr(self, 'defines'): - module.defines = self.defines - else: - module.defines = [] - if hasattr(self, 'add_objects'): - module.add_objects = self.add_objects - else: - module.add_objects = [] - if hasattr(self, "is_ns3_module"): - module.is_ns3_module = self.is_ns3_module - if hasattr(self, 'add_objects'): - module.add_objects = self.add_objects - - linkflags = [] - cxxflags = [] - ccflags = [] - if not static: - cxxflags = module.env['shlib_CXXFLAGS'] - ccflags = module.env['shlib_CXXFLAGS'] - # Turn on the link flags for shared libraries if we have the - # proper compiler and platform. - if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']: - # Get the module library name without any relative paths - # at its beginning because all of the libraries will end - # up in the same directory. - module_library_name = os.path.basename(ccroot.get_target_name(module)) - linkflags = '-Wl,--soname=%s' % module_library_name - elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \ - os.uname()[4] == 'x86_64' and \ - sys.platform != 'darwin' and \ - module.env['ENABLE_PYTHON_BINDINGS']: - # enable that flag for static builds only on x86-64 platforms - # when gcc is present and only when we want python bindings - # (it's more efficient to not use this option if we can avoid it) - cxxflags = ['-mcmodel=large'] - ccflags = ['-mcmodel=large'] - cxxdefines = ["NS3_MODULE_COMPILATION"] - ccdefines = ["NS3_MODULE_COMPILATION"] - - module.env.append_value('CXXFLAGS', cxxflags) - module.env.append_value('CCFLAGS', ccflags) - module.env.append_value('LINKFLAGS', linkflags) - module.env.append_value('CXXDEFINES', cxxdefines) - module.env.append_value('CCDEFINES', ccdefines) - - if len(module.source) > 0 and hasattr(self, 'ns3_dir_location'): - uselib_cpppath = [] - for lib in module.uselib.split(): - if 'CPPPATH_%s' % lib in module.env: - uselib_cpppath.extend(module.env['CPPPATH_%s' % lib]) - objects = [] - for src in module.source[0:-1]: - full_src = os.path.join(self.ns3_dir_location, src) - path = os.path.dirname(full_src) - target = '%s_object' % src - # XXX: calculate the features correctly here. - obj = bld (source=[full_src], target=target, features='cxx cc', - defines=['NS_TEST_SOURCEDIR="%s"' % path], - includes=' '.join(uselib_cpppath), - env = module.env) - objects.append(target) - last = module.source[-1] - full_src = os.path.join(self.ns3_dir_location, last) - path = os.path.dirname(full_src) - module.defines.append('NS_TEST_SOURCEDIR="%s"' % path) - module.source = [last] - module.add_objects.extend(objects) - - - module.is_static = static - module.vnum = wutils.VNUM - # Add the proper path to the module's name. - module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(self.path), name) - # Set the libraries this module depends on. - module.module_deps = list(dependencies) - - module.install_path = "${LIBDIR}" - - return module def create_ns3_module(bld, name, dependencies=(), test=False): - module = bld.new_task_gen('ns3module') + static = bool(bld.env.ENABLE_STATIC_NS3) + # Create a separate library for this module. + if static: + module = bld.new_task_gen(features=['cxx', 'cxxstlib']) + else: + module = bld.new_task_gen(features=['cxx', 'cxxshlib']) + linkflags = [] + cxxflags = [] + ccflags = [] + if not static: + cxxflags = module.env['shlib_CXXFLAGS'] + ccflags = module.env['shlib_CXXFLAGS'] + # Turn on the link flags for shared libraries if we have the + # proper compiler and platform. + if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']: + # Get the module library name without any relative paths + # at its beginning because all of the libraries will end + # up in the same directory. + if 0: # TODO FIXME + module_library_name = os.path.basename(ccroot.get_target_name(module)) + linkflags = '-Wl,--soname=%s' % module_library_name + elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \ + os.uname()[4] == 'x86_64' and \ + sys.platform != 'darwin' and \ + module.env['ENABLE_PYTHON_BINDINGS']: + # enable that flag for static builds only on x86-64 platforms + # when gcc is present and only when we want python bindings + # (it's more efficient to not use this option if we can avoid it) + cxxflags = ['-mcmodel=large'] + ccflags = ['-mcmodel=large'] + cxxdefines = ["NS3_MODULE_COMPILATION"] + ccdefines = ["NS3_MODULE_COMPILATION"] + + module.env.append_value('CXXFLAGS', cxxflags) + module.env.append_value('CCFLAGS', ccflags) + module.env.append_value('LINKFLAGS', linkflags) + module.env.append_value('CXXDEFINES', cxxdefines) + module.env.append_value('CCDEFINES', ccdefines) + + module.is_static = static + module.vnum = wutils.VNUM + # Add the proper path to the module's name. + module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(module.path), name) + # Set the libraries this module depends on. + module.module_deps = list(dependencies) + + module.install_path = "${LIBDIR}" + module.bld = bld module.name = "ns3-" + name module.dependencies = dependencies # Initially create an empty value for this because the pcfile # writing task assumes every module has a uselib attribute. module.uselib = '' - module.uselib_local = ['ns3-' + dep for dep in dependencies] - module.module_deps = list(dependencies) + 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.env.append_value("INCLUDES", '#') + + if len(module.source) > 0 and hasattr(self, 'ns3_dir_location'): + uselib_cpppath = [] + for lib in module.uselib.split(): + if 'CPPPATH_%s' % lib in module.env: + uselib_cpppath.extend(module.env['CPPPATH_%s' % lib]) + objects = [] + for src in module.source[0:-1]: + full_src = os.path.join(self.ns3_dir_location, src) + path = os.path.dirname(full_src) + target = '%s_object' % src + # XXX: calculate the features correctly here. + obj = bld (source=[full_src], target=target, features='cxx cc', + defines=['NS_TEST_SOURCEDIR="%s"' % path], + includes=' '.join(uselib_cpppath), + env = module.env) + objects.append(target) + last = module.source[-1] + full_src = os.path.join(self.ns3_dir_location, last) + path = os.path.dirname(full_src) + module.defines.append('NS_TEST_SOURCEDIR="%s"' % path) + module.source = [last] + module.add_objects.extend(objects) + return module @@ -367,29 +344,29 @@ def ns3_python_bindings(bld): if was_enabled: features.append(name) - bindgen = bld.new_task_gen('command', source=source, target=target, command=argv) + bindgen = bld.new_task_gen(features=['command'], source=source, target=target, command=argv) bindgen.env['FEATURES'] = ','.join(features) bindgen.dep_vars = ['FEATURES', "GCC_RTTI_ABI_COMPLETE"] bindgen.before = 'cxx' - bindgen.after = 'gen_ns3_module_header_task' + bindgen.after = 'gen_ns3_module_header' bindgen.name = "pybindgen(ns3 module %s)" % module # generate the extension module - pymod = bld.new_task_gen(features='cxx cshlib pyext') + pymod = bld.new_task_gen(features='cxx cxxshlib pyext') pymod.source = ['bindings/ns3module.cc'] pymod.target = '%s/%s' % (module_target_dir, extension_name) pymod.name = 'ns3module_%s' % module - pymod.uselib_local = ["%s--lib" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117 + pymod.use = ["%s" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117 if pymod.env['ENABLE_STATIC_NS3']: if sys.platform == 'darwin': pymod.env.append_value('LINKFLAGS', '-Wl,-all_load') - for mod in pymod.uselib_local: - mod = mod.split("--lib")[0] + for mod in pymod.usel: + #mod = mod.split("--lib")[0] pymod.env.append_value('LINKFLAGS', '-l' + mod) else: pymod.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic') - for mod in pymod.uselib_local: - mod = mod.split("--lib")[0] + for mod in pymod.use: + #mod = mod.split("--lib")[0] pymod.env.append_value('LINKFLAGS', '-l' + mod) pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') defines = list(pymod.env['CXXDEFINES']) @@ -400,7 +377,7 @@ def ns3_python_bindings(bld): except ValueError: pass pymod.env['CXXDEFINES'] = defines - pymod.includes = 'bindings' + pymod.includes = '# bindings' pymod.install_path = '${PYTHONDIR}/ns' return pymod @@ -427,7 +404,7 @@ def build(bld): bld.add_subdirs(list(all_modules)) for module in all_modules: - modheader = bld.new_task_gen('ns3moduleheader') + modheader = bld.new_task_gen(features=['ns3moduleheader']) modheader.module = module.split('/')[-1] class ns3pcfile_task(Task.Task): @@ -480,7 +457,7 @@ class ns3pcfile_task(Task.Task): includes = self.env['CPPPATH_%s' % dep] return [self.env['CPPPATH_ST'] % include for include in includes] - def _generate_pcfile(self, name, use, uselib_local, env, outfilename): + def _generate_pcfile(self, name, uselib, use, env, outfilename): outfile = open(outfilename, 'w') prefix = env.PREFIX includedir = env.INCLUDEDIR @@ -488,7 +465,7 @@ class ns3pcfile_task(Task.Task): libs = self._self_libs(self.env, name, '${libdir}') for dep in use: libs = libs + self._lib(self.env, dep) - for dep in uselib_local: + for dep in uselib: libs = libs + [self.env['LIB_ST'] % dep] cflags = [self.env['CPPPATH_ST'] % '${includedir}'] for dep in use: @@ -511,7 +488,7 @@ Cflags: %s def run(self): output_filename = self.outputs[0].bldpath(self.env) self._generate_pcfile(self.module.name, self.module.uselib, - self.module.uselib_local, + self.module.use, self.env, output_filename) class ns3pcfile_taskgen(TaskGen.task_gen): @@ -527,41 +504,49 @@ class ns3pcfile_taskgen(TaskGen.task_gen): task.module = self.module -class ns3header_taskgen(TaskGen.task_gen): - """A set of NS-3 header files""" - COLOR = 'BLUE' - def __init__(self, *args, **kwargs): - super(ns3header_taskgen, self).__init__(*args, **kwargs) - self.install_path = None - self.sub_dir = None # if not None, header files will be published as ns3/sub_dir/file.h - self.module = None # module name - self.mode = 'install' +# @TaskGen.extension('.h') +# class ns3header_taskgen(TaskGen.task_gen): +# """A set of NS-3 header files""" +# COLOR = 'BLUE' +# def __init__(self, *args, **kwargs): +# super(ns3header_taskgen, self).__init__(*args, **kwargs) +# self.install_path = None +# self.sub_dir = None # if not None, header files will be published as ns3/sub_dir/file.h +# self.module = None # module name +# self.mode = 'install' +# self.features.append(features=['ns3header']) +# print "YYYYYYYYYYYYYYYYYYYYYYYYYYY", self - def apply(self): - for filename in set(self.to_list(self.source)): - src_node = self.path.find_resource(filename) - if self.module is None: - raise Utils.WafError("'module' missing on ns3headers object %s" % self) - ns3_dir_node = self.bld.path.find_dir("ns3") - if self.sub_dir is not None: - ns3_dir_node = ns3_dir_node.find_dir(self.sub_dir) - for filename in set(self.to_list(self.source)): - src_node = self.path.find_resource(filename) - if src_node is None: - raise Utils.WafError("source ns3 header file %s not found" % (filename,)) - dst_node = ns3_dir_node.find_or_declare(os.path.basename(filename)) - assert dst_node is not None - task = self.create_task('ns3header', env=self.env) - task.mode = self.mode - if self.mode == 'install': - self.bld.install_files('${PREFIX}/include/ns3', [src_node]) - task.set_inputs([src_node]) - task.set_outputs([dst_node]) - else: - task.header_to_remove = dst_node + +@TaskGen.feature('ns3header') +@TaskGen.after_method('process_rule') +def apply_ns3header(self): + #for filename in set(self.to_list(self.source)): + # src_node = self.path.find_resource(filename) + if self.module is None: + raise Utils.WafError("'module' missing on ns3headers object %s" % self) + ns3_dir_node = self.bld.path.find_dir("ns3") + #if self.sub_dir is not None: + # ns3_dir_node = ns3_dir_node.find_dir(self.sub_dir) + for filename in set(self.to_list(self.source)): + src_node = self.path.find_resource(filename) + if src_node is None: + raise Utils.WafError("source ns3 header file %s not found" % (filename,)) + dst_node = ns3_dir_node.find_or_declare(src_node.name) + assert dst_node is not None + task = self.create_task('ns3header') + task.mode = getattr(self, 'mode', 'install') + if task.mode == 'install': + self.bld.install_files('${PREFIX}/include/ns3', [src_node]) + task.set_inputs([src_node]) + task.set_outputs([dst_node]) + else: + task.header_to_remove = dst_node + self.headers = set(self.to_list(self.source)) + self.source = '' # tell WAF not to process these files further class ns3header_task(Task.Task): - before = 'cc cxx gen_ns3_module_header_task' + before = 'cc cxx gen_ns3_module_header' color = 'BLUE' def __str__(self): @@ -578,17 +563,17 @@ class ns3header_task(Task.Task): def runnable_status(self): if self.mode == 'remove': if os.path.exists(self.header_to_remove.bldpath(self.env)): - return Constants.RUN_ME + return Task.RUN_ME else: - return Constants.SKIP_ME + return Task.SKIP_ME else: return super(ns3header_task, self).runnable_status() def run(self): if self.mode == 'install': assert len(self.inputs) == len(self.outputs) - inputs = [node.srcpath(self.env) for node in self.inputs] - outputs = [node.bldpath(self.env) for node in self.outputs] + inputs = [node.abspath() for node in self.inputs] + outputs = [node.abspath() for node in self.outputs] for src, dst in zip(inputs, outputs): try: os.chmod(dst, 0600) @@ -613,15 +598,15 @@ class ns3header_task(Task.Task): class gen_ns3_module_header_task(Task.Task): before = 'cc cxx' - after = 'ns3header_task' + after = 'ns3header' color = 'BLUE' def runnable_status(self): if self.mode == 'remove': if os.path.exists(self.header_to_remove.bldpath(self.env)): - return Constants.RUN_ME + return Task.RUN_ME else: - return Constants.SKIP_ME + return Task.SKIP_ME else: return super(gen_ns3_module_header_task, self).runnable_status() @@ -647,10 +632,9 @@ class gen_ns3_module_header_task(Task.Task): if ex.errno != 2: raise return 0 - assert len(self.outputs) == 1 - out_file_name = self.outputs[0].bldpath(self.env) - header_files = [os.path.basename(node.abspath(self.env)) for node in self.inputs] + out_file_name = self.outputs[0].get_bld().abspath()#self.env) + header_files = [os.path.basename(node.abspath()) for node in self.inputs] outfile = file(out_file_name, "w") header_files.sort() @@ -678,7 +662,7 @@ class gen_ns3_module_header_task(Task.Task): return 0 def sig_explicit_deps(self): - self.m.update('\n'.join([node.abspath(self.env) for node in self.inputs])) + self.m.update('\n'.join([node.abspath() for node in self.inputs])) return self.m.digest() def unique_id(self): @@ -692,50 +676,46 @@ class gen_ns3_module_header_task(Task.Task): return self.uid -class ns3moduleheader_taskgen(TaskGen.task_gen): - """ - Generates a 'ns3/foo-module.h' header file that includes all - public ns3 headers of a certain module. - """ - COLOR = 'BLUE' - def __init__(self, *args, **kwargs): - super(ns3moduleheader_taskgen, self).__init__(*args, **kwargs) - self.mode = 'install' +# Generates a 'ns3/foo-module.h' header file that includes all public +# ns3 headers of a certain module. +@TaskGen.feature('ns3moduleheader') +@TaskGen.after_method('process_rule') +def apply_ns3moduleheader(self): + ## get all of the ns3 headers + ns3_dir_node = self.bld.path.find_dir("ns3") + all_headers_inputs = [] + found_the_module = False + for ns3headers in self.bld.all_task_gen: + if 'ns3header' in getattr(ns3headers, "features", []): + if ns3headers.module != self.module: + continue + found_the_module = True + for source in ns3headers.headers: + source = os.path.basename(source) + node = ns3_dir_node.find_or_declare(os.path.basename(source)) + if node is None: + fatal("missing header file %s" % (source,)) + all_headers_inputs.append(node) + if not found_the_module: + raise Utils.WscriptError("error finding headers for module %s" % self.module) + if not all_headers_inputs: + return - def apply(self): - ## get all of the ns3 headers - ns3_dir_node = self.bld.path.find_dir("ns3") - all_headers_inputs = [] - found_the_module = False - for ns3headers in self.bld.all_task_gen: - if isinstance(ns3headers, ns3header_taskgen): - if ns3headers.module != self.module: - continue - found_the_module = True - for source in set(ns3headers.to_list(ns3headers.source)): - source = os.path.basename(source) - node = ns3_dir_node.find_or_declare(os.path.basename(source)) - if node is None: - fatal("missing header file %s" % (source,)) - all_headers_inputs.append(node) - if not found_the_module: - raise Utils.WscriptError("error finding headers for module %s" % self.module) - if not all_headers_inputs: - return - all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)] - task = self.create_task('gen_ns3_module_header', env=self.env) - task.module = self.module - task.mode = self.mode - if self.mode == 'install': - self.bld.install_files('${PREFIX}/include/ns3', - ns3_dir_node.find_or_declare("%s-module.h" % self.module)) - task.set_inputs(all_headers_inputs) - task.set_outputs(all_headers_outputs) - module_obj = self.bld.name_to_obj("ns3-" + self.module, self.env) - assert module_obj is not None, self.module - task.module_deps = module_obj.module_deps - else: - task.header_to_remove = all_headers_outputs[0] + try: + module_obj = self.bld.get_taskgen("ns3-" + self.module) + except KeyError: # maybe the module was disabled, and therefore removed + return - def install(self): - pass + all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)] + task = self.create_task('gen_ns3_module_header') + task.module = self.module + task.mode = getattr(self, "mode", "install") + if task.mode == 'install': + assert module_obj is not None, self.module + self.bld.install_files('${PREFIX}/include/ns3', + ns3_dir_node.find_or_declare("%s-module.h" % self.module)) + task.set_inputs(all_headers_inputs) + task.set_outputs(all_headers_outputs) + task.module_deps = module_obj.module_deps + else: + task.header_to_remove = all_headers_outputs[0] diff --git a/utils/wscript b/utils/wscript index fb49a7712..a1addf860 100644 --- a/utils/wscript +++ b/utils/wscript @@ -10,7 +10,7 @@ def build(bld): # Set the libraries the testrunner depends on equal to the list of # enabled modules plus the list of enabled module test libraries. - test_runner.uselib_local = [mod+"--lib" for mod in (env['NS3_ENABLED_MODULES'] + env['NS3_ENABLED_MODULE_TEST_LIBRARIES'])] + test_runner.use = [mod for mod in (env['NS3_ENABLED_MODULES'] + env['NS3_ENABLED_MODULE_TEST_LIBRARIES'])] obj = bld.create_ns3_program('bench-simulator', ['core']) obj.source = 'bench-simulator.cc' @@ -28,5 +28,5 @@ def build(bld): obj = bld.create_ns3_program('print-introspected-doxygen', ['network']) obj.source = 'print-introspected-doxygen.cc' - obj.uselib_local = [mod+"--lib" for mod in env['NS3_ENABLED_MODULES']] + obj.use = [mod for mod in env['NS3_ENABLED_MODULES']] diff --git a/waf b/waf index 22d00ed292a2816a8f7d80765032313db6763106..f7c97d6a833f623fc7eec6580b3a1478aee49ff1 100755 GIT binary patch delta 83165 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⁢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

^I^Rdx}GcwvI1h0SA-cOroOsvtQgGMxbzhjVnqi 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ξ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, 2008 +# modified by Bjoern Michaelsen, 2008 +# modified by Luca Fossati, 2008 +# rewritten for waf 1.5.1, Thomas Nagy, 2008 +# rewritten for waf 1.6.2, Sylvain Rouquette, 2011 + +''' +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: + +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 build(bld): + bld(source='main.cpp', target='app', use='BOOST') +''' + +import sys +import re +from waflib import Utils, Logs +from waflib.Configure import conf + +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 +#include +int main() { std::cout << BOOST_LIB_VERSION << std::endl; } +''' + +# toolsets from {boost_dir}/tools/build/v2/tools/common.jam +PLATFORM = Utils.unversioned_sys_platform() +detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il' +detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang' +detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc' +BOOST_TOOLSETS = { + 'borland': 'bcb', + 'clang': detect_clang, + 'como': 'como', + 'cw': 'cw', + 'darwin': 'xgcc', + 'edg': 'edg', + 'g++': detect_mingw, + 'gcc': detect_mingw, + 'icpc': detect_intel, + 'intel': detect_intel, + 'kcc': 'kcc', + 'kylix': 'bck', + 'mipspro': 'mp', + 'mingw': 'mgw', + 'msvc': 'vc', + 'qcc': 'qcc', + 'sun': 'sw', + 'sunc++': 'sw', + 'tru64cxx': 'tru', + 'vacpp': 'xlc' +} + + +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''') + 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''') + opt.add_option('--boost-static', action='store_true', + default=False, dest='boost_static', + help='link static libraries') + 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-toolset', type='string', + default='', dest='boost_toolset', + help='force a toolset e.g. msvc, vc90, \ + gcc, mingw, mgw45 (default: auto)') + py_version = '%d%d' % (sys.version_info[0], sys.version_info[1]) + opt.add_option('--boost-python', type='string', + default=py_version, dest='boost_python', + help='select the lib python with this version \ + (default: %s)' % py_version) + + +@conf +def __boost_get_version_file(self, dir): + try: + return self.root.find_dir(dir).find_node(BOOST_VERSION_FILE) + except: + return None + + +@conf +def boost_get_version(self, dir): + """silently retrieve the boost version number""" + re_but = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"$', re.M) + 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) + return val + + +@conf +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 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') + + +@conf +def boost_get_toolset(self, cc): + toolset = cc + if not cc: + build_platform = Utils.unversioned_sys_platform() + if build_platform in BOOST_TOOLSETS: + cc = build_platform + else: + cc = self.env.CXX_NAME + if cc in BOOST_TOOLSETS: + toolset = BOOST_TOOLSETS[cc] + return isinstance(toolset, str) and toolset or toolset(self.env) + + +@conf +def __boost_get_libs_path(self, *k, **kw): + ''' return the lib path and all the files in it ''' + if 'files' in kw: + return self.root.find_dir('.'), Utils.to_list(kw['files']) + libs = k and k[0] or kw.get('libs', None) + if libs: + path = self.root.find_dir(libs) + files = path.ant_glob('*boost_*') + if not libs or not files: + for dir in BOOST_LIBS: + try: + path = self.root.find_dir(dir) + files = path.ant_glob('*boost_*') + if files: + break + path = self.root.find_dir(dir + '64') + files = path.ant_glob('*boost_*') + if files: + break + except: + path = None + if not path: + 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 + + +@conf +def boost_get_libs(self, *k, **kw): + ''' + return the lib path and the required libs + 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 '' + toolset = '(-%s[0-9]{0,3})+' % self.boost_get_toolset(kw.get('toolset', '')) + version = '(-%s)+' % self.env.BOOST_VERSION + + def find_lib(re_lib, files): + for file in files: + if re_lib.search(file.name): + return file + return None + + def format_lib_name(name): + if name.startswith('lib'): + name = name[3:] + return name.split('.')[0] + + 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), + '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' % (lib, tags, py), + 'boost_%s%s' % (lib, tags)]: + 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)) + + return path.abspath(), libs + + +@conf +def check_boost(self, *k, **kw): + """ + initialize boost + + You can pass the same parameters as the command line (without "--boost-"), + but the command line has the priority. + """ + 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)} + for key, value in self.options.__dict__.items(): + if not key.startswith('boost_'): + continue + key = key[len('boost_'):] + params[key] = value and value or kw.get(key, '') + + var = kw.get('uselib_store', 'BOOST') + + self.start_msg('Checking boost includes') + self.env['INCLUDES_%s' % var] = self.boost_get_includes(**params) + self.env.BOOST_VERSION = self.boost_get_version(self.env['INCLUDES_%s' % var]) + self.end_msg(self.env.BOOST_VERSION) + if Logs.verbose: + Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) + + if not params['lib']: + return + self.start_msg('Checking boost libs') + suffix = params.get('static', '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') + if Logs.verbose: + Logs.pprint('CYAN', ' path : %s' % path) + Logs.pprint('CYAN', ' libs : %s' % libs) + diff --git a/waf-tools/command.py b/waf-tools/command.py index 5034acf3c..5953a6695 100644 --- a/waf-tools/command.py +++ b/waf-tools/command.py @@ -1,9 +1,10 @@ -from TaskGen import feature, taskgen, before, task_gen -import Node, Task, Utils, Build, pproc, Constants +import TaskGen# import feature, taskgen_method, before_method, task_gen +import Node, Task, Utils, Build +import subprocess import Options import shellcmd -shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy +#shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy from Logs import debug, error shellcmd.debug = debug @@ -18,7 +19,7 @@ arg_rx = re.compile(r"(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\} class command_task(Task.Task): color = "BLUE" def __init__(self, env, generator): - Task.Task.__init__(self, env, normal=1, generator=generator) + Task.Task.__init__(self, env=env, normal=1, generator=generator) def __str__(self): "string to display to the user" @@ -33,7 +34,6 @@ class command_task(Task.Task): pipeline = shellcmd.Pipeline() pipeline.parse(self.generator.command) cmd = pipeline.get_abbreviated_command() - return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str) def _subst_arg(self, arg, direction, namespace): @@ -50,21 +50,24 @@ class command_task(Task.Task): result = eval(var+code, namespace) if isinstance(result, Node.Node): if var == 'TGT': - return result.bldpath(self.env) + return result.get_bld().abspath() elif var == 'SRC': - return result.srcpath(self.env) + return result.srcpath() else: raise ValueError("Bad subst variable %r" % var) elif result is self.inputs: if len(self.inputs) == 1: - return result[0].srcpath(self.env) + return result[0].srcpath() else: raise ValueError("${SRC} requested but have multiple sources; which one?") elif result is self.outputs: if len(self.outputs) == 1: - return result[0].bldpath(self.env) + return result[0].get_bld().abspath() else: raise ValueError("${TGT} requested but have multiple targets; which one?") + elif isinstance(result, list): + assert len(result) == 1 + return result[0] else: return result return None @@ -95,11 +98,10 @@ class command_task(Task.Task): cmd.env_vars = env_vars elif isinstance(cmd, shellcmd.Chdir): cmd.dir = self._subst_arg(cmd.dir, None, namespace) - return pipeline.run(verbose=(Options.options.verbose > 0)) -@taskgen -@feature('command') +@TaskGen.taskgen_method +@TaskGen.feature('command') def init_command(self): Utils.def_attrs(self, # other variables that can be used in the command: ${VARIABLE} @@ -107,28 +109,25 @@ def init_command(self): -@taskgen -@feature('command') -@before('apply_core') +@TaskGen.feature('command') +@TaskGen.after_method('process_rule') def apply_command(self): - self.meths.remove('apply_core') + #self.meths.remove('apply_core') # create the task task = self.create_task('command') setattr(task, "dep_vars", getattr(self, "dep_vars", None)) # process the sources inputs = [] - for src in self.to_list(self.source): - node = self.path.find_resource(src) - if node is None: - raise Utils.WafError("source %s not found" % src) - inputs.append(node) + for node in self.source: + inputs.append(node) task.set_inputs(inputs) task.set_outputs([self.path.find_or_declare(tgt) for tgt in self.to_list(self.target)]) + self.source = '' #Task.file_deps = Task.extract_deps -class command_taskgen(task_gen): - def __init__(self, *k, **kw): - task_gen.__init__(self, *k, **kw) - self.features.append('command') +# class command_taskgen(task_gen): +# def __init__(self, *k, **kw): +# task_gen.__init__(self, *k, **kw) +# self.features.append('command') diff --git a/waf-tools/misc.py b/waf-tools/misc.py new file mode 100644 index 000000000..e8620fb14 --- /dev/null +++ b/waf-tools/misc.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2010 (ita) + +""" +This tool is totally deprecated + +Try using: + .pc.in files for .pc files + the feature intltool_in - see demos/intltool + make-like rules +""" + +import shutil, re, os +from waflib import TaskGen, Node, Task, Utils, Build, Errors +from waflib.TaskGen import feature, after_method, before_method +from waflib.Logs import debug + +def copy_attrs(orig, dest, names, only_if_set=False): + """ + copy class attributes from an object to another + """ + for a in Utils.to_list(names): + u = getattr(orig, a, ()) + if u or not only_if_set: + setattr(dest, a, u) + +def copy_func(tsk): + "Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)" + env = tsk.env + infile = tsk.inputs[0].abspath() + outfile = tsk.outputs[0].abspath() + try: + shutil.copy2(infile, outfile) + except (OSError, IOError): + return 1 + else: + if tsk.chmod: os.chmod(outfile, tsk.chmod) + return 0 + +def action_process_file_func(tsk): + "Ask the function attached to the task to process it" + if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!') + return tsk.fun(tsk) + +@feature('cmd') +def apply_cmd(self): + "call a command everytime" + if not self.fun: raise Errors.WafError('cmdobj needs a function!') + tsk = Task.TaskBase() + tsk.fun = self.fun + tsk.env = self.env + self.tasks.append(tsk) + tsk.install_path = self.install_path + +@feature('copy') +@before_method('process_source') +def apply_copy(self): + Utils.def_attrs(self, fun=copy_func) + self.default_install_path = 0 + + lst = self.to_list(self.source) + self.meths.remove('process_source') + + for filename in lst: + node = self.path.find_resource(filename) + if not node: raise Errors.WafError('cannot find input file %s for processing' % filename) + + target = self.target + if not target or len(lst)>1: target = node.name + + # TODO the file path may be incorrect + newnode = self.path.find_or_declare(target) + + tsk = self.create_task('copy', node, newnode) + tsk.fun = self.fun + tsk.chmod = getattr(self, 'chmod', Utils.O644) + + if not tsk.env: + tsk.debug() + raise Errors.WafError('task without an environment') + +def subst_func(tsk): + "Substitutes variables in a .in file" + + m4_re = re.compile('@(\w+)@', re.M) + + code = tsk.inputs[0].read() #Utils.readf(infile) + + # replace all % by %% to prevent errors by % signs in the input file while string formatting + code = code.replace('%', '%%') + + s = m4_re.sub(r'%(\1)s', code) + + env = tsk.env + di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {}) + if not di: + names = m4_re.findall(code) + for i in names: + di[i] = env.get_flat(i) or env.get_flat(i.upper()) + + tsk.outputs[0].write(s % di) + +@feature('subst') +@before_method('process_source') +def apply_subst(self): + Utils.def_attrs(self, fun=subst_func) + lst = self.to_list(self.source) + self.meths.remove('process_source') + + self.dict = getattr(self, 'dict', {}) + + for filename in lst: + node = self.path.find_resource(filename) + if not node: raise Errors.WafError('cannot find input file %s for processing' % filename) + + if self.target: + newnode = self.path.find_or_declare(self.target) + else: + newnode = node.change_ext('') + + try: + self.dict = self.dict.get_merged_dict() + except AttributeError: + pass + + if self.dict and not self.env['DICT_HASH']: + self.env = self.env.derive() + keys = list(self.dict.keys()) + keys.sort() + lst = [self.dict[x] for x in keys] + self.env['DICT_HASH'] = str(Utils.h_list(lst)) + + tsk = self.create_task('copy', node, newnode) + tsk.fun = self.fun + tsk.dict = self.dict + tsk.dep_vars = ['DICT_HASH'] + tsk.chmod = getattr(self, 'chmod', Utils.O644) + + if not tsk.env: + tsk.debug() + raise Errors.WafError('task without an environment') + +#################### +## command-output #### +#################### + +class cmd_arg(object): + """command-output arguments for representing files or folders""" + def __init__(self, name, template='%s'): + self.name = name + self.template = template + self.node = None + +class input_file(cmd_arg): + def find_node(self, base_path): + assert isinstance(base_path, Node.Node) + self.node = base_path.find_resource(self.name) + if self.node is None: + raise Errors.WafError("Input file %s not found in " % (self.name, base_path)) + + def get_path(self, env, absolute): + if absolute: + return self.template % self.node.abspath() + else: + return self.template % self.node.srcpath() + +class output_file(cmd_arg): + def find_node(self, base_path): + assert isinstance(base_path, Node.Node) + self.node = base_path.find_or_declare(self.name) + if self.node is None: + raise Errors.WafError("Output file %s not found in " % (self.name, base_path)) + + def get_path(self, env, absolute): + if absolute: + return self.template % self.node.abspath() + else: + return self.template % self.node.bldpath() + +class cmd_dir_arg(cmd_arg): + def find_node(self, base_path): + assert isinstance(base_path, Node.Node) + self.node = base_path.find_dir(self.name) + if self.node is None: + raise Errors.WafError("Directory %s not found in " % (self.name, base_path)) + +class input_dir(cmd_dir_arg): + def get_path(self, dummy_env, dummy_absolute): + return self.template % self.node.abspath() + +class output_dir(cmd_dir_arg): + def get_path(self, env, dummy_absolute): + return self.template % self.node.abspath() + + +class command_output(Task.Task): + color = "BLUE" + def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr): + Task.Task.__init__(self, env=env) + assert isinstance(command, (str, Node.Node)) + self.command = command + self.command_args = command_args + self.stdin = stdin + self.stdout = stdout + self.cwd = cwd + self.os_env = os_env + self.stderr = stderr + + if command_node is not None: self.dep_nodes = [command_node] + self.dep_vars = [] # additional environment variables to look + + def run(self): + task = self + #assert len(task.inputs) > 0 + + def input_path(node, template): + if task.cwd is None: + return template % node.bldpath() + else: + return template % node.abspath() + def output_path(node, template): + fun = node.abspath + if task.cwd is None: fun = node.bldpath + return template % fun() + + if isinstance(task.command, Node.Node): + argv = [input_path(task.command, '%s')] + else: + argv = [task.command] + + for arg in task.command_args: + if isinstance(arg, str): + argv.append(arg) + else: + assert isinstance(arg, cmd_arg) + argv.append(arg.get_path(task.env, (task.cwd is not None))) + + if task.stdin: + stdin = open(input_path(task.stdin, '%s')) + else: + stdin = None + + if task.stdout: + stdout = open(output_path(task.stdout, '%s'), "w") + else: + stdout = None + + if task.stderr: + stderr = open(output_path(task.stderr, '%s'), "w") + else: + stderr = None + + if task.cwd is None: + cwd = ('None (actually %r)' % os.getcwd()) + else: + cwd = repr(task.cwd) + debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" % + (cwd, stdin, stdout, argv)) + + if task.os_env is None: + os_env = os.environ + else: + os_env = task.os_env + command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env) + return command.wait() + +@feature('command-output') +def init_cmd_output(self): + Utils.def_attrs(self, + stdin = None, + stdout = None, + stderr = None, + # the command to execute + command = None, + + # whether it is an external command; otherwise it is assumed + # to be an executable binary or script that lives in the + # source or build tree. + command_is_external = False, + + # extra parameters (argv) to pass to the command (excluding + # the command itself) + argv = [], + + # dependencies to other objects -> this is probably not what you want (ita) + # values must be 'task_gen' instances (not names!) + dependencies = [], + + # dependencies on env variable contents + dep_vars = [], + + # input files that are implicit, i.e. they are not + # stdin, nor are they mentioned explicitly in argv + hidden_inputs = [], + + # output files that are implicit, i.e. they are not + # stdout, nor are they mentioned explicitly in argv + hidden_outputs = [], + + # change the subprocess to this cwd (must use obj.input_dir() or output_dir() here) + cwd = None, + + # OS environment variables to pass to the subprocess + # if None, use the default environment variables unchanged + os_env = None) + +@feature('command-output') +@after_method('init_cmd_output') +def apply_cmd_output(self): + if self.command is None: + raise Errors.WafError("command-output missing command") + if self.command_is_external: + cmd = self.command + cmd_node = None + else: + cmd_node = self.path.find_resource(self.command) + assert cmd_node is not None, ('''Could not find command '%s' in source tree. +Hint: if this is an external command, +use command_is_external=True''') % (self.command,) + cmd = cmd_node + + if self.cwd is None: + cwd = None + else: + assert isinstance(cwd, CmdDirArg) + self.cwd.find_node(self.path) + + args = [] + inputs = [] + outputs = [] + + for arg in self.argv: + if isinstance(arg, cmd_arg): + arg.find_node(self.path) + if isinstance(arg, input_file): + inputs.append(arg.node) + if isinstance(arg, output_file): + outputs.append(arg.node) + + if self.stdout is None: + stdout = None + else: + assert isinstance(self.stdout, str) + stdout = self.path.find_or_declare(self.stdout) + if stdout is None: + raise Errors.WafError("File %s not found" % (self.stdout,)) + outputs.append(stdout) + + if self.stderr is None: + stderr = None + else: + assert isinstance(self.stderr, str) + stderr = self.path.find_or_declare(self.stderr) + if stderr is None: + raise Errors.WafError("File %s not found" % (self.stderr,)) + outputs.append(stderr) + + if self.stdin is None: + stdin = None + else: + assert isinstance(self.stdin, str) + stdin = self.path.find_resource(self.stdin) + if stdin is None: + raise Errors.WafError("File %s not found" % (self.stdin,)) + inputs.append(stdin) + + for hidden_input in self.to_list(self.hidden_inputs): + node = self.path.find_resource(hidden_input) + if node is None: + raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path)) + inputs.append(node) + + for hidden_output in self.to_list(self.hidden_outputs): + node = self.path.find_or_declare(hidden_output) + if node is None: + raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path)) + outputs.append(node) + + if not (inputs or getattr(self, 'no_inputs', None)): + raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs') + if not (outputs or getattr(self, 'no_outputs', None)): + raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs') + + cwd = self.bld.variant_dir + task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr) + task.generator = self + copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True) + self.tasks.append(task) + + task.inputs = inputs + task.outputs = outputs + task.dep_vars = self.to_list(self.dep_vars) + + for dep in self.dependencies: + assert dep is not self + dep.post() + for dep_task in dep.tasks: + task.set_run_after(dep_task) + + if not task.inputs: + # the case for svnversion, always run, and update the output nodes + task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run + task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__) + + # TODO the case with no outputs? + +def post_run(self): + for x in self.outputs: + x.sig = Utils.h_file(x.abspath()) + +def runnable_status(self): + return self.RUN_ME + +Task.task_factory('copy', vars=[], func=action_process_file_func) + diff --git a/waf-tools/pkgconfig.py b/waf-tools/pkgconfig.py index 95d7cf587..e01012ba6 100644 --- a/waf-tools/pkgconfig.py +++ b/waf-tools/pkgconfig.py @@ -3,10 +3,11 @@ import Options import Configure -import pproc as subprocess +import subprocess import config_c +import sys -def detect(conf): +def configure(conf): pkg_config = conf.find_program('pkg-config', var='PKG_CONFIG') if not pkg_config: return @@ -19,25 +20,31 @@ def pkg_check_modules(conf, uselib_name, expression, mandatory=True): else: return False + if Options.options.verbose: + extra_msg = ' (%s)' % expression + else: + extra_msg = '' + + conf.start_msg('pkg-config flags for %s%s' % (uselib_name, extra_msg)) + argv = [pkg_config, '--cflags', '--libs', expression] - cmd = subprocess.Popen(argv, stdout=subprocess.PIPE) - out, dummy = cmd.communicate() + cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = cmd.communicate() retval = cmd.wait() - msg_checking = ("pkg-config flags for %s" % (uselib_name,)) - if Options.options.verbose: - if retval == 0: - conf.check_message_custom(msg_checking, - ('(%s)' % expression), out) - else: - conf.check_message(msg_checking, ('(%s)' % expression), False) + conf.to_log('%r: %r (exit code %i)\n%s' % (argv, out, retval, err)) + + if retval != 0: + conf.end_msg(False) + sys.stderr.write(err) else: - conf.check_message(msg_checking, '', (retval == 0), '') - conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval)) + if Options.options.verbose: + conf.end_msg(out) + else: + conf.end_msg(True) if retval == 0: - - config_c.parse_flags(out, uselib_name, conf.env) + conf.parse_flags(out, uselib_name, conf.env) conf.env[uselib_name] = True return True diff --git a/wscript b/wscript index 8c319ef08..ce38fc0fc 100644 --- a/wscript +++ b/wscript @@ -11,18 +11,18 @@ import shlex import textwrap # WAF modules -import pproc as subprocess +import subprocess import Options import Logs import TaskGen -import Constants +#import Constants -import ccroot -ccroot.USE_TOP_LEVEL = True +#import ccroot +#ccroot.USE_TOP_LEVEL = True import Task -Task.algotype = Constants.JOBCONTROL # so that Task.maxjobs=1 takes effect +#Task.algotype = Constants.JOBCONTROL # so that Task.maxjobs=1 takes effect import Utils import Build @@ -58,7 +58,7 @@ cflags.default_profile = 'debug' # local modules import wutils -Configure.autoconfig = 1 +Configure.autoconfig = 0 # the following two variables are used by the target "waf dist" VERSION = file("VERSION", "rt").read().strip() @@ -124,12 +124,12 @@ def print_module_names(names): if i != 1: print -def set_options(opt): +def options(opt): # options provided by the modules - opt.tool_options('compiler_cc') - opt.tool_options('compiler_cxx') - opt.tool_options('cflags') - opt.tool_options('gnu_dirs') + opt.load('compiler_c') + opt.load('compiler_cxx') + opt.load('cflags') + opt.load('gnu_dirs') opt.add_option('--cwd', help=('Set the working directory for a program.'), @@ -234,6 +234,7 @@ def _check_compilation_flag(conf, flag, mode='cxx'): flag: can be a string or a list of strings """ + conf.start_msg('Checking for compilation flag %r support' % (flag,)) env = conf.env.copy() if mode == 'cxx': fname = 'test.cc' @@ -244,26 +245,36 @@ def _check_compilation_flag(conf, flag, mode='cxx'): try: retval = conf.run_c_code(code='#include \nint main() { return 0; }\n', env=env, compile_filename=fname, - compile_mode=mode, type='cprogram', execute=False) + compile_mode=mode, features='c cprogram', execute=False) except Configure.ConfigurationError: ok = False else: ok = (retval == 0) - conf.check_message_custom(flag, 'support', (ok and 'yes' or 'no')) + conf.end_msg(ok) return ok def report_optional_feature(conf, name, caption, was_enabled, reason_not_enabled): - conf.env.append_value('NS3_OPTIONAL_FEATURES', (name, caption, was_enabled, reason_not_enabled)) + conf.env.append_value('NS3_OPTIONAL_FEATURES', [(name, caption, was_enabled, reason_not_enabled)]) + + +# starting with waf 1.6, conf.check() becomes fatal by default if the +# test fails, this alternative method makes the test non-fatal, as it +# was in waf <= 1.5 +def _check_nonfatal(conf, *args, **kwargs): + try: + return conf.check(*args, **kwargs) + except conf.errors.ConfigurationError: + return None def configure(conf): # attach some extra methods + conf.check_nonfatal = types.MethodType(_check_nonfatal, conf) conf.check_compilation_flag = types.MethodType(_check_compilation_flag, conf) conf.report_optional_feature = types.MethodType(report_optional_feature, conf) conf.env['NS3_OPTIONAL_FEATURES'] = [] - conf.env['NS3_BUILDDIR'] = conf.blddir - conf.check_tool('compiler_cc') + conf.check_tool('compiler_c') conf.check_tool('compiler_cxx') conf.check_tool('cflags', ['waf-tools']) try: @@ -276,24 +287,20 @@ def configure(conf): #if os.path.exists('/usr/lib64'): # conf.env.LIBDIR = os.path.join(conf.env.PREFIX, "lib64") - # create the second environment, set the variant and set its name - variant_env = conf.env.copy() - variant_name = Options.options.build_profile + + # variant_name = Options.options.build_profile + # if Options.options.enable_gcov: + # variant_name += '-gcov' + # conf.env['NS3_ACTIVE_VARIANT'] = variant_name + # conf.setenv(variant_name, env=conf.env.derive()) # start with a copy instead of a new env + env = conf.env if Options.options.enable_gcov: - variant_name += '-gcov' - variant_env.append_value('CCFLAGS', '-fprofile-arcs') - variant_env.append_value('CCFLAGS', '-ftest-coverage') - variant_env.append_value('CXXFLAGS', '-fprofile-arcs') - variant_env.append_value('CXXFLAGS', '-ftest-coverage') - variant_env.append_value('LINKFLAGS', '-fprofile-arcs') - - conf.env['NS3_ACTIVE_VARIANT'] = variant_name - variant_env['NS3_ACTIVE_VARIANT'] = variant_name - variant_env.set_variant(variant_name) - conf.set_env_name(variant_name, variant_env) - conf.setenv(variant_name) - env = variant_env + env.append_value('CCFLAGS', '-fprofile-arcs') + env.append_value('CCFLAGS', '-ftest-coverage') + env.append_value('CXXFLAGS', '-fprofile-arcs') + env.append_value('CXXFLAGS', '-ftest-coverage') + env.append_value('LINKFLAGS', '-fprofile-arcs') if Options.options.build_profile == 'debug': env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') @@ -332,8 +339,6 @@ def configure(conf): conf.report_optional_feature("static", "Static build", True, '') if Options.options.enable_static: env['ENABLE_STATIC_NS3'] = True - if Options.options.enable_shared_and_static: - env['ENABLE_SHARED_AND_STATIC_NS3'] = True elif os.uname()[4] == 'x86_64': if env['ENABLE_PYTHON_BINDINGS'] and \ not conf.check_compilation_flag('-mcmodel=large'): @@ -346,8 +351,6 @@ def configure(conf): conf.report_optional_feature("static", "Static build", True, '') if Options.options.enable_static: env['ENABLE_STATIC_NS3'] = True - if Options.options.enable_shared_and_static: - env['ENABLE_SHARED_AND_STATIC_NS3'] = True elif env['CXX_NAME'] == 'gcc' and \ (env['PLATFORM'].startswith('darwin') or \ env['PLATFORM'].startswith('cygwin')): @@ -553,13 +556,12 @@ class SuidBuildTask(Task.TaskBase): "RUN_ME SKIP_ME or ASK_LATER" st = os.stat(self.filename) if st.st_uid == 0: - return Constants.SKIP_ME + return Task.SKIP_ME else: - return Constants.RUN_ME - + return Task.RUN_ME def create_suid_program(bld, name): - program = bld.new_task_gen('cxx', 'program') + program = bld.new_task_gen(features=['cxx', 'cxxprogram']) program.is_ns3_program = True program.module_deps = list() program.name = name @@ -571,20 +573,21 @@ def create_suid_program(bld, name): return program def create_ns3_program(bld, name, dependencies=('core',)): - program = bld.new_task_gen('cxx', 'program') + program = bld.new_task_gen(features=['cxx', 'cxxprogram']) program.is_ns3_program = True program.name = name program.target = program.name # Each of the modules this program depends on has its own library. program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies] + program.includes = "# #/.." return program def register_ns3_script(bld, name, dependencies=('core',)): ns3_module_dependencies = ['ns3-'+dep for dep in dependencies] - bld.env.append_value('NS3_SCRIPT_DEPENDENCIES', (name, ns3_module_dependencies)) + bld.env.append_value('NS3_SCRIPT_DEPENDENCIES', [(name, ns3_module_dependencies)]) def add_examples_programs(bld): - env = bld.env_of_name('default') + env = bld.env if env['ENABLE_EXAMPLES']: for dir in os.listdir('examples'): if dir.startswith('.') or dir == 'CVS': @@ -615,8 +618,9 @@ def add_scratch_programs(bld): def _add_ns3_program_missing_deps(bld, program): deps_found = program.ns3_module_dependencies - program.uselib_local = getattr(program, "uselib_local", []) + [dep + "--lib" for dep in deps_found] - if program.env['ENABLE_STATIC_NS3'] and not program.env['ENABLE_SHARED_AND_STATIC_NS3']: + program.use = getattr(program, "use", []) + [dep #+ "--lib" + for dep in deps_found] + if program.env['ENABLE_STATIC_NS3']: if sys.platform == 'darwin': program.env.append_value('LINKFLAGS', '-Wl,-all_load') for dep in deps_found: @@ -628,8 +632,62 @@ def _add_ns3_program_missing_deps(bld, program): program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') +from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext +class Ns3BuildContext(BuildContext): + cmd = 'build' + #variant = 'debug' # FIXME + + # @property + # def variant(self): + # if not self.all_envs: + # self.load_envs() + # return self.all_envs[''].NS3_ACTIVE_VARIANT + + def get_all_task_gen(self): + for group in self.groups: + for taskgen in group: + yield taskgen + all_task_gen = property(get_all_task_gen) + + def get_taskgen(self, name): + for group in self.groups: + for taskgen in group: + if taskgen.name == name: + return taskgen + raise KeyError(name) + + def exclude_taskgen(self, taskgen): + # ok, so WAF does not provide an API to prevent an + # arbitrary taskgen from running; we have to muck around with + # WAF internal state, something that might stop working if + # WAF is upgraded... + for group in self.groups: + for tg1 in group: + if tg1 is taskgen: + group.remove(tg1) + break + else: + continue + break + def build(bld): + + + # switch to the variant matching our debug level + #variant_name = bld.env['NS3_ACTIVE_VARIANT'] + #print variant_name + #bld.variant = variant_name + #variant_env = bld.env_of_name(variant_name) + #bld.all_envs['default'] = variant_env + + env = bld.env + #bld.variant = bld.env.NS3_ACTIVE_VARIANT + #bld.init_dirs() + #env = bld.env + #print "-----------------------------------------------------------------------" + #print env + # If --enabled-modules option was given, then print a warning # message and exit this function. if Options.options.enable_modules: @@ -654,15 +712,10 @@ def build(bld): bld.register_ns3_script = types.MethodType(register_ns3_script, bld) bld.create_suid_program = types.MethodType(create_suid_program, bld) - # switch default variant to the one matching our debug level - variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT'] - variant_env = bld.env_of_name(variant_name) - bld.all_envs['default'] = variant_env - # process subfolders from here bld.add_subdirs('src') - env = bld.env + #env = bld.env # If modules have been enabled, then set lists of enabled modules # and enabled module test libraries. @@ -679,7 +732,7 @@ def build(bld): if module_obj is None: raise ValueError("module %s not found" % module) # Each enabled module has its own library. - for dep in module_obj.uselib_local: + for dep in module_obj.use: if not dep.startswith('ns3-'): continue if dep not in modules: @@ -701,20 +754,6 @@ def build(bld): if env['NS3_ENABLED_MODULES']: modules = env['NS3_ENABLED_MODULES'] - def exclude_taskgen(bld, taskgen): - # ok, so WAF does not provide an API to prevent an - # arbitrary taskgen from running; we have to muck around with - # WAF internal state, something that might stop working if - # WAF is upgraded... - bld.all_task_gen.remove(taskgen) - for group in bld.task_manager.groups: - try: - group.tasks_gen.remove(taskgen) - except ValueError: - pass - else: - break - # Exclude the programs other misc task gens that depend on disabled modules for obj in list(bld.all_task_gen): @@ -729,7 +768,7 @@ def build(bld): program_built = True for dep in obj.ns3_module_dependencies: if dep not in modules: # prog. depends on a module that isn't enabled? - exclude_taskgen(bld, obj) + bld.exclude_taskgen(obj) program_built = False break @@ -740,12 +779,12 @@ def build(bld): # disable the modules themselves if hasattr(obj, "is_ns3_module") and obj.name not in modules: - exclude_taskgen(bld, obj) # kill the module + bld.exclude_taskgen(obj) # kill the module # disable the module test libraries if hasattr(obj, "is_ns3_module_test_library"): if not env['ENABLE_TESTS'] or (obj.module_name not in modules): - exclude_taskgen(bld, obj) # kill the module test library + bld.exclude_taskgen(obj) # kill the module test library # disable the ns3header_taskgen if type(obj).__name__ == 'ns3header_taskgen': @@ -806,7 +845,7 @@ def build(bld): # When --run'ing a program, tell WAF to only build that program, # nothing more; this greatly speeds up compilation when all you # want to do is run a test program. - Options.options.compile_targets += ',' + os.path.basename(program_name) + Options.options.targets += ',' + os.path.basename(program_name) for gen in bld.all_task_gen: if type(gen).__name__ in ['ns3header_taskgen', 'ns3moduleheader_taskgen']: gen.post() @@ -826,9 +865,9 @@ def shutdown(ctx): # clean. if ((not Options.options.run) and (not Options.options.pyrun) - and ('clean' not in Options.arg_line) - and ('distclean' not in Options.arg_line) - and ('shell' not in Options.arg_line)): + and ('clean' not in Options.commands) + and ('distclean' not in Options.commands) + and ('shell' not in Options.commands)): # Print the list of built modules. print @@ -844,7 +883,8 @@ def shutdown(ctx): print # Write the build status file. - build_status_file = os.path.join (env['NS3_BUILDDIR'], env['NS3_ACTIVE_VARIANT'], 'build-status.py') + build_status_file = os.path.join(bld.out_dir, #env['NS3_ACTIVE_VARIANT'], + 'build-status.py') out = open(build_status_file, 'w') out.write('#! /usr/bin/env python\n') out.write('\n') @@ -955,21 +995,31 @@ def check_shell(bld): raise Utils.WafError(msg) -shell_context = Build.BuildContext -def shell(ctx): +from waflib import Context, Build +class Ns3ShellContext(Context.Context): """run a shell with an environment suitably modified to run locally built programs""" + cmd = 'shell' - #make sure we build first" - Scripting.build(ctx) + def execute(self): - if sys.platform == 'win32': - shell = os.environ.get("COMSPEC", "cmd.exe") - else: - shell = os.environ.get("SHELL", "/bin/sh") + # first we execute the build + bld = Context.create_context("build") + bld.options = Options.options # provided for convenience + bld.cmd = "build" + bld.execute() + + if sys.platform == 'win32': + shell = os.environ.get("COMSPEC", "cmd.exe") + else: + shell = os.environ.get("SHELL", "/bin/sh") + + env = bld.env + os_env = { + 'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH']), + 'NS3_EXECUTABLE_PATH': os.pathsep.join(env['NS3_EXECUTABLE_PATH']), + } + wutils.run_argv([shell], env, os_env) - env = wutils.bld.env - os_env = {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH']), 'NS3_EXECUTABLE_PATH': os.pathsep.join(env['NS3_EXECUTABLE_PATH'])} - wutils.run_argv([shell], env, os_env) def _doxygen(bld): env = wutils.bld.env @@ -1049,109 +1099,109 @@ def lcov_report(): ## and the .hg repository tree. Here we provide a replacement DistDir ## implementation that is more efficient. ## -import Scripting -from Scripting import dist_exts, excludes, BLDDIR -import Utils -import os +# import Scripting +# from Scripting import dist_exts, excludes, BLDDIR +# import Utils +# import os -def _copytree(src, dst, symlinks=False, excludes=(), build_dir=None): - """Recursively copy a directory tree using copy2(). +# def _copytree(src, dst, symlinks=False, excludes=(), build_dir=None): +# """Recursively copy a directory tree using copy2(). - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. +# The destination directory must not already exist. +# If exception(s) occur, an Error is raised with a list of reasons. - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. +# If the optional symlinks flag is true, symbolic links in the +# source tree result in symbolic links in the destination tree; if +# it is false, the contents of the files pointed to by symbolic +# links are copied. - XXX Consider this example code rather than the ultimate tool. +# XXX Consider this example code rather than the ultimate tool. - Note: this is a modified version of shutil.copytree from python - 2.5.2 library; modified for WAF purposes to exclude dot dirs and - another list of files. - """ - names = os.listdir(src) - os.makedirs(dst) - errors = [] - for name in names: - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if symlinks and os.path.islink(srcname): - linkto = os.readlink(srcname) - os.symlink(linkto, dstname) - elif os.path.isdir(srcname): - if name in excludes: - continue - elif name.startswith('.') or name.startswith(',,') or name.startswith('++') or name.startswith('CVS'): - continue - elif name == build_dir: - continue - else: - ## build_dir is not passed into the recursive - ## copytree, but that is intentional; it is a - ## directory name valid only at the top level. - copytree(srcname, dstname, symlinks, excludes) - else: - ends = name.endswith - to_remove = False - if name.startswith('.') or name.startswith('++'): - to_remove = True - else: - for x in dist_exts: - if ends(x): - to_remove = True - break - if not to_remove: - shutil.copy2(srcname, dstname) - # XXX What about devices, sockets etc.? - except (IOError, os.error), why: - errors.append((srcname, dstname, str(why))) - # catch the Error from the recursive copytree so that we can - # continue with other files - except shutil.Error, err: - errors.extend(err.args[0]) - try: - shutil.copystat(src, dst) - except WindowsError: - # can't copy file access times on Windows - pass - except OSError, why: - errors.extend((src, dst, str(why))) - if errors: - raise shutil.Error, errors +# Note: this is a modified version of shutil.copytree from python +# 2.5.2 library; modified for WAF purposes to exclude dot dirs and +# another list of files. +# """ +# names = os.listdir(src) +# os.makedirs(dst) +# errors = [] +# for name in names: +# srcname = os.path.join(src, name) +# dstname = os.path.join(dst, name) +# try: +# if symlinks and os.path.islink(srcname): +# linkto = os.readlink(srcname) +# os.symlink(linkto, dstname) +# elif os.path.isdir(srcname): +# if name in excludes: +# continue +# elif name.startswith('.') or name.startswith(',,') or name.startswith('++') or name.startswith('CVS'): +# continue +# elif name == build_dir: +# continue +# else: +# ## build_dir is not passed into the recursive +# ## copytree, but that is intentional; it is a +# ## directory name valid only at the top level. +# copytree(srcname, dstname, symlinks, excludes) +# else: +# ends = name.endswith +# to_remove = False +# if name.startswith('.') or name.startswith('++'): +# to_remove = True +# else: +# for x in dist_exts: +# if ends(x): +# to_remove = True +# break +# if not to_remove: +# shutil.copy2(srcname, dstname) +# # XXX What about devices, sockets etc.? +# except (IOError, os.error), why: +# errors.append((srcname, dstname, str(why))) +# # catch the Error from the recursive copytree so that we can +# # continue with other files +# except shutil.Error, err: +# errors.extend(err.args[0]) +# try: +# shutil.copystat(src, dst) +# except WindowsError: +# # can't copy file access times on Windows +# pass +# except OSError, why: +# errors.extend((src, dst, str(why))) +# if errors: +# raise shutil.Error, errors -def DistDir(appname, version): - #"make a distribution directory with all the sources in it" - import shutil +# def DistDir(appname, version): +# #"make a distribution directory with all the sources in it" +# import shutil - # Our temporary folder where to put our files - TMPFOLDER=appname+'-'+version +# # Our temporary folder where to put our files +# TMPFOLDER=appname+'-'+version - # Remove an old package directory - if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) +# # Remove an old package directory +# if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) - global g_dist_exts, g_excludes +# global g_dist_exts, g_excludes - # Remove the Build dir - build_dir = getattr(Utils.g_module, BLDDIR, None) +# # Remove the Build dir +# build_dir = getattr(Utils.g_module, BLDDIR, None) - # Copy everything into the new folder - _copytree('.', TMPFOLDER, excludes=excludes, build_dir=build_dir) +# # Copy everything into the new folder +# _copytree('.', TMPFOLDER, excludes=excludes, build_dir=build_dir) - # TODO undocumented hook - dist_hook = getattr(Utils.g_module, 'dist_hook', None) - if dist_hook: - os.chdir(TMPFOLDER) - try: - dist_hook() - finally: - # go back to the root directory - os.chdir('..') - return TMPFOLDER +# # TODO undocumented hook +# dist_hook = getattr(Utils.g_module, 'dist_hook', None) +# if dist_hook: +# os.chdir(TMPFOLDER) +# try: +# dist_hook() +# finally: +# # go back to the root directory +# os.chdir('..') +# return TMPFOLDER -Scripting.DistDir = DistDir +# Scripting.DistDir = DistDir diff --git a/wutils.py b/wutils.py index 6d16fac95..b4210e7d7 100644 --- a/wutils.py +++ b/wutils.py @@ -1,18 +1,17 @@ import os import os.path import sys -import pproc as subprocess +import subprocess import shlex # WAF modules -import ccroot import Options import Utils import Logs import TaskGen import Build import re - +from waflib.Errors import WafError # these are set from the main wscript file APPNAME=None @@ -48,10 +47,10 @@ else: return os.path.curdir return os.path.join(*rel_list) - +from waflib import Context def find_program(program_name, env): - launch_dir = os.path.abspath(Options.cwd_launch) - top_dir = os.path.abspath(Options.launch_dir) + launch_dir = os.path.abspath(Context.launch_dir) + #top_dir = os.path.abspath(Options.cwd_launch) found_programs = [] for obj in bld.all_task_gen: if not getattr(obj, 'is_ns3_program', False): @@ -63,7 +62,7 @@ def find_program(program_name, env): continue name1 = obj.target - name2 = os.path.join(relpath(obj.path.abspath(), top_dir), obj.target) + name2 = os.path.join(relpath(obj.path.abspath(), launch_dir), obj.target) names = [name1, name2] found_programs.extend(names) if program_name in names: @@ -99,7 +98,7 @@ def get_proc_env(os_env=None): else: proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH'])) - pymoddir = bld.path.find_dir('bindings/python').abspath(env) + pymoddir = bld.path.find_dir('bindings/python').get_bld().abspath() pyvizdir = bld.path.find_dir('src/visualizer').abspath() if 'PYTHONPATH' in proc_env: proc_env['PYTHONPATH'] = os.pathsep.join([pymoddir, pyvizdir] + [proc_env['PYTHONPATH']]) @@ -117,9 +116,9 @@ def run_argv(argv, env, os_env=None, cwd=None, force_no_valgrind=False): proc_env = get_proc_env(os_env) if Options.options.valgrind and not force_no_valgrind: if Options.options.command_template: - raise Utils.WafError("Options --command-template and --valgrind are conflicting") + raise WafError("Options --command-template and --valgrind are conflicting") if not env['VALGRIND']: - raise Utils.WafError("valgrind is not installed") + raise WafError("valgrind is not installed") argv = [env['VALGRIND'], "--leak-check=full", "--show-reachable=yes", "--error-exitcode=1"] + argv proc = subprocess.Popen(argv, env=proc_env, cwd=cwd, stderr=subprocess.PIPE) error = False @@ -139,7 +138,7 @@ def run_argv(argv, env, os_env=None, cwd=None, force_no_valgrind=False): try: retval = subprocess.Popen(argv, env=proc_env, cwd=cwd).wait() except WindowsError, ex: - raise Utils.WafError("Command %s raised exception %s" % (argv, ex)) + raise WafError("Command %s raised exception %s" % (argv, ex)) if retval: signame = None if retval < 0: # signal? @@ -150,11 +149,11 @@ def run_argv(argv, env, os_env=None, cwd=None, force_no_valgrind=False): signame = name break if signame: - raise Utils.WafError("Command %s terminated with signal %s." + raise WafError("Command %s terminated with signal %s." " Run it under a debugger to get more information " "(./waf --run --command-template=\"gdb --args %%s \")." % (argv, signame)) else: - raise Utils.WafError("Command %s exited with code %i" % (argv, retval)) + raise WafError("Command %s exited with code %i" % (argv, retval)) return retval def get_run_program(program_string, command_template=None): @@ -173,15 +172,15 @@ def get_run_program(program_string, command_template=None): try: program_obj = find_program(program_name, env) except ValueError, ex: - raise Utils.WafError(str(ex)) + raise WafError(str(ex)) - program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)) + program_node = program_obj.path.find_or_declare(program_obj.target) #try: # program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj)) #except AttributeError: # raise Utils.WafError("%s does not appear to be a program" % (program_name,)) - execvec = [program_node.abspath(env)] + argv[1:] + execvec = [program_node.abspath()] + argv[1:] else: @@ -189,9 +188,9 @@ def get_run_program(program_string, command_template=None): try: program_obj = find_program(program_name, env) except ValueError, ex: - raise Utils.WafError(str(ex)) + raise WafError(str(ex)) - program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)) + program_node = program_obj.path.find_or_declare(program_obj.target) #try: # program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj)) #except AttributeError: From 0536f2416f69bb2895f0fcfc5fe62dc360e4c8e3 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 14:54:27 +0100 Subject: [PATCH 02/17] More waf 1.6.7 build fixes --- bindings/python/wscript | 2 +- src/click/wscript | 2 +- src/core/wscript | 2 +- src/internet/wscript | 2 +- src/openflow/wscript | 2 +- src/wscript | 109 ++++++++++++++++++++++++++-------------- test.py | 38 +++++--------- waf-tools/cflags.py | 4 +- wscript | 109 ++++++++++++++-------------------------- 9 files changed, 130 insertions(+), 140 deletions(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index bcbb57b36..9f5a47e2c 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -46,7 +46,7 @@ def set_pybindgen_pythonpath(env): add_to_python_path(env['WITH_PYBINDGEN']) -def set_options(opt): +def options(opt): opt.tool_options('python') opt.add_option('--disable-python', help=("Don't build Python bindings."), diff --git a/src/click/wscript b/src/click/wscript index 955bb2637..e72a78d44 100644 --- a/src/click/wscript +++ b/src/click/wscript @@ -4,7 +4,7 @@ import os import Options -def set_options(opt): +def options(opt): opt.add_option('--with-nsclick', help=('Path to Click source or installation prefix for NS-3 Click Integration support'), dest='with_nsclick', default=None) diff --git a/src/core/wscript b/src/core/wscript index 0c6483ab5..07db59c19 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -3,7 +3,7 @@ import sys import Options -def set_options(opt): +def options(opt): opt.add_option('--int64x64-as-double', help=('Whether to use a double floating point' ' type for int64x64 values' diff --git a/src/internet/wscript b/src/internet/wscript index 6a699ea9a..65aeaa70a 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -11,7 +11,7 @@ import Task NSC_RELEASE_NAME = "nsc-0.5.2" -def set_options(opt): +def options(opt): opt.add_option('--with-nsc', help=('Use Network Simulation Cradle, given by the indicated path,' ' to allow the use of real-world network stacks'), diff --git a/src/openflow/wscript b/src/openflow/wscript index 99b8f959f..4a639f7d5 100644 --- a/src/openflow/wscript +++ b/src/openflow/wscript @@ -3,7 +3,7 @@ import os import Options -def set_options(opt): +def options(opt): opt.add_option('--with-openflow', help=('Path to OFSID source for NS-3 OpenFlow Integration support'), default='', dest='with_openflow') diff --git a/src/wscript b/src/wscript index e53a6cce1..7b9759c4b 100644 --- a/src/wscript +++ b/src/wscript @@ -6,6 +6,8 @@ import shutil import types import warnings +from waflib.Errors import WafError + import TaskGen import Task import Options @@ -65,7 +67,7 @@ all_modules = [ 'template', ] -def set_options(opt): +def options(opt): opt.sub_options('core') opt.sub_options('click') opt.sub_options('openflow') @@ -157,14 +159,42 @@ def configure(conf): # # FIXME: env modifications are overwritten by parent caller +@TaskGen.feature('ns3module') +@TaskGen.after_method('process_rule') +def _add_test_code(module): + bld = module.bld + if 0: #len(module.source) > 0 and hasattr(module, 'ns3_dir_location'): + uselib_cpppath = [] + for lib in module.uselib.split(): + if 'CPPPATH_%s' % lib in module.env: + uselib_cpppath.extend(module.env['CPPPATH_%s' % lib]) + objects = [] + for src in module.source[0:-1]: + full_src = os.path.join(module.ns3_dir_location, src) + path = os.path.dirname(full_src) + target = '%s_object' % src + # XXX: calculate the features correctly here. + obj = bld.objects(source=[full_src], target=target, features='cxx cc', + env = module.env.copy()) + obj.env.CXXDEFINES += 'NS_TEST_SOURCEDIR="%s"' % path + obj.env.INCLUDES += uselib_cpppath + obj.name = module.name + '--test' + objects.append(target) + last = module.source[-1] + full_src = os.path.join(module.ns3_dir_location, last) + path = os.path.dirname(full_src) + module.env.CXXDEFINES += 'NS_TEST_SOURCEDIR="%s"' % path + module.source = [last] + objects + #module.add_objects.extend(objects) + 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']) + module = bld.new_task_gen(features=['cxx', 'cxxstlib', 'ns3module']) else: - module = bld.new_task_gen(features=['cxx', 'cxxshlib']) + module = bld.new_task_gen(features=['cxx', 'cxxshlib', 'ns3module']) linkflags = [] cxxflags = [] ccflags = [] @@ -219,38 +249,24 @@ def create_ns3_module(bld, name, dependencies=(), test=False): module.ns3_dir_location = bld.path.relpath_gen(bld.srcnode) module.env.append_value("INCLUDES", '#') - - if len(module.source) > 0 and hasattr(self, 'ns3_dir_location'): - uselib_cpppath = [] - for lib in module.uselib.split(): - if 'CPPPATH_%s' % lib in module.env: - uselib_cpppath.extend(module.env['CPPPATH_%s' % lib]) - objects = [] - for src in module.source[0:-1]: - full_src = os.path.join(self.ns3_dir_location, src) - path = os.path.dirname(full_src) - target = '%s_object' % src - # XXX: calculate the features correctly here. - obj = bld (source=[full_src], target=target, features='cxx cc', - defines=['NS_TEST_SOURCEDIR="%s"' % path], - includes=' '.join(uselib_cpppath), - env = module.env) - objects.append(target) - last = module.source[-1] - full_src = os.path.join(self.ns3_dir_location, last) - path = os.path.dirname(full_src) - module.defines.append('NS_TEST_SOURCEDIR="%s"' % path) - module.source = [last] - module.add_objects.extend(objects) - + return module +@TaskGen.feature("ns3testlib") +@TaskGen.before_method("apply_incpaths") +def apply_incpaths_ns3testlib(self): + if not self.source: + return + testdir = self.source[-1].parent.relpath_gen(self.bld.srcnode) + self.env.append_value("DEFINES", 'NS_TEST_SOURCEDIR="%s"' % (testdir,)) + def create_ns3_module_test_library(bld, name): # Create an ns3 module for the test library that depends only on # the module being tested. library_name = name + "-test" - library = bld.create_ns3_module(library_name, [name], test = True) + library = bld.create_ns3_module(library_name, [name], test=True) + library.features.append("ns3testlib") # Modify attributes for the test library that are different from a # normal module. @@ -259,7 +275,7 @@ def create_ns3_module_test_library(bld, name): library.module_name = 'ns3-' + name # Add this module and test library to the list. - bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', (library.module_name, library.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) @@ -528,6 +544,7 @@ def apply_ns3header(self): ns3_dir_node = self.bld.path.find_dir("ns3") #if self.sub_dir is not None: # ns3_dir_node = ns3_dir_node.find_dir(self.sub_dir) + for filename in set(self.to_list(self.source)): src_node = self.path.find_resource(filename) if src_node is None: @@ -557,12 +574,30 @@ class ns3header_task(Task.Task): if self.outputs: sep = ' -> ' else: sep = '' if self.mode == 'remove': - return 'rm-ns3-header %s\n' % (self.header_to_remove.bldpath(self.env),) + return 'rm-ns3-header %s\n' % (self.header_to_remove.abspath(),) return 'install-ns3-header: %s%s%s\n' % (src_str, sep, tgt_str) + def __repr__(self): + return str(self) + + def uid(self): + try: + return self.uid_ + except AttributeError: + m = Utils.md5() + up = m.update + up(self.__class__.__name__.encode()) + for x in self.inputs + self.outputs: + up(x.abspath().encode()) + up(self.mode) + if self.mode == 'remove': + up(self.header_to_remove.abspath().encode()) + self.uid_ = m.digest() + return self.uid_ + def runnable_status(self): if self.mode == 'remove': - if os.path.exists(self.header_to_remove.bldpath(self.env)): + if os.path.exists(self.header_to_remove.abspath()): return Task.RUN_ME else: return Task.SKIP_ME @@ -587,7 +622,7 @@ class ns3header_task(Task.Task): else: assert len(self.inputs) == 0 assert len(self.outputs) == 0 - out_file_name = self.header_to_remove.bldpath(self.env) + out_file_name = self.header_to_remove.abspath() try: os.unlink(out_file_name) except OSError, ex: @@ -603,7 +638,7 @@ class gen_ns3_module_header_task(Task.Task): def runnable_status(self): if self.mode == 'remove': - if os.path.exists(self.header_to_remove.bldpath(self.env)): + if os.path.exists(self.header_to_remove.abspath()): return Task.RUN_ME else: return Task.SKIP_ME @@ -618,14 +653,14 @@ class gen_ns3_module_header_task(Task.Task): if self.outputs: sep = ' -> ' else: sep = '' if self.mode == 'remove': - return 'rm-module-header %s\n' % (self.header_to_remove.bldpath(self.env),) + return 'rm-module-header %s\n' % (self.header_to_remove.abspath(),) return 'gen-module-header: %s%s%s\n' % (src_str, sep, tgt_str) def run(self): if self.mode == 'remove': assert len(self.inputs) == 0 assert len(self.outputs) == 0 - out_file_name = self.header_to_remove.bldpath(self.env) + out_file_name = self.header_to_remove.abspath() try: os.unlink(out_file_name) except OSError, ex: @@ -702,8 +737,8 @@ def apply_ns3moduleheader(self): return try: - module_obj = self.bld.get_taskgen("ns3-" + self.module) - except KeyError: # maybe the module was disabled, and therefore removed + module_obj = self.bld.get_tgen_by_name("ns3-" + self.module) + except WafError: # maybe the module was disabled, and therefore removed return all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)] diff --git a/test.py b/test.py index f4c2433ca..7fee5e8fb 100755 --- a/test.py +++ b/test.py @@ -42,7 +42,6 @@ from utils import get_list_from_file # found in the associated subdirectory wscript files. # interesting_config_items = [ - "NS3_BUILDDIR", "NS3_ENABLED_MODULES", "NS3_MODULE_PATH", "NSC_ENABLED", @@ -483,24 +482,6 @@ def sigint_hook(signal, frame): thread_exit = True return 0 -# -# Waf can be configured to compile in debug or optimized modes. In each -# case, the resulting built goes into a different directory. If we want -# test tests to run from the correct code-base, we have to figure out which -# mode waf is running in. This is called its active variant. -# -# XXX This function pokes around in the waf internal state file. To be a -# little less hacky, we should add a commmand to waf to return this info -# and use that result. -# -def read_waf_active_variant(): - for line in open("build/c4che/default.cache.py").readlines(): - if line.startswith("NS3_ACTIVE_VARIANT"): - exec(line, globals()) - break - - if options.verbose: - print "NS3_ACTIVE_VARIANT == %s" % NS3_ACTIVE_VARIANT # # In general, the build process itself naturally takes care of figuring out @@ -519,7 +500,13 @@ def read_waf_active_variant(): # and use that result. # def read_waf_config(): - for line in open("build/c4che/%s.cache.py" % NS3_ACTIVE_VARIANT).readlines(): + for line in open(".lock-wafbuild", "rt"): + if line.startswith("out_dir ="): + key, val = line.split('=') + out_dir = eval(val.strip()) + global NS3_BUILDDIR + NS3_BUILDDIR = out_dir + for line in open("%s/c4che/_cache.py" % out_dir).readlines(): for item in interesting_config_items: if line.startswith(item): exec(line, globals()) @@ -555,7 +542,7 @@ def make_paths(): if key == "PYTHONPATH": have_PYTHONPATH = True - pypath = os.environ["PYTHONPATH"] = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, "bindings", "python") + pypath = os.environ["PYTHONPATH"] = os.path.join (NS3_BUILDDIR, "bindings", "python") if not have_PYTHONPATH: os.environ["PYTHONPATH"] = pypath @@ -684,7 +671,7 @@ def run_job_synchronously(shell_command, directory, valgrind, is_python, build_p if len(build_path): path_cmd = os.path.join (build_path, shell_command) else: - path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command) + path_cmd = os.path.join (NS3_BUILDDIR, shell_command) if valgrind: cmd = "valgrind --suppressions=%s --leak-check=full --show-reachable=yes --error-exitcode=2 %s" % (suppressions_path, @@ -991,12 +978,11 @@ def run_tests(): # pieces of the system have been built. This will tell us what examples # are runnable. # - read_waf_active_variant() read_waf_config() make_paths() # Get the information from the build status file. - build_status_file = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, 'build-status.py') + build_status_file = os.path.join (NS3_BUILDDIR, 'build-status.py') if os.path.exists(build_status_file): ns3_runnable_programs = get_list_from_file(build_status_file, "ns3_runnable_programs") ns3_runnable_scripts = get_list_from_file(build_status_file, "ns3_runnable_scripts") @@ -1013,7 +999,7 @@ def run_tests(): # Set the directories and paths for this example. example_directory = os.path.join("examples", directory) examples_to_run_path = os.path.join(example_directory, "examples-to-run.py") - cpp_executable_dir = os.path.join(NS3_BUILDDIR, NS3_ACTIVE_VARIANT, example_directory) + cpp_executable_dir = os.path.join(NS3_BUILDDIR, example_directory) python_script_dir = os.path.join(example_directory) # Parse this example directory's file. @@ -1032,7 +1018,7 @@ def run_tests(): module_directory = os.path.join("src", module) example_directory = os.path.join(module_directory, "examples") examples_to_run_path = os.path.join(module_directory, "test", "examples-to-run.py") - cpp_executable_dir = os.path.join(NS3_BUILDDIR, NS3_ACTIVE_VARIANT, example_directory) + cpp_executable_dir = os.path.join(NS3_BUILDDIR, example_directory) python_script_dir = os.path.join(example_directory) # Parse this module's file. diff --git a/waf-tools/cflags.py b/waf-tools/cflags.py index 1738c88f9..cf9c93c46 100644 --- a/waf-tools/cflags.py +++ b/waf-tools/cflags.py @@ -144,7 +144,7 @@ profiles = { default_profile = 'default' -def set_options(opt): +def options(opt): assert default_profile in profiles opt.add_option('-d', '--build-profile', action='store', @@ -157,7 +157,7 @@ def set_options(opt): choices=profiles.keys(), dest='build_profile') -def detect(conf): +def configure(conf): cc = conf.env['COMPILER_CC'] or None cxx = conf.env['COMPILER_CXX'] or None if not (cc or cxx): diff --git a/wscript b/wscript index ce38fc0fc..8801483c6 100644 --- a/wscript +++ b/wscript @@ -73,8 +73,8 @@ if sys.platform != 'darwin' and re.match(r"^\d+\.\d+(\.\d+)?$", VERSION) is not wutils.VNUM = VERSION # these variables are mandatory ('/' are converted automatically) -srcdir = '.' -blddir = 'build' +top = '.' +out = 'build' def load_env(): bld_cls = getattr(Utils.g_module, 'build_context', Utils.Context) @@ -525,23 +525,20 @@ def configure(conf): status = 'not enabled (%s)' % reason_not_enabled print "%-30s: %s" % (caption, status) -class SuidBuildTask(Task.TaskBase): + +class SuidBuild_task(Task.TaskBase): """task that makes a binary Suid """ - after = 'cxx_link cc_link' - maxjobs = 1 - def __init__(self, bld, program): - self.bld = bld + after = 'link' + def __init__(self, *args, **kwargs): + super(SuidBuild_task, self).__init__(*args, **kwargs) self.m_display = 'build-suid' - self.__program = program - self.__env = bld.env.copy () - super(SuidBuildTask, self).__init__(generator=self) try: - program_obj = wutils.find_program(self.__program.target, self.__env) + program_obj = wutils.find_program(self.generator.target, self.generator.env) except ValueError, ex: - raise Utils.WafError(str(ex)) - program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)) - self.filename = program_node.abspath(self.__env) + raise WafError(str(ex)) + program_node = program_obj.path.find_or_declare(program_obj.target) + self.filename = program_node.abspath() def run(self): @@ -561,6 +558,8 @@ class SuidBuildTask(Task.TaskBase): return Task.RUN_ME def create_suid_program(bld, name): + grp = bld.current_group + bld.add_group() # this to make sure no two sudo tasks run at the same time program = bld.new_task_gen(features=['cxx', 'cxxprogram']) program.is_ns3_program = True program.module_deps = list() @@ -568,7 +567,9 @@ def create_suid_program(bld, name): program.target = name if bld.env['ENABLE_SUDO']: - SuidBuildTask(bld, program) + program.create_task("SuidBuild") + + bld.set_group(grp) return program @@ -632,61 +633,29 @@ def _add_ns3_program_missing_deps(bld, program): program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') -from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext -class Ns3BuildContext(BuildContext): - cmd = 'build' - #variant = 'debug' # FIXME +def _get_all_task_gen(self): + for group in self.groups: + for taskgen in group: + yield taskgen - # @property - # def variant(self): - # if not self.all_envs: - # self.load_envs() - # return self.all_envs[''].NS3_ACTIVE_VARIANT - def get_all_task_gen(self): - for group in self.groups: - for taskgen in group: - yield taskgen - all_task_gen = property(get_all_task_gen) - - def get_taskgen(self, name): - for group in self.groups: - for taskgen in group: - if taskgen.name == name: - return taskgen - raise KeyError(name) - - def exclude_taskgen(self, taskgen): - # ok, so WAF does not provide an API to prevent an - # arbitrary taskgen from running; we have to muck around with - # WAF internal state, something that might stop working if - # WAF is upgraded... - for group in self.groups: - for tg1 in group: - if tg1 is taskgen: - group.remove(tg1) - break - else: - continue - break +# ok, so WAF does not provide an API to prevent an +# arbitrary taskgen from running; we have to muck around with +# WAF internal state, something that might stop working if +# WAF is upgraded... +def _exclude_taskgen(self, taskgen): + for group in self.groups: + for tg1 in group: + if tg1 is taskgen: + group.remove(tg1) + break + else: + continue + break def build(bld): - - - # switch to the variant matching our debug level - #variant_name = bld.env['NS3_ACTIVE_VARIANT'] - #print variant_name - #bld.variant = variant_name - #variant_env = bld.env_of_name(variant_name) - #bld.all_envs['default'] = variant_env - env = bld.env - #bld.variant = bld.env.NS3_ACTIVE_VARIANT - #bld.init_dirs() - #env = bld.env - #print "-----------------------------------------------------------------------" - #print env # If --enabled-modules option was given, then print a warning # message and exit this function. @@ -711,12 +680,12 @@ def build(bld): bld.create_ns3_program = types.MethodType(create_ns3_program, bld) bld.register_ns3_script = types.MethodType(register_ns3_script, bld) bld.create_suid_program = types.MethodType(create_suid_program, bld) + bld.__class__.all_task_gen = property(_get_all_task_gen) + bld.exclude_taskgen = types.MethodType(_exclude_taskgen, bld) # process subfolders from here bld.add_subdirs('src') - #env = bld.env - # If modules have been enabled, then set lists of enabled modules # and enabled module test libraries. if env['NS3_ENABLED_MODULES']: @@ -728,7 +697,7 @@ def build(bld): while changed: changed = False for module in modules: - module_obj = bld.name_to_obj(module, env) + module_obj = bld.get_tgen_by_name(module) if module_obj is None: raise ValueError("module %s not found" % module) # Each enabled module has its own library. @@ -758,7 +727,7 @@ def build(bld): for obj in list(bld.all_task_gen): # check for ns3moduleheader_taskgen - if type(obj).__name__ == 'ns3moduleheader_taskgen': + if 'ns3moduleheader' in getattr(obj, "features", []): if ("ns3-%s" % obj.module) not in modules: obj.mode = 'remove' # tell it to remove headers instead of installing @@ -787,7 +756,7 @@ def build(bld): bld.exclude_taskgen(obj) # kill the module test library # disable the ns3header_taskgen - if type(obj).__name__ == 'ns3header_taskgen': + if 'ns3header' in getattr(obj, "features", []): if ("ns3-%s" % obj.module) not in modules: obj.mode = 'remove' # tell it to remove headers instead of installing @@ -823,7 +792,7 @@ def build(bld): # we need to post() the ns3 modules, so they create libraries underneath, and programs can list them in uselib_local for module in sorted_ns3_modules: - gen = bld.name_to_obj(module, bld.env) + gen = bld.get_tgen_by_name(module) if type(gen).__name__ in ['ns3module_taskgen']: gen.post() for lib in gen.libs: From a16ebdd4ba87044e743c41d6a314a776d6acacc7 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 16:19:24 +0100 Subject: [PATCH 03/17] waf 1.6: bring back -Wl,--soname, fix waf warnings --- bindings/python/wscript | 4 ++-- src/wscript | 7 +++---- waf-tools/command.py | 5 +++-- wscript | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index 9f5a47e2c..7d6563e5b 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -309,7 +309,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 gchx' + before = 'cc cxx' color = "BLUE" def __init__(self, curdirnode, env, bld, target, cflags, module): self.bld = bld @@ -402,7 +402,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 gchx' + before = 'cc cxx' color = 'BLUE' def run(self): diff --git a/src/wscript b/src/wscript index 7b9759c4b..ba5d56e2c 100644 --- a/src/wscript +++ b/src/wscript @@ -195,6 +195,7 @@ def create_ns3_module(bld, name, dependencies=(), test=False): module = bld.new_task_gen(features=['cxx', 'cxxstlib', 'ns3module']) else: module = bld.new_task_gen(features=['cxx', 'cxxshlib', 'ns3module']) + module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(module.path), name) linkflags = [] cxxflags = [] ccflags = [] @@ -207,9 +208,8 @@ def create_ns3_module(bld, name, dependencies=(), test=False): # Get the module library name without any relative paths # at its beginning because all of the libraries will end # up in the same directory. - if 0: # TODO FIXME - module_library_name = os.path.basename(ccroot.get_target_name(module)) - linkflags = '-Wl,--soname=%s' % module_library_name + module_library_name = module.env.cshlib_PATTERN % (os.path.basename(module.target),) + linkflags = '-Wl,--soname=' + module_library_name elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \ os.uname()[4] == 'x86_64' and \ sys.platform != 'darwin' and \ @@ -231,7 +231,6 @@ def create_ns3_module(bld, name, dependencies=(), test=False): module.is_static = static module.vnum = wutils.VNUM # Add the proper path to the module's name. - module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(module.path), name) # Set the libraries this module depends on. module.module_deps = list(dependencies) diff --git a/waf-tools/command.py b/waf-tools/command.py index 5953a6695..9066e0abb 100644 --- a/waf-tools/command.py +++ b/waf-tools/command.py @@ -104,8 +104,9 @@ class command_task(Task.Task): @TaskGen.feature('command') def init_command(self): Utils.def_attrs(self, - # other variables that can be used in the command: ${VARIABLE} - variables = None) + # other variables that can be used in the command: ${VARIABLE} + variables = None, + rule='') diff --git a/wscript b/wscript index 8801483c6..557879b88 100644 --- a/wscript +++ b/wscript @@ -894,7 +894,7 @@ def check(bld): wutils.run_python_program("test.py -n -c core", env) class print_introspected_doxygen_task(Task.TaskBase): - after = 'cc cxx cc_link cxx_link' + after = 'cc cxx link' color = 'BLUE' def __init__(self, bld): @@ -925,7 +925,7 @@ class print_introspected_doxygen_task(Task.TaskBase): out.close() class run_python_unit_tests_task(Task.TaskBase): - after = 'cc cxx cc_link cxx_link' + after = 'cc cxx link' color = 'BLUE' def __init__(self, bld): From 4e3855f771430c57d8474280f5b39b3610a0d9d1 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 18:54:57 +0100 Subject: [PATCH 04/17] waf 1.6: fix python bindings apiscan --- bindings/python/wscript | 32 ++++++++++++++++++-------------- src/wscript | 3 +++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index 7d6563e5b..8c0c3d2bb 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -288,19 +288,18 @@ int main () def get_headers_map(bld): headers_map = {} # header => module for ns3headers in bld.all_task_gen: - if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare + if 'ns3header' in getattr(ns3headers, "features", []): if ns3headers.module.endswith('-test'): continue - for h in ns3headers.to_list(ns3headers.source): + for h in ns3headers.to_list(ns3headers.headers): headers_map[os.path.basename(h)] = ns3headers.module return headers_map def get_module_path(bld, module): for ns3headers in bld.all_task_gen: - if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare + if 'ns3header' in getattr(ns3headers, "features", []): if ns3headers.module == module: break - else: raise ValueError("Module %r not found" % module) return ns3headers.path.abspath() @@ -309,7 +308,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' + before = 'cc cxx command' color = "BLUE" def __init__(self, curdirnode, env, bld, target, cflags, module): self.bld = bld @@ -324,7 +323,7 @@ class apiscan_task(Task.TaskBase): return 'api-scan-%s\n' % (self.target,) def run(self): - top_builddir = self.curdirnode.find_dir('../..').abspath(self.env) + top_builddir = self.bld.bldnode.abspath() module_path = get_module_path(self.bld, self.module) headers_map = get_headers_map(self.bld) scan_header = os.path.join(top_builddir, "ns3", "%s-module.h" % self.module) @@ -334,7 +333,7 @@ class apiscan_task(Task.TaskBase): return 0 argv = [ - self.env['PYTHON'], + self.env['PYTHON'][0], os.path.join(self.curdirnode.abspath(), 'ns3modulescan-modular.py'), # scanning script top_builddir, self.module, @@ -364,11 +363,11 @@ def get_modules_and_headers(bld): ## find the headers object for this module headers = [] for ns3headers in bld.all_task_gen: - if type(ns3headers).__name__ != 'ns3header_taskgen': # XXX: find less hackish way to compare + if 'ns3header' not in getattr(ns3headers, "features", []): continue if ns3headers.module != module_name: continue - for source in ns3headers.to_list(ns3headers.source): + for source in ns3headers.to_list(ns3headers.headers): headers.append(os.path.basename(source)) retval[module_name] = (list(module.module_deps), headers) return retval @@ -395,7 +394,8 @@ class python_scan_task_collector(Task.TaskBase): # signal stop (we generated files into the source dir and WAF # can't cope with it, so we have to force the user to restart # WAF) - self.bld.generator.stop = 1 + self.bld.producer.stop = 1 + self.bld.producer.free_task_pool() return 0 @@ -407,7 +407,7 @@ class gen_ns3_compat_pymod_task(Task.Task): def run(self): assert len(self.outputs) == 1 - outfile = file(self.outputs[0].abspath(self.env), "w") + outfile = file(self.outputs[0].abspath(), "w") print >> outfile, "import warnings" print >> outfile, 'warnings.warn("the ns3 module is a compatibility layer '\ 'and should not be used in newly written code", DeprecationWarning, stacklevel=2)' @@ -466,16 +466,20 @@ def build(bld): scan_modules = Options.options.apiscan.split(',') print "Modules to scan: ", scan_modules for target, cflags in scan_targets: + group = bld.get_group(bld.current_group) for module in scan_modules: - apiscan_task(bld.path, env, bld, target, cflags, module) - python_scan_task_collector(bld.path, env, bld) + group.append(apiscan_task(bld.path, env, bld, target, cflags, module)) + group.append(python_scan_task_collector(bld.path, env, bld)) return if env['ENABLE_PYTHON_BINDINGS']: - task = gen_ns3_compat_pymod_task(env=env) + task = gen_ns3_compat_pymod_task(env=env.derive()) task.set_outputs(bld.path.find_or_declare("ns3.py")) task.dep_vars = ['PYTHON_MODULES_BUILT'] + task.bld = bld + grp = bld.get_group(bld.current_group) + grp.append(task) # note: the actual build commands for the python bindings are in # src/wscript, not here. diff --git a/src/wscript b/src/wscript index ba5d56e2c..011b24426 100644 --- a/src/wscript +++ b/src/wscript @@ -291,6 +291,9 @@ def create_obj(bld, *args): def ns3_python_bindings(bld): + if Options.options.apiscan: + return + # this method is called from a module wscript, so remember bld.path is not bindings/python! module_abs_src_path = bld.path.abspath() module = os.path.basename(module_abs_src_path) From ba4ab5a12b7917ca62693f017d6952c8bf91b34b Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 18:57:10 +0100 Subject: [PATCH 05/17] Remove the --enable-shared-and-static option --- wscript | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/wscript b/wscript index 557879b88..475c9f4ae 100644 --- a/wscript +++ b/wscript @@ -208,10 +208,6 @@ def options(opt): help=('Compile NS-3 statically: works only on linux, without python'), dest='enable_static', action='store_true', default=False) - opt.add_option('--enable-shared-and-static', - help=('Compile NS-3 both shared and static libraries at the same time: static works only on linux'), - dest='enable_shared_and_static', action='store_true', - default=False) opt.add_option('--enable-mpi', help=('Compile NS-3 with MPI and distributed simulation support'), dest='enable_mpi', action='store_true', @@ -332,7 +328,7 @@ def configure(conf): env['WL_SONAME_SUPPORTED'] = True env['ENABLE_STATIC_NS3'] = False - if Options.options.enable_static or Options.options.enable_shared_and_static: + if Options.options.enable_static: if env['PLATFORM'].startswith('linux') and \ env['CXX_NAME'] in ['gcc', 'icc']: if re.match('i[3-6]86', os.uname()[4]): @@ -357,8 +353,6 @@ def configure(conf): conf.report_optional_feature("static", "Static build", True, '') if Options.options.enable_static: env['ENABLE_STATIC_NS3'] = True - if Options.options.enable_shared_and_static: - env['ENABLE_SHARED_AND_STATIC_NS3'] = True else: conf.report_optional_feature("static", "Static build", False, "Unsupported platform") From 1938704a9ad87e908856d9ad84cc2c2f21fc19ba Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 19:04:36 +0100 Subject: [PATCH 06/17] Clean some dead waf code --- src/wscript | 104 ++---------------------------------------- wscript | 127 ---------------------------------------------------- 2 files changed, 4 insertions(+), 227 deletions(-) diff --git a/src/wscript b/src/wscript index 011b24426..624502bd9 100644 --- a/src/wscript +++ b/src/wscript @@ -13,10 +13,6 @@ import Task import Options import Build import Utils -#import Constants - -#import ccroot -#ccroot.USE_TOP_LEVEL = True import wutils @@ -105,87 +101,12 @@ def configure(conf): conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] -# class ns3module_taskgen(TaskGen.task_gen): -# def __init__(self, *args, **kwargs): -# super(ns3module_taskgen, self).__init__(*args, **kwargs) -# self.libs = [] - -# def apply(self): -# print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -# static_enabled = False -# shared_enabled = True -# bld = self.bld -# if bld.env['ENABLE_STATIC_NS3']: -# static_enabled = True -# shared_enabled = False -# if bld.env['ENABLE_SHARED_AND_STATIC_NS3']: -# static_enabled = True -# shared_enabled = True - -# assert self.name.startswith("ns3-") -# name = self.name.split("ns3-")[1] - -# if static_enabled: -# static = self._create_ns3_module(self.bld, name, self.dependencies, True) -# self.libs.append(static) -# else: -# static = None - -# if shared_enabled: -# shared = self._create_ns3_module(self.bld, name, self.dependencies, False) -# self.libs.append(shared) -# else: -# shared = None - -# if static is not None and shared is None: -# static.name = self.name + "--lib" -# static.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] - -# elif shared is not None and static is None: -# shared.name = self.name + "--lib" -# shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] -# else: -# shared.name = self.name + "--lib" -# shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies] -# static.name = self.name + "--static" -# static.uselib_local = ['ns3-%s--static' % (dep,) for dep in self.dependencies] - -# if not self.test: -# pcfile = bld.new_task_gen('ns3pcfile') -# pcfile.module = self - -# def _create_ns3_module(self, bld, name, dependencies, static): - -# # FIXME: env modifications are overwritten by parent caller - +# we need the 'ns3module' waf "feature" to be created because code +# elsewhere looks for it to find the ns3 module objects. @TaskGen.feature('ns3module') -@TaskGen.after_method('process_rule') def _add_test_code(module): - bld = module.bld - if 0: #len(module.source) > 0 and hasattr(module, 'ns3_dir_location'): - uselib_cpppath = [] - for lib in module.uselib.split(): - if 'CPPPATH_%s' % lib in module.env: - uselib_cpppath.extend(module.env['CPPPATH_%s' % lib]) - objects = [] - for src in module.source[0:-1]: - full_src = os.path.join(module.ns3_dir_location, src) - path = os.path.dirname(full_src) - target = '%s_object' % src - # XXX: calculate the features correctly here. - obj = bld.objects(source=[full_src], target=target, features='cxx cc', - env = module.env.copy()) - obj.env.CXXDEFINES += 'NS_TEST_SOURCEDIR="%s"' % path - obj.env.INCLUDES += uselib_cpppath - obj.name = module.name + '--test' - objects.append(target) - last = module.source[-1] - full_src = os.path.join(module.ns3_dir_location, last) - path = os.path.dirname(full_src) - module.env.CXXDEFINES += 'NS_TEST_SOURCEDIR="%s"' % path - module.source = [last] + objects - #module.add_objects.extend(objects) + pass def create_ns3_module(bld, name, dependencies=(), test=False): @@ -522,31 +443,13 @@ class ns3pcfile_taskgen(TaskGen.task_gen): task.module = self.module -# @TaskGen.extension('.h') -# class ns3header_taskgen(TaskGen.task_gen): -# """A set of NS-3 header files""" -# COLOR = 'BLUE' -# def __init__(self, *args, **kwargs): -# super(ns3header_taskgen, self).__init__(*args, **kwargs) -# self.install_path = None -# self.sub_dir = None # if not None, header files will be published as ns3/sub_dir/file.h -# self.module = None # module name -# self.mode = 'install' -# self.features.append(features=['ns3header']) -# print "YYYYYYYYYYYYYYYYYYYYYYYYYYY", self - @TaskGen.feature('ns3header') @TaskGen.after_method('process_rule') def apply_ns3header(self): - #for filename in set(self.to_list(self.source)): - # src_node = self.path.find_resource(filename) if self.module is None: raise Utils.WafError("'module' missing on ns3headers object %s" % self) ns3_dir_node = self.bld.path.find_dir("ns3") - #if self.sub_dir is not None: - # ns3_dir_node = ns3_dir_node.find_dir(self.sub_dir) - for filename in set(self.to_list(self.source)): src_node = self.path.find_resource(filename) if src_node is None: @@ -564,6 +467,7 @@ def apply_ns3header(self): self.headers = set(self.to_list(self.source)) self.source = '' # tell WAF not to process these files further + class ns3header_task(Task.Task): before = 'cc cxx gen_ns3_module_header' color = 'BLUE' diff --git a/wscript b/wscript index 475c9f4ae..70b1265d7 100644 --- a/wscript +++ b/wscript @@ -16,13 +16,8 @@ import Options import Logs import TaskGen -#import Constants - -#import ccroot -#ccroot.USE_TOP_LEVEL = True import Task -#Task.algotype = Constants.JOBCONTROL # so that Task.maxjobs=1 takes effect import Utils import Build @@ -280,15 +275,6 @@ def configure(conf): conf.check_tool('command', ['waf-tools']) conf.check_tool('gnu_dirs') - #if os.path.exists('/usr/lib64'): - # conf.env.LIBDIR = os.path.join(conf.env.PREFIX, "lib64") - - - # variant_name = Options.options.build_profile - # if Options.options.enable_gcov: - # variant_name += '-gcov' - # conf.env['NS3_ACTIVE_VARIANT'] = variant_name - # conf.setenv(variant_name, env=conf.env.derive()) # start with a copy instead of a new env env = conf.env if Options.options.enable_gcov: @@ -1055,116 +1041,3 @@ def lcov_report(): finally: os.chdir("..") -## -## The default WAF DistDir implementation is rather slow, because it -## first copies everything and only later removes unwanted files and -## directories; this means that it needless copies the full build dir -## and the .hg repository tree. Here we provide a replacement DistDir -## implementation that is more efficient. -## -# import Scripting -# from Scripting import dist_exts, excludes, BLDDIR -# import Utils -# import os - -# def _copytree(src, dst, symlinks=False, excludes=(), build_dir=None): -# """Recursively copy a directory tree using copy2(). - -# The destination directory must not already exist. -# If exception(s) occur, an Error is raised with a list of reasons. - -# If the optional symlinks flag is true, symbolic links in the -# source tree result in symbolic links in the destination tree; if -# it is false, the contents of the files pointed to by symbolic -# links are copied. - -# XXX Consider this example code rather than the ultimate tool. - -# Note: this is a modified version of shutil.copytree from python -# 2.5.2 library; modified for WAF purposes to exclude dot dirs and -# another list of files. -# """ -# names = os.listdir(src) -# os.makedirs(dst) -# errors = [] -# for name in names: -# srcname = os.path.join(src, name) -# dstname = os.path.join(dst, name) -# try: -# if symlinks and os.path.islink(srcname): -# linkto = os.readlink(srcname) -# os.symlink(linkto, dstname) -# elif os.path.isdir(srcname): -# if name in excludes: -# continue -# elif name.startswith('.') or name.startswith(',,') or name.startswith('++') or name.startswith('CVS'): -# continue -# elif name == build_dir: -# continue -# else: -# ## build_dir is not passed into the recursive -# ## copytree, but that is intentional; it is a -# ## directory name valid only at the top level. -# copytree(srcname, dstname, symlinks, excludes) -# else: -# ends = name.endswith -# to_remove = False -# if name.startswith('.') or name.startswith('++'): -# to_remove = True -# else: -# for x in dist_exts: -# if ends(x): -# to_remove = True -# break -# if not to_remove: -# shutil.copy2(srcname, dstname) -# # XXX What about devices, sockets etc.? -# except (IOError, os.error), why: -# errors.append((srcname, dstname, str(why))) -# # catch the Error from the recursive copytree so that we can -# # continue with other files -# except shutil.Error, err: -# errors.extend(err.args[0]) -# try: -# shutil.copystat(src, dst) -# except WindowsError: -# # can't copy file access times on Windows -# pass -# except OSError, why: -# errors.extend((src, dst, str(why))) -# if errors: -# raise shutil.Error, errors - - -# def DistDir(appname, version): -# #"make a distribution directory with all the sources in it" -# import shutil - -# # Our temporary folder where to put our files -# TMPFOLDER=appname+'-'+version - -# # Remove an old package directory -# if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) - -# global g_dist_exts, g_excludes - -# # Remove the Build dir -# build_dir = getattr(Utils.g_module, BLDDIR, None) - -# # Copy everything into the new folder -# _copytree('.', TMPFOLDER, excludes=excludes, build_dir=build_dir) - -# # TODO undocumented hook -# dist_hook = getattr(Utils.g_module, 'dist_hook', None) -# if dist_hook: -# os.chdir(TMPFOLDER) -# try: -# dist_hook() -# finally: -# # go back to the root directory -# os.chdir('..') -# return TMPFOLDER - -# Scripting.DistDir = DistDir - - From 49c1b1e0fd3f496a9d1d7b188f93c4c302b5a9de Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 12 Sep 2011 19:19:00 +0100 Subject: [PATCH 07/17] Fix the --lcov-report option --- wscript | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/wscript b/wscript index 70b1265d7..af94866af 100644 --- a/wscript +++ b/wscript @@ -278,6 +278,7 @@ def configure(conf): env = conf.env if Options.options.enable_gcov: + env['GCOV_ENABLED'] = True env.append_value('CCFLAGS', '-fprofile-arcs') env.append_value('CCFLAGS', '-ftest-coverage') env.append_value('CXXFLAGS', '-fprofile-arcs') @@ -846,7 +847,7 @@ def shutdown(ctx): out.close() if Options.options.lcov_report: - lcov_report() + lcov_report(bld) if Options.options.run: wutils.run_program(Options.options.run, env, wutils.get_command_template(env), @@ -1009,28 +1010,26 @@ def doxygen(bld): Scripting.build(bld) _doxygen(bld) -def lcov_report(): - env = Build.bld.env - variant_name = env['NS3_ACTIVE_VARIANT'] +def lcov_report(bld): + env = bld.env - if 'gcov' not in variant_name: - raise Utils.WafError("project not configured for code coverage;" - " reconfigure with --enable-gcov") + if not env['GCOV_ENABLED']: + raise WafError("project not configured for code coverage;" + " reconfigure with --enable-gcov") - os.chdir(blddir) + os.chdir(out) try: - lcov_report_dir = os.path.join(variant_name, 'lcov-report') + lcov_report_dir = 'lcov-report' create_dir_command = "rm -rf " + lcov_report_dir create_dir_command += " && mkdir " + lcov_report_dir + ";" if subprocess.Popen(create_dir_command, shell=True).wait(): raise SystemExit(1) - info_file = os.path.join(lcov_report_dir, variant_name + '.info') + info_file = os.path.join(lcov_report_dir, 'report.info') lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file lcov_command += " --source-dirs=" + os.getcwd() - lcov_command += ":" + os.path.join( - os.getcwd(), variant_name, 'include') + lcov_command += ":" + os.path.join(os.getcwd(), 'include') if subprocess.Popen(lcov_command, shell=True).wait(): raise SystemExit(1) From e8aeb9c6ce7d16e44934d125c14b48855abbbc9b Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 13 Sep 2011 13:47:17 +0100 Subject: [PATCH 08/17] waf-1.6: Mac OSX and other fixes --- bindings/python/wscript | 26 +++++++++++++++++++++----- src/core/model/int64x64-128.h | 2 +- src/emu/wscript | 2 +- src/openflow/wscript | 24 ++++++++++++++---------- src/tap-bridge/wscript | 2 +- src/visualizer/wscript | 4 ++-- src/wscript | 4 ++-- wscript | 15 +++++++++------ 8 files changed, 51 insertions(+), 28 deletions(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index 8c0c3d2bb..9681e245f 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -14,6 +14,8 @@ import Logs import Build import Utils +from waflib.Errors import WafError + ## https://launchpad.net/pybindgen/ REQUIRED_PYBINDGEN_VERSION = (0, 15, 0, 795) REQUIRED_PYGCCXML_VERSION = (0, 9, 5) @@ -52,10 +54,6 @@ def options(opt): help=("Don't build Python bindings."), action="store_true", default=False, dest='python_disable') - opt.add_option('--python-scan', - help=("Rescan Python bindings. Needs working GCCXML / pygccxml environment."), - action="store_true", default=False, - dest='python_scan') opt.add_option('--apiscan', help=("EXPERIMENTAL: Rescan the API for the indicated module(s), for Python bindings. " "Needs working GCCXML / pygccxml environment. " @@ -103,6 +101,21 @@ def configure(conf): conf.report_optional_feature("python", "Python Bindings", False, str(ex)) return + # stupid Mac OSX Python wants to build extensions as "universal + # binaries", i386, x86_64, and ppc, but this way the type + # __uint128_t is not available. We need to disable the multiarch + # crap by removing the -arch parameters. + for flags_var in ["CFLAGS_PYEXT", "CFLAGS_PYEMBED", "CXXFLAGS_PYEMBED", + "CXXFLAGS_PYEXT", "LINKFLAGS_PYEMBED", "LINKFLAGS_PYEXT"]: + flags = conf.env[flags_var] + i = 0 + while i < len(flags): + if flags[i] == '-arch': + del flags[i] + del flags[i] + continue + i += 1 + conf.env[flags_var] = flags if 0: # alternative code to computing PYTHONDIR, that is more correct than the one in waf 1.5.16 @@ -261,7 +274,10 @@ int main () ## Check gccxml version - gccxml = conf.find_program('gccxml', var='GCCXML') + try: + gccxml = conf.find_program('gccxml', var='GCCXML') + except WafError: + gccxml = None if not gccxml: Logs.warn("gccxml missing; automatic scanning of API definitions will not be possible") conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, diff --git a/src/core/model/int64x64-128.h b/src/core/model/int64x64-128.h index d1a60c605..a116b8874 100644 --- a/src/core/model/int64x64-128.h +++ b/src/core/model/int64x64-128.h @@ -6,7 +6,7 @@ #include #include -#if defined(HAVE___UINT128_T)and !defined(HAVE_UINT128_T) +#if defined(HAVE___UINT128_T) && !defined(HAVE_UINT128_T) typedef __uint128_t uint128_t; typedef __int128_t int128_t; #endif diff --git a/src/emu/wscript b/src/emu/wscript index b48b012b8..43c51106d 100644 --- a/src/emu/wscript +++ b/src/emu/wscript @@ -4,7 +4,7 @@ import os.path def configure(conf): if conf.env['ENABLE_THREADING']: - conf.env['ENABLE_EMU'] = conf.check(header_name='netpacket/packet.h', + conf.env['ENABLE_EMU'] = conf.check_nonfatal(header_name='netpacket/packet.h', define_name='HAVE_PACKET_H') conf.report_optional_feature("EmuNetDevice", "Emulated Net Device", conf.env['ENABLE_EMU'], diff --git a/src/openflow/wscript b/src/openflow/wscript index 4a639f7d5..d5580282a 100644 --- a/src/openflow/wscript +++ b/src/openflow/wscript @@ -2,6 +2,7 @@ import os import Options +from waflib.Errors import WafError def options(opt): opt.add_option('--with-openflow', @@ -10,17 +11,20 @@ def options(opt): opt.tool_options('boost', tooldir=["waf-tools"]) def configure(conf): - conf.check_tool('boost') - conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem', - kind = 'STATIC_BOTH', - score_version = (-1000, 1000), - tag_minscore = 1000) - if not conf.env['BOOST']: + try: + conf.check_tool('boost') conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem', - kind = 'STATIC_BOTH', - score_version = (-1000, 1000), - tag_minscore = 1000, - libpath="/usr/lib64") + kind = 'STATIC_BOTH', + score_version = (-1000, 1000), + tag_minscore = 1000) + if not conf.env['BOOST']: + conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem', + kind = 'STATIC_BOTH', + score_version = (-1000, 1000), + tag_minscore = 1000, + libpath="/usr/lib64") + except WafError: + conf.env['BOOST'] = False if not conf.env['BOOST']: conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False, diff --git a/src/tap-bridge/wscript b/src/tap-bridge/wscript index 913843232..ab1376b60 100644 --- a/src/tap-bridge/wscript +++ b/src/tap-bridge/wscript @@ -4,7 +4,7 @@ import os.path def configure(conf): if conf.env['ENABLE_THREADING']: - conf.env['ENABLE_TAP'] = conf.check(header_name='linux/if_tun.h', + conf.env['ENABLE_TAP'] = conf.check_nonfatal(header_name='linux/if_tun.h', define_name='HAVE_IF_TUN_H') conf.report_optional_feature("TapBridge", "Tap Bridge", conf.env['ENABLE_TAP'], diff --git a/src/visualizer/wscript b/src/visualizer/wscript index dbfbd5e62..8857f458e 100644 --- a/src/visualizer/wscript +++ b/src/visualizer/wscript @@ -36,8 +36,8 @@ def build(bld): return module.features.append('pyembed') - module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS']) - module.includes = '.' + #module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS']) + #module.includes = '.' module.source.extend([ 'model/pyviz.cc', diff --git a/src/wscript b/src/wscript index 624502bd9..0e670d332 100644 --- a/src/wscript +++ b/src/wscript @@ -308,14 +308,14 @@ def ns3_python_bindings(bld): #mod = mod.split("--lib")[0] pymod.env.append_value('LINKFLAGS', '-l' + mod) pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') - defines = list(pymod.env['CXXDEFINES']) + defines = list(pymod.env['DEFINES']) defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H']) if Options.platform == 'win32': try: defines.remove('_DEBUG') # causes undefined symbols on win32 except ValueError: pass - pymod.env['CXXDEFINES'] = defines + pymod.env['DEFINES'] = defines pymod.includes = '# bindings' pymod.install_path = '${PYTHONDIR}/ns' return pymod diff --git a/wscript b/wscript index af94866af..29b3b5395 100644 --- a/wscript +++ b/wscript @@ -24,6 +24,8 @@ import Build import Configure import Scripting +from waflib.Errors import WafError + from utils import read_config_file # By default, all modules will be enabled, examples will be disabled, @@ -286,8 +288,8 @@ def configure(conf): env.append_value('LINKFLAGS', '-fprofile-arcs') if Options.options.build_profile == 'debug': - env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') - env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE') + env.append_value('DEFINES', 'NS3_ASSERT_ENABLE') + env.append_value('DEFINES', 'NS3_LOG_ENABLE') env['PLATFORM'] = sys.platform @@ -467,12 +469,10 @@ def configure(conf): conf.env['ENABLE_GSL'], "GSL not found") if have_gsl: - conf.env.append_value('CXXDEFINES', "ENABLE_GSL") - conf.env.append_value('CCDEFINES', "ENABLE_GSL") + conf.env.append_value('DEFINES', "ENABLE_GSL") # for compiling C code, copy over the CXX* flags conf.env.append_value('CCFLAGS', conf.env['CXXFLAGS']) - conf.env.append_value('CCDEFINES', conf.env['CXXDEFINES']) def add_gcc_flag(flag): if env['COMPILER_CXX'] == 'g++' and 'CXXFLAGS' not in os.environ: @@ -486,7 +486,10 @@ def configure(conf): add_gcc_flag('-fstrict-aliasing') add_gcc_flag('-Wstrict-aliasing') - conf.find_program('doxygen', var='DOXYGEN') + try: + conf.find_program('doxygen', var='DOXYGEN') + except WafError: + pass # append user defined flags after all our ones for (confvar, envvar) in [['CCFLAGS', 'CCFLAGS_EXTRA'], From 94fffe6305887d3dbd73b8ce30787f0456c53e9a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 13 Sep 2011 17:21:44 +0100 Subject: [PATCH 09/17] waf1.6: remove code not needed, fix static build, cleanup --- wscript | 56 ++++++++++++-------------------------------------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/wscript b/wscript index 29b3b5395..0e2778628 100644 --- a/wscript +++ b/wscript @@ -565,6 +565,13 @@ def create_ns3_program(bld, name, dependencies=('core',)): # Each of the modules this program depends on has its own library. program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies] program.includes = "# #/.." + program.use = program.ns3_module_dependencies + if program.env['ENABLE_STATIC_NS3']: + if sys.platform == 'darwin': + program.env.STLIB_MARKER = '-Wl,-all_load' + else: + program.env.STLIB_MARKER = '-Wl,--whole-archive,-Bstatic' + program.env.SHLIB_MARKER = '-Wl,-Bdynamic,--no-whole-archive' return program def register_ns3_script(bld, name, dependencies=('core',)): @@ -601,22 +608,6 @@ def add_scratch_programs(bld): obj.name = obj.target -def _add_ns3_program_missing_deps(bld, program): - deps_found = program.ns3_module_dependencies - program.use = getattr(program, "use", []) + [dep #+ "--lib" - for dep in deps_found] - if program.env['ENABLE_STATIC_NS3']: - if sys.platform == 'darwin': - program.env.append_value('LINKFLAGS', '-Wl,-all_load') - for dep in deps_found: - program.env.append_value('LINKFLAGS', '-l' + dep) - else: - program.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic') - for dep in deps_found: - program.env.append_value('LINKFLAGS', '-l' + dep) - program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') - - def _get_all_task_gen(self): for group in self.groups: for taskgen in group: @@ -762,35 +753,10 @@ def build(bld): bld.add_subdirs('bindings/python') - ## do a topological sort on the modules graph - dep_graph = [] - for gen in bld.all_task_gen: - if type(gen).__name__ in ['ns3module_taskgen']: - for dep in gen.dependencies: - dep_graph.append(("ns3-"+dep, gen.name)) - dep_graph.sort() - sys.path.insert(0, "bindings/python") - from topsort import topsort - sorted_ns3_modules = topsort(dep_graph) - #print sorted_ns3_modules - - # we need to post() the ns3 modules, so they create libraries underneath, and programs can list them in uselib_local - for module in sorted_ns3_modules: - gen = bld.get_tgen_by_name(module) - if type(gen).__name__ in ['ns3module_taskgen']: - gen.post() - for lib in gen.libs: - lib.post() - # Process this subfolder here after the lists of enabled modules # and module test libraries have been set. bld.add_subdirs('utils') - for gen in bld.all_task_gen: - if not getattr(gen, "is_ns3_program", False) or not hasattr(gen, "ns3_module_dependencies"): - continue - _add_ns3_program_missing_deps(bld, gen) - if Options.options.run: # Check that the requested program name is valid program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, wutils.get_command_template(env)) @@ -807,6 +773,8 @@ def build(bld): _doxygen(bld) raise SystemExit(0) + + def shutdown(ctx): bld = wutils.bld if wutils.bld is None: @@ -836,8 +804,7 @@ def shutdown(ctx): print # Write the build status file. - build_status_file = os.path.join(bld.out_dir, #env['NS3_ACTIVE_VARIANT'], - 'build-status.py') + build_status_file = os.path.join(bld.out_dir, 'build-status.py') out = open(build_status_file, 'w') out.write('#! /usr/bin/env python\n') out.write('\n') @@ -870,13 +837,14 @@ def shutdown(ctx): check_shell(bld) -check_context = Build.BuildContext +check_context = Build.BuildContext def check(bld): """run the equivalent of the old ns-3 unit tests using test.py""" env = wutils.bld.env wutils.run_python_program("test.py -n -c core", env) + class print_introspected_doxygen_task(Task.TaskBase): after = 'cc cxx link' color = 'BLUE' From 7905163b14da8f5f5074070bc729b741df457989 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 13 Sep 2011 17:50:05 +0100 Subject: [PATCH 10/17] waf1.6: make the all_modules in src/wscript be automatically discovered --- src/wscript | 82 ++++++++++++++--------------------------------------- wscript | 8 +++--- 2 files changed, 26 insertions(+), 64 deletions(-) diff --git a/src/wscript b/src/wscript index 0e670d332..a5c08d052 100644 --- a/src/wscript +++ b/src/wscript @@ -21,53 +21,21 @@ try: except NameError: from sets import Set as set # Python 2.3 fallback -all_modules = [ - 'core', - 'network', - 'config-store', - 'internet', - 'propagation', - 'point-to-point', - 'csma', - 'emu', - 'bridge', - 'tap-bridge', - 'virtual-net-device', - 'applications', - 'nix-vector-routing', - 'olsr', - 'aodv', - 'dsdv', - 'click', - 'openflow', - 'mobility', - 'wifi', - 'netanim', - 'stats', - 'uan', - 'spectrum', - 'mesh', - 'test', - 'test/ns3tcp', - 'test/ns3wifi', - 'flow-monitor', - 'wimax', - 'lte', - 'mpi', - 'topology-read', - 'energy', - 'tools', - 'visualizer', - 'point-to-point-layout', - 'csma-layout', - 'template', - ] + +all_modules = [] +for dirname in os.listdir('src'): + if dirname.startswith('.') or dir == 'CVS': + continue + path = os.path.join('src', dirname) + if not os.path.isdir(path): + continue + if os.path.exists(os.path.join(path, 'wscript')): + all_modules.append(dirname) +all_modules.sort() + + def options(opt): - opt.sub_options('core') - opt.sub_options('click') - opt.sub_options('openflow') - opt.add_option('--enable-rpath', help=("Link programs with rpath" " (normally not needed, see " @@ -79,18 +47,13 @@ def options(opt): help=("Build only these modules (and dependencies)"), dest='enable_modules') + for module in all_modules: + opt.sub_options(module, mandatory=False) + + def configure(conf): - conf.sub_config('core') - conf.sub_config('emu') - conf.sub_config('tap-bridge') - conf.sub_config('config-store') - conf.sub_config('internet') - conf.sub_config('netanim') - conf.sub_config('test') - conf.sub_config('click') - conf.sub_config('openflow') - conf.sub_config('stats') - conf.sub_config('visualizer') + for module in all_modules: + conf.sub_config(module, mandatory=False) blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) conf.env.append_value('NS3_MODULE_PATH', blddir) @@ -157,7 +120,6 @@ def create_ns3_module(bld, name, dependencies=(), test=False): module.install_path = "${LIBDIR}" - module.bld = bld module.name = "ns3-" + name module.dependencies = dependencies # Initially create an empty value for this because the pcfile @@ -448,12 +410,12 @@ class ns3pcfile_taskgen(TaskGen.task_gen): @TaskGen.after_method('process_rule') def apply_ns3header(self): if self.module is None: - raise Utils.WafError("'module' missing on ns3headers object %s" % self) + raise WafError("'module' missing on ns3headers object %s" % self) ns3_dir_node = self.bld.path.find_dir("ns3") for filename in set(self.to_list(self.source)): src_node = self.path.find_resource(filename) if src_node is None: - raise Utils.WafError("source ns3 header file %s not found" % (filename,)) + raise WafError("source ns3 header file %s not found" % (filename,)) dst_node = ns3_dir_node.find_or_declare(src_node.name) assert dst_node is not None task = self.create_task('ns3header') @@ -638,7 +600,7 @@ def apply_ns3moduleheader(self): fatal("missing header file %s" % (source,)) all_headers_inputs.append(node) if not found_the_module: - raise Utils.WscriptError("error finding headers for module %s" % self.module) + raise WafError("error finding headers for module %s" % self.module) if not all_headers_inputs: return diff --git a/wscript b/wscript index 0e2778628..e94d3eba8 100644 --- a/wscript +++ b/wscript @@ -381,7 +381,7 @@ def configure(conf): if not_built_name in conf.env['NS3_ENABLED_MODULES']: conf.env['NS3_ENABLED_MODULES'].remove(not_built_name) if not conf.env['NS3_ENABLED_MODULES']: - raise Utils.WafError('Exiting because the ' + not_built + ' module can not be built and it was the only one enabled.') + raise WafError('Exiting because the ' + not_built + ' module can not be built and it was the only one enabled.') conf.sub_config('bindings/python') @@ -830,10 +830,10 @@ def shutdown(ctx): raise SystemExit(0) if Options.options.shell: - raise Utils.WafError("Please run `./waf shell' now, instead of `./waf --shell'") + raise WafError("Please run `./waf shell' now, instead of `./waf --shell'") if Options.options.check: - raise Utils.WafError("Please run `./test.py' now, instead of `./waf --check'") + raise WafError("Please run `./test.py' now, instead of `./waf --check'") check_shell(bld) @@ -913,7 +913,7 @@ def check_shell(bld): "You should correct this situation before running any program. Possible solutions:\n" " 1. Exit this shell, and start a new one\n" " 2. Run a new nested shell") - raise Utils.WafError(msg) + raise WafError(msg) from waflib import Context, Build From bf815a25917fddf4ad32d42e0455a060ebb6d207 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 13 Sep 2011 18:51:45 +0100 Subject: [PATCH 11/17] Add a script to help create new ns-3 modules --- .hgignore | 2 +- src/create-module.py | 207 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 1 deletion(-) create mode 100755 src/create-module.py diff --git a/.hgignore b/.hgignore index ba9effb2d..97329aa78 100644 --- a/.hgignore +++ b/.hgignore @@ -7,7 +7,7 @@ ^testpy-output ^doc/html ^doc/latex -^\.lock-wscript +^\.lock-wafbuild ^\.waf ^doc/introspected-doxygen\.h$ .*\.py[co]$ diff --git a/src/create-module.py b/src/create-module.py new file mode 100755 index 000000000..38622662b --- /dev/null +++ b/src/create-module.py @@ -0,0 +1,207 @@ +#! /usr/bin/env python +import sys +from optparse import OptionParser +import os + + +WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +# def options(opt): +# pass + +# def configure(conf): +# conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H') + +def build(bld): + module = bld.create_ns3_module(%(MODULE)r, ['core']) + module.source = [ + 'model/%(MODULE)s.cc', + 'helper/%(MODULE)s-helper.cc', + ] + + headers = bld.new_task_gen(features=['ns3header']) + headers.module = %(MODULE)r + headers.source = [ + 'model/%(MODULE)s.h', + 'helper/%(MODULE)s-helper.h', + ] + + if bld.env.ENABLE_EXAMPLES: + bld.add_subdirs('examples') + + # bld.ns3_python_bindings() + +''' + + + +MODEL_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "%(MODULE)s.h" + +namespace ns3 { + +/* ... */ + + +} + +''' + + + +MODEL_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#ifndef %(INCLUDE_GUARD)s +#define %(INCLUDE_GUARD)s + +namespace ns3 { + +/* ... */ + +} + +#endif /* %(INCLUDE_GUARD)s */ + +''' + + + +HELPER_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "%(MODULE)s-helper.h" + +namespace ns3 { + +/* ... */ + + +} + +''' + + + +HELPER_H_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#ifndef %(INCLUDE_GUARD)s +#define %(INCLUDE_GUARD)s + +#include "ns3/%(MODULE)s.h" + +namespace ns3 { + +/* ... */ + +} + +#endif /* %(INCLUDE_GUARD)s */ + +''' + + +EXAMPLES_WSCRIPT_TEMPLATE = '''# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_program('%(MODULE)s-example', [%(MODULE)r]) + obj.source = '%(MODULE)s-example.cc' + +''' + +EXAMPLE_CC_TEMPLATE = '''/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "ns3/core-module.h" +#include "ns3/%(MODULE)s-helper.h" + +using namespace ns3; + + +int +main (int argc, char *argv[]) +{ + bool verbose = true; + + CommandLine cmd; + cmd.AddValue ("verbose", "Tell application to log if true", verbose); + + cmd.Parse (argc,argv); + + /* ... */ + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} + + +''' + + +def main(argv): + parser = OptionParser(usage=("Usage: %prog [options] modulename\n" + "Utility script to create a basic template for a new ns-3 module")) + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + return 1 + + modname = args[0] + assert os.path.sep not in modname + + moduledir = os.path.join(os.path.dirname(__file__), modname) + + if os.path.exists(moduledir): + print >> sys.stderr, "Module %r already exists" % (modname,) + return 2 + + os.mkdir(moduledir) + wscript = file(os.path.join(moduledir, "wscript"), "wt") + wscript.write(WSCRIPT_TEMPLATE % dict(MODULE=modname)) + wscript.close() + + + # + # model + # + modeldir = os.path.join(moduledir, "model") + os.mkdir(modeldir) + + model_cc = file(os.path.join(moduledir, "model", "%s.cc" % modname), "wt") + model_cc.write(MODEL_CC_TEMPLATE % dict(MODULE=modname)) + model_cc.close() + + model_h = file(os.path.join(moduledir, "model", "%s.h" % modname), "wt") + model_h.write(MODEL_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="__%s_H__" % (modname.upper()),)) + model_h.close() + + + + # + # helper + # + helperdir = os.path.join(moduledir, "helper") + os.mkdir(helperdir) + + helper_cc = file(os.path.join(moduledir, "helper", "%s-helper.cc" % modname), "wt") + helper_cc.write(HELPER_CC_TEMPLATE % dict(MODULE=modname)) + helper_cc.close() + + helper_h = file(os.path.join(moduledir, "helper", "%s-helper.h" % modname), "wt") + helper_h.write(HELPER_H_TEMPLATE % dict(MODULE=modname, INCLUDE_GUARD="__%s_HELPER_H__" % (modname.upper()),)) + helper_h.close() + + + examplesdir = os.path.join(moduledir, "examples") + os.mkdir(examplesdir) + + examples_wscript = file(os.path.join(examplesdir, "wscript"), "wt") + examples_wscript.write(EXAMPLES_WSCRIPT_TEMPLATE % dict(MODULE=modname)) + examples_wscript.close() + + example_cc = file(os.path.join(moduledir, "examples", "%s-example.cc" % modname), "wt") + example_cc.write(EXAMPLE_CC_TEMPLATE % dict(MODULE=modname)) + example_cc.close() + + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) From 2413ed70335b22f3879f468de45fc50ecc666d2e Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 13 Sep 2011 19:25:55 +0100 Subject: [PATCH 12/17] Don't traceback on missing mpic++ --- src/mpi/wscript | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mpi/wscript b/src/mpi/wscript index 173470d00..52ed53312 100644 --- a/src/mpi/wscript +++ b/src/mpi/wscript @@ -2,11 +2,14 @@ import sys import subprocess import Options - +from waflib.Errors import WafError def configure(conf): env = conf.env - conf.find_program('mpic++', var='MPI') + try: + conf.find_program('mpic++', var='MPI') + except WafError: + return if Options.options.enable_mpi and conf.env['MPI']: p = subprocess.Popen([conf.env['MPI'], '-showme:compile'], stdout=subprocess.PIPE) flags = p.stdout.read().rstrip().split() From 6e0bff270620de2570f6372afde1b3ce62aacb0c Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 15 Sep 2011 11:21:55 +0100 Subject: [PATCH 13/17] waf1.6: possibly fix click module build --- src/click/wscript | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/click/wscript b/src/click/wscript index e72a78d44..8e6c5f511 100644 --- a/src/click/wscript +++ b/src/click/wscript @@ -58,7 +58,7 @@ int main() return 0; } ''' - conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib='DL') + conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib_store='DL') for tmp in ['lib', 'ns']: libdir = os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],tmp)) @@ -68,7 +68,7 @@ int main() conf.env['CPPPATH_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'include'))] - conf.env['NSCLICK'] = conf.check_nonfatal(fragment=test_code, lib='nsclick', uselib='NSCLICK DL') + conf.env['NSCLICK'] = conf.check_nonfatal(fragment=test_code, lib='nsclick', use='DL', uselib_store='NSCLICK') conf.report_optional_feature("nsclick", "NS-3 Click Integration", conf.env['NSCLICK'], "nsclick library not found") if conf.env['NSCLICK']: @@ -84,7 +84,7 @@ def build(bld): if 'click' in bld.env['MODULES_NOT_BUILT']: return - module = bld.create_ns3_module('click', ['internet']) + module = bld.create_ns3_module('click', ['core', 'network', 'internet']) module.includes = '. CPPPATH_NSCLICK' module.source = [ 'model/ipv4-click-routing.cc', @@ -98,8 +98,8 @@ def build(bld): ] if bld.env['NSCLICK'] and bld.env['DL']: - module.uselib = 'NSCLICK DL' - module_test.uselib = 'NSCLICK DL' + module.use = 'NSCLICK DL' + module_test.use = 'NSCLICK DL' headers = bld.new_task_gen(features=['ns3header']) headers.module = 'click' From 7518a6ba56510980afcb79d4fd6f383ff731731a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 15 Sep 2011 11:38:36 +0100 Subject: [PATCH 14/17] Add a --disable-nsclick configure option --- src/click/wscript | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/click/wscript b/src/click/wscript index 8e6c5f511..5ceacef75 100644 --- a/src/click/wscript +++ b/src/click/wscript @@ -8,8 +8,16 @@ def options(opt): opt.add_option('--with-nsclick', help=('Path to Click source or installation prefix for NS-3 Click Integration support'), dest='with_nsclick', default=None) + opt.add_option('--disable-nsclick', + help=('Disable NS-3 Click Integration support'), + dest='disable_nsclick', default=False, action="store_true") def configure(conf): + if Options.options.disable_nsclick: + conf.report_optional_feature("nsclick", "NS-3 Click Integration", False, + "disabled by user request") + return + if Options.options.with_nsclick: if os.path.isdir(Options.options.with_nsclick): conf.msg("libnsclick.so location", ("%s (given)" % Options.options.with_nsclick)) From 149d7922d26e26fa1acb87d00db0398dfc90d679 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 15 Sep 2011 14:52:24 +0100 Subject: [PATCH 15/17] Possible openflow module waf1.6 fixes --- src/openflow/wscript | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/openflow/wscript b/src/openflow/wscript index d5580282a..5038cacbd 100644 --- a/src/openflow/wscript +++ b/src/openflow/wscript @@ -13,20 +13,13 @@ def options(opt): def configure(conf): try: conf.check_tool('boost') - conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem', - kind = 'STATIC_BOTH', - score_version = (-1000, 1000), - tag_minscore = 1000) - if not conf.env['BOOST']: - conf.env['BOOST'] = conf.check_boost(lib = 'signals filesystem', - kind = 'STATIC_BOTH', - score_version = (-1000, 1000), - tag_minscore = 1000, - libpath="/usr/lib64") + 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['BOOST'] = False + conf.env['LIB_BOOST'] = [] - if not conf.env['BOOST']: + if not conf.env.LIB_BOOST: conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False, "Required boost libraries not found") @@ -38,16 +31,16 @@ def configure(conf): if Options.options.with_openflow: if os.path.isdir(Options.options.with_openflow): - conf.check_message("OpenFlow location", '', True, ("%s (given)" % Options.options.with_openflow)) + conf.msg("Checking for OpenFlow location", ("%s (given)" % Options.options.with_openflow)) conf.env['WITH_OPENFLOW'] = os.path.abspath(Options.options.with_openflow) else: openflow_dir = os.path.join('..','openflow') if os.path.isdir(openflow_dir): - conf.check_message("OpenFlow location", '', True, ("%s (guessed)" % openflow_dir)) + conf.msg("Checking for OpenFlow location", ("%s (guessed)" % openflow_dir)) conf.env['WITH_OPENFLOW'] = os.path.abspath(openflow_dir) del openflow_dir if not conf.env['WITH_OPENFLOW']: - conf.check_message("OpenFlow location", '', False) + conf.msg("Checking for OpenFlow location", False) conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", False, "OpenFlow not enabled (see option --with-openflow)") # Add this module to the list of modules that won't be built @@ -108,23 +101,19 @@ int main() conf.env.append_value('NS3_MODULE_PATH',os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default'))) - conf.env['CPPPATH_OPENFLOW'] = [ + conf.env['INCLUDES_OPENFLOW'] = [ os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'include'))] conf.env['LIBPATH_OPENFLOW'] = [ os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'build','default')), os.path.abspath(os.path.join(conf.env['WITH_OPENFLOW'],'lib'))] - conf.env['OPENFLOW'] = conf.check(fragment=test_code, lib='openflow', - libpath=conf.env['LIBPATH_OPENFLOW'], - uselib='OPENFLOW DL XML2') - + conf.env['OPENFLOW'] = conf.check_nonfatal(fragment=test_code, lib='openflow', + libpath=conf.env['LIBPATH_OPENFLOW'], + use='OPENFLOW DL XML2') conf.report_optional_feature("openflow", "NS-3 OpenFlow Integration", conf.env['OPENFLOW'], "openflow library not found") if conf.env['OPENFLOW']: conf.env['ENABLE_OPENFLOW'] = True - conf.env.append_value('CXXDEFINES', 'NS3_OPENFLOW') - conf.env.append_value('CPPPATH', conf.env['CPPPATH_OPENFLOW']) - conf.env.append_value('LIBPATH', conf.env['LIBPATH_OPENFLOW']) else: # Add this module to the list of modules that won't be built # if they are enabled. @@ -159,6 +148,10 @@ def build(bld): obj.source.append('model/openflow-interface.cc') obj.source.append('model/openflow-switch-net-device.cc') obj.source.append('helper/openflow-switch-helper.cc') + + obj.env.append_value('DEFINES', 'NS3_OPENFLOW') + obj.use = "OPENFLOW" + obj_test.source.append('test/openflow-switch-test-suite.cc') headers.source.append('model/openflow-interface.h') headers.source.append('model/openflow-switch-net-device.h') From 3d13582a2e324daf2f3e128e181a21487a957885 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 15 Sep 2011 17:11:53 +0100 Subject: [PATCH 16/17] waf1.6: fix click module build --- src/click/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/click/wscript b/src/click/wscript index 5ceacef75..fb7423cba 100644 --- a/src/click/wscript +++ b/src/click/wscript @@ -80,7 +80,7 @@ int main() conf.report_optional_feature("nsclick", "NS-3 Click Integration", conf.env['NSCLICK'], "nsclick library not found") if conf.env['NSCLICK']: - conf.env.append_value('CXXDEFINES', 'NS3_CLICK') + conf.env.append_value('DEFINES', 'NS3_CLICK') conf.env.append_value('CPPPATH', conf.env['CPPPATH_NSCLICK']) else: # Add this module to the list of modules that won't be built From 8405e52966b8d18165a7beb32b24590435564dea Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Sun, 18 Sep 2011 12:19:14 +0100 Subject: [PATCH 17/17] Remove the EXPERIMENTAL from --apiscan option help --- bindings/python/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/wscript b/bindings/python/wscript index 9681e245f..c7c5b43fb 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -55,7 +55,7 @@ def options(opt): action="store_true", default=False, dest='python_disable') opt.add_option('--apiscan', - help=("EXPERIMENTAL: Rescan the API for the indicated module(s), for Python bindings. " + help=("Rescan the API for the indicated module(s), for Python bindings. " "Needs working GCCXML / pygccxml environment. " "The metamodule 'all' expands to all available ns-3 modules."), default=None, dest='apiscan', metavar="MODULE[,MODULE...]")