## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- import os, os.path import shutil import types import warnings import TaskGen import Task import Options import Build import Utils import Constants try: set except NameError: from sets import Set as set # Python 2.3 fallback all_modules = ( 'core', 'network', 'contrib', 'internet-stack', 'propagation', 'devices/point-to-point', 'devices/csma', 'devices/emu', 'devices/bridge', 'devices/tap-bridge', 'devices/virtual-net-device', 'applications/onoff', 'applications/packet-sink', 'applications/udp-echo', 'applications/bulk-send', 'routing/nix-vector-routing', 'routing/olsr', 'routing/global-routing', 'routing/static-routing', 'routing/list-routing', 'routing/aodv', 'routing/dsdv', 'routing/click', 'mobility', 'devices/wifi', 'helper', 'contrib/stats', 'applications/v4ping', 'devices/uan', 'spectrum', 'devices/mesh', 'devices/mesh/dot11s', 'devices/mesh/flame', 'applications/ping6', 'applications/radvd', 'test', 'test/perf', 'test/ns3tcp', 'test/nsctcp', 'test/ns3wifi', 'contrib/flow-monitor', 'applications/udp-client-server', 'devices/wimax', 'devices/lte', 'mpi', 'contrib/topology-read', 'contrib/energy', 'tools/visualizer', ) def set_options(opt): opt.sub_options('core') opt.sub_options('routing/click') 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') def configure(conf): conf.sub_config('core') conf.sub_config('devices/emu') conf.sub_config('devices/tap-bridge') conf.sub_config('contrib') conf.sub_config('internet-stack') conf.sub_config('helper') conf.sub_config('test') conf.sub_config('routing/click') blddir = os.path.abspath(os.path.join(conf.blddir, conf.env.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),)) ## Used to link the 'test-runner' program with all of ns-3 code conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] def create_ns3_module(bld, name, dependencies=()): module = bld.new_task_gen('cxx', 'cc') module.is_ns3_module = True module.name = 'ns3-' + name module.target = module.name module.add_objects = ['ns3-' + dep for dep in dependencies] module.module_deps = list(dependencies) if not module.env['ENABLE_STATIC_NS3']: module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS']) module.env.append_value('CCFLAGS', module.env['shlib_CXXFLAGS']) elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \ os.uname()[4] == 'x86_64' 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) module.env.append_value('CXXFLAGS', '-mcmodel=large') module.env.append_value('CCFLAGS', '-mcmodel=large') module.env.append_value('CXXDEFINES', "NS3_MODULE_COMPILATION") module.env.append_value('CCDEFINES', "NS3_MODULE_COMPILATION") return module def create_obj(bld, *args): warnings.warn("(in %s) Use bld.new_task_gen(...) now, instead of bld.create_obj(...)" % str(bld.path), DeprecationWarning, stacklevel=2) return bld.new_task_gen(*args) def build(bld): bld.create_ns3_module = types.MethodType(create_ns3_module, bld) bld.create_obj = types.MethodType(create_obj, bld) bld.add_subdirs(list(all_modules)) for module in all_modules: modheader = bld.new_task_gen('ns3moduleheader') modheader.module = module.split('/')[-1] 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' def apply(self): 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': task.set_inputs([src_node]) task.set_outputs([dst_node]) else: task.header_to_remove = dst_node class ns3header_task(Task.Task): before = 'cc cxx gen_ns3_module_header_task' color = 'BLUE' def __str__(self): "string to display to the user" env = self.env src_str = ' '.join([a.nice_path(env) for a in self.inputs]) tgt_str = ' '.join([a.nice_path(env) for a in self.outputs]) if self.outputs: sep = ' -> ' else: sep = '' if self.mode == 'remove': return 'rm-ns3-header %s\n' % (self.header_to_remove.bldpath(self.env),) return 'install-ns3-header: %s%s%s\n' % (src_str, sep, tgt_str) def runnable_status(self): if self.mode == 'remove': if os.path.exists(self.header_to_remove.bldpath(self.env)): return Constants.RUN_ME else: return Constants.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] for src, dst in zip(inputs, outputs): try: os.chmod(dst, 0600) except OSError: pass shutil.copy2(src, dst) ## make the headers in builddir read-only, to prevent ## accidental modification os.chmod(dst, 0400) return 0 else: assert len(self.inputs) == 0 assert len(self.outputs) == 0 out_file_name = self.header_to_remove.bldpath(self.env) try: os.unlink(out_file_name) except OSError, ex: if ex.errno != 2: raise return 0 class gen_ns3_module_header_task(Task.Task): before = 'cc cxx' after = 'ns3header_task' 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 else: return Constants.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.nice_path(env) for a in self.inputs]) tgt_str = ' '.join([a.nice_path(env) for a in self.outputs]) if self.outputs: sep = ' -> ' else: sep = '' if self.mode == 'remove': return 'rm-module-header %s\n' % (self.header_to_remove.bldpath(self.env),) 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) try: os.unlink(out_file_name) except OSError, ex: 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] outfile = file(out_file_name, "w") header_files.sort() print >> outfile, """ #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('-', '_'),) # if self.module_deps: # print >> outfile, "// Module dependencies:" # for dep in self.module_deps: # print >> outfile, "#include \"%s-module.h\"" % dep print >> outfile print >> outfile, "// Module headers:" for header in header_files: print >> outfile, "#include \"%s\"" % (header,) print >> outfile, "#endif" outfile.close() return 0 def sig_explicit_deps(self): self.m.update('\n'.join([node.abspath(self.env) for node in self.inputs])) 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 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' 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': 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] def install(self): pass