build: (fixes #2884) Remove code duplication in contrib/wscript
authorTom Henderson <tomh@tomh.org>
Wed, 14 Mar 2018 22:01:41 -0700
changeset 13411 9f79028812c0
parent 13410 660d3dfff1ca
child 13412 6ff8a70148e0
build: (fixes #2884) Remove code duplication in contrib/wscript
contrib/wscript
--- a/contrib/wscript	Wed Mar 14 20:38:59 2018 -0700
+++ b/contrib/wscript	Wed Mar 14 22:01:41 2018 -0700
@@ -1,4 +1,3 @@
-
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 from __future__ import print_function
 import os, os.path
@@ -16,9 +15,7 @@
 except NameError:
     from sets import Set as set # Python 2.3 fallback
 
-
-
-all_modules = []
+all_contrib_modules = []
 for dirname in os.listdir('contrib'):
     if dirname.startswith('.') or dirname == 'CVS':
         continue
@@ -26,65 +23,23 @@
     if not os.path.isdir(path):
         continue
     if os.path.exists(os.path.join(path, 'wscript')):
-        all_modules.append(dirname)
-all_modules.sort()
-
-
+        all_contrib_modules.append(dirname)
+all_contrib_modules.sort()
 
 def options(opt):
-    opt.add_option('--enable-rpath',
-                   help=("Link programs with rpath"
-                         " (normally not needed, see "
-                         " --run and --shell; moreover, only works in some"
-                         " specific platforms, such as Linux and Solaris)"),
-                   action="store_true", dest='enable_rpath', default=False)
-    
-    opt.add_option('--enable-modules',
-                   help=("Build only these modules (and dependencies)"),
-                   dest='enable_modules')
-
-    opt.load('boost', tooldir=['waf-tools'])
-
-    for module in all_modules:
+    for module in all_contrib_modules:
         opt.recurse(module, mandatory=False)
 
 def configure(conf):
-    if not conf.env['REQUIRED_BOOST_LIBS']:
-        conf.env['REQUIRED_BOOST_LIBS'] = []
-    for module in all_modules:
-        conf.recurse (module, name="required_boost_libs", mandatory=False)
-
-    if conf.env['REQUIRED_BOOST_LIBS'] is not []:
-        conf.load('boost')
-        conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), mandatory=False)
-        if not conf.env['LIB_BOOST']:
-            conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), libpath="/usr/lib64", mandatory=False)
-            if not conf.env['LIB_BOOST']:
-                conf.env['LIB_BOOST'] = []
-
-    # Append blddir to the module path before recursing into modules
-    blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
-    conf.env.append_value('NS3_MODULE_PATH', blddir)
-
-    for module in all_modules:
+    for module in all_contrib_modules:
         conf.recurse(module, mandatory=False)
 
-    # Remove duplicate path items
-    conf.env['NS3_MODULE_PATH'] = wutils.uniquify_list(conf.env['NS3_MODULE_PATH'])
-
-    if Options.options.enable_rpath:
-        conf.env.append_value('RPATH', '-Wl,-rpath,%s' % (os.path.join(blddir),))
-
     ## Used to link the 'test-runner' program with all of ns-3 code
-    conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
-
+    conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_contrib_modules]
 
 
 # we need the 'ns3module' waf "feature" to be created because code
 # elsewhere looks for it to find the ns3 module objects.
-@TaskGen.feature('ns3module')
-def _add_test_code(module):
-    pass
 
 def create_ns3_module(bld, name, dependencies=(), test=False):
     static = bool(bld.env.ENABLE_STATIC_NS3)
@@ -143,15 +98,6 @@
     
     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.path_from(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.
@@ -183,7 +129,6 @@
 
 
 def ns3_python_bindings(bld):
-
     # 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)
@@ -305,7 +250,6 @@
 
     return pymod
 
-
 def build(bld):
     bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
     bld.create_ns3_module_test_library = types.MethodType(create_ns3_module_test_library, bld)
@@ -315,439 +259,12 @@
     # Remove these modules from the list of all modules.
     for not_built in bld.env['MODULES_NOT_BUILT']:
 
-        # XXX Because these modules are located in subdirectories of
-        # test, their names in the all_modules list include the extra
-        # relative path "test/".  If these modules are moved into the
-        # src directory, then this if block should be removed.
-        if not_built == 'ns3tcp' or not_built == 'ns3wifi':
-            not_built = 'test/' + not_built
+        if not_built in all_contrib_modules:
+            all_contrib_modules.remove(not_built)
 
-        if not_built in all_modules:
-            all_modules.remove(not_built)
+    bld.recurse(list(all_contrib_modules))
 
-    bld.recurse(list(all_modules))
-
-    for module in all_modules:
+    for module in all_contrib_modules:
         modheader = bld(features='ns3moduleheader')
         modheader.module = module.split('/')[-1]
 
-class ns3pcfile_task(Task.Task):
-    after = 'cxx'
-
-    def __str__(self):
-        "string to display to the user"
-        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
-        return 'pcfile: %s\n' % (tgt_str)
-
-    def runnable_status(self):
-        return super(ns3pcfile_task, self).runnable_status()
-
-    def _self_libs(self, env, name, libdir):
-        if env['ENABLE_STATIC_NS3']:
-            path_st = 'STLIBPATH_ST'
-            lib_st = 'STLIB_ST'
-            lib_marker = 'STLIB_MARKER'
-        else:
-            path_st = 'LIBPATH_ST'
-            lib_st = 'LIB_ST'
-            lib_marker = 'SHLIB_MARKER'
-        retval = [env[path_st] % libdir]
-        if env[lib_marker]:
-            retval.append(env[lib_marker])
-        retval.append(env[lib_st] % name)
-        return retval
-
-    def _lib(self, env, dep):
-        libpath = env['LIBPATH_%s' % dep]
-        linkflags = env['LINKFLAGS_%s' % dep]
-        libs = env['LIB_%s' % dep]
-        retval = []
-        for path in libpath:
-            retval.append(env['LIBPATH_ST'] % path)
-            retval = retval + linkflags
-        for lib in libs:
-            retval.append(env['LIB_ST'] % lib)
-        return retval
-
-    def _listify(self, v):
-        if isinstance(v, list):
-            return v
-        else:
-            return [v]
-
-    def _cflags(self, dep):
-        flags = self.env['CFLAGS_%s' % dep]
-        return self._listify(flags)
-
-    def _cxxflags(self, dep):
-        return self._listify(self.env['CXXFLAGS_%s' % dep])
-
-    def _defines(self, dep):
-        return [self.env['DEFINES_ST'] % define for define in self.env['DEFINES_%s' % dep]] 
-
-    def _includes(self, dep):
-        includes = self.env['INCLUDES_%s' % dep]
-        return [self.env['CPPPATH_ST'] % include for include in includes]
-
-    def _generate_pcfile(self, name, use, env, outfilename):
-        outfile = open(outfilename, 'wt')
-        prefix = env.PREFIX
-        includedir = Utils.subst_vars('${INCLUDEDIR}/%s%s' % (wutils.APPNAME, wutils.VERSION), env)
-        libdir = env.LIBDIR
-        libs = self._self_libs(env, "%s%s-%s%s" % (wutils.APPNAME, wutils.VERSION, name[4:], env.BUILD_SUFFIX), '${libdir}')
-        for dep in use:
-            libs += self._lib(env, dep)
-        for dep in env.LIBS:
-            libs += self.env['LIB_ST'] % dep
-        cflags = [self.env['CPPPATH_ST'] % '${includedir}']
-        requires = []
-        for dep in use:
-            cflags = cflags + self._cflags(dep) + self._cxxflags(dep) + \
-                self._defines(dep) + self._includes(dep)
-            if dep.startswith('ns3-'):
-                dep_name = dep[4:]
-                requires.append("libns%s-%s%s" % (wutils.VERSION, dep_name, env.BUILD_SUFFIX))
-        print("""\
-prefix=%s
-libdir=%s
-includedir=%s
-
-Name: lib%s
-Description: ns-3 module %s
-Version: %s
-Libs: %s
-Cflags: %s
-Requires: %s\
-""" % (prefix, libdir, includedir,
-       name, name, wutils.VERSION, ' '.join(libs), ' '.join(cflags), ' '.join(requires)), file=outfile)
-        outfile.close()
-
-    def run(self):
-        output_filename = self.outputs[0].abspath()
-        self._generate_pcfile(self.module.name, 
-                              self.module.to_list(self.module.use),
-                              self.env, output_filename)
-
-
-@TaskGen.feature('ns3pcfile')
-@TaskGen.after_method('process_rule')
-def apply(self):
-    module = self.bld.find_ns3_module(self.module)
-    output_filename = 'lib%s.pc' % os.path.basename(module.target)
-    output_node = self.path.find_or_declare(output_filename)
-    assert output_node is not None, str(self)
-    task = self.create_task('ns3pcfile')
-    self.bld.install_files('${LIBDIR}/pkgconfig', output_node)
-    task.set_outputs([output_node])
-    task.module = module
-
-
-
-@TaskGen.feature('ns3header')
-@TaskGen.after_method('process_rule')
-def apply_ns3header(self):
-    if self.module is None:
-        raise WafError("'module' missing on ns3headers object %s" % self)
-    ns3_dir_node = self.bld.path.find_or_declare("ns3")
-    for filename in set(self.to_list(self.source)):
-        src_node = self.path.find_resource(filename)
-        if src_node is None:
-            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')
-        task.mode = getattr(self, 'mode', 'install')
-        if task.mode == 'install':
-            self.bld.install_files('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION), [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 = 'cxx gen_ns3_module_header'
-    color = 'BLUE'
-
-    def __str__(self):
-        "string to display to the user"
-        env = self.env
-        src_str = ' '.join([a.bldpath() for a in self.inputs])
-        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
-        if self.outputs: sep = ' -> '
-        else: sep = ''
-        if self.mode == 'remove':
-            return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),)
-        return 'install-ns3-header: %s' % (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.encode())
-            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.abspath()):
-                return Task.RUN_ME
-            else:
-                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.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, 0o600)
-                except OSError:
-                    pass
-                shutil.copy2(src, dst)
-                ## make the headers in builddir read-only, to prevent
-                ## accidental modification
-                os.chmod(dst, 0o400)
-            return 0
-        else:
-            assert len(self.inputs) == 0
-            assert len(self.outputs) == 0
-            out_file_name = self.header_to_remove.abspath()
-            try:
-                os.unlink(out_file_name)
-            except OSError as ex:
-                if ex.errno != 2:
-                    raise
-            return 0
-
-
-@TaskGen.feature('ns3privateheader')
-@TaskGen.after_method('process_rule')
-def apply_ns3privateheader(self):
-    if self.module is None:
-        raise WafError("'module' missing on ns3headers object %s" % self)
-    ns3_dir_node = self.bld.path.find_or_declare("ns3/private")
-    for filename in set(self.to_list(self.source)):
-        src_node = self.path.find_resource(filename)
-        if src_node is None:
-            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('ns3privateheader')
-        task.mode = getattr(self, 'mode', 'install')
-        if task.mode == 'install':
-            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 ns3privateheader_task(Task.Task):
-    before = 'cxx gen_ns3_module_header'
-    after = 'ns3header'
-    color = 'BLUE'
-
-    def __str__(self):
-        "string to display to the user"
-        env = self.env
-        src_str = ' '.join([a.bldpath() for a in self.inputs])
-        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
-        if self.outputs: sep = ' -> '
-        else: sep = ''
-        if self.mode == 'remove':
-            return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),)
-        return 'install-ns3-header: %s' % (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.encode())
-            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.abspath()):
-                return Task.RUN_ME
-            else:
-                return Task.SKIP_ME
-        else:
-            return super(ns3privateheader_task, self).runnable_status()
-
-    def run(self):
-        if self.mode == 'install':
-            assert len(self.inputs) == len(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, 0o600)
-                except OSError:
-                    pass
-                shutil.copy2(src, dst)
-                ## make the headers in builddir read-only, to prevent
-                ## accidental modification
-                os.chmod(dst, 0o400)
-            return 0
-        else:
-            assert len(self.inputs) == 0
-            assert len(self.outputs) == 0
-            out_file_name = self.header_to_remove.abspath()
-            try:
-                os.unlink(out_file_name)
-            except OSError as ex:
-                if ex.errno != 2:
-                    raise
-            return 0
-
-
-class gen_ns3_module_header_task(Task.Task):
-    before = 'cxx'
-    after = 'ns3header'
-    color = 'BLUE'
-
-    def runnable_status(self):
-        if self.mode == 'remove':
-            if os.path.exists(self.header_to_remove.abspath()):
-                return Task.RUN_ME
-            else:
-                return Task.SKIP_ME
-        else:
-            return super(gen_ns3_module_header_task, self).runnable_status()
-
-    def __str__(self):
-        "string to display to the user"
-        env = self.env
-        src_str = ' '.join([a.bldpath() for a in self.inputs])
-        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
-        if self.outputs: sep = ' -> '
-        else: sep = ''
-        if self.mode == 'remove':
-            return 'rm-module-header %s' % (self.header_to_remove.abspath(),)
-        return 'gen-module-header: %s' % (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.abspath()
-            try:
-                os.unlink(out_file_name)
-            except OSError as ex:
-                if ex.errno != 2:
-                    raise
-            return 0
-        assert len(self.outputs) == 1
-        out_file_name = self.outputs[0].get_bld().abspath()#self.env)
-        header_files = [os.path.basename(node.abspath()) for node in self.inputs]
-        outfile = open(out_file_name, "w")
-        header_files.sort()
-
-        print("""
-#ifdef NS3_MODULE_COMPILATION
-# error "Do not include ns3 module aggregator headers from other modules; these are meant only for end user scripts."
-#endif
-
-#ifndef NS3_MODULE_%s
-    """ % (self.module.upper().replace('-', '_'),), file=outfile)
-
-    #     if self.module_deps:
-    #         print >> outfile, "// Module dependencies:"
-    #     for dep in self.module_deps:
-    #         print >> outfile, "#include \"%s-module.h\"" % dep
-
-        print(file=outfile)
-        print("// Module headers:", file=outfile)
-        for header in header_files:
-            print("#include \"%s\"" % (header,), file=outfile)
-
-        print("#endif", file=outfile)
-
-        outfile.close()
-        return 0
-
-    def sig_explicit_deps(self):
-        self.m.update('\n'.join(sorted([node.abspath() for node in self.inputs])).encode('utf-8'))
-        return self.m.digest()
-
-    def unique_id(self):
-        try:
-            return self.uid
-        except AttributeError:
-            "this is not a real hot zone, but we want to avoid surprizes here"
-            m = Utils.md5()
-            m.update("ns-3-module-header-%s" % self.module)
-            self.uid = m.digest()
-            return self.uid
-
-
-# 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_or_declare("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 sorted(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 WafError("error finding headers for module %s" % self.module)
-    if not all_headers_inputs:
-        return
-
-    try:
-        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)]
-    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('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION),
-                               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]