1 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
12 import pproc as subprocess
20 ccroot.USE_TOP_LEVEL = True
23 Task.algotype = Constants.JOBCONTROL # so that Task.maxjobs=1 takes effect
30 import cflags # override the build profiles from waf
32 # profile name: [optimization_level, warnings_level, debug_level]
34 'optimized': [3, 2, 1],
36 cflags.default_profile = 'debug'
42 Configure.autoconfig = 1
44 # the following two variables are used by the target "waf dist"
45 VERSION = file("VERSION", "rt").read().strip()
48 wutils.VERSION = VERSION
49 wutils.APPNAME = APPNAME
52 # The last part of the path name to use to find the regression traces. The
53 # path will be APPNAME + '-' + VERSION + REGRESSION_SUFFIX, e.g.,
56 REGRESSION_SUFFIX = "-ref-traces"
59 # these variables are mandatory ('/' are converted automatically)
64 bld_cls = getattr(Utils.g_module, 'build_context', Utils.Context)
66 bld_ctx.load_dirs(os.path.abspath(os.path.join (srcdir,'..')),
67 os.path.abspath(os.path.join (srcdir,'..', blddir)))
69 env = bld_ctx.get_env()
72 def get_files(base_dir):
74 reference=os.path.dirname(base_dir)
75 for root, dirs, files in os.walk(base_dir):
76 if root.find('.hg') != -1:
79 if file.find('.hg') != -1:
81 fullname = os.path.join(root,file)
82 # we can't use os.path.relpath because it's new in python 2.6
83 relname = fullname.replace(reference + '/','')
84 retval.append([fullname,relname])
90 shutil.rmtree("doc/html", True)
91 shutil.rmtree("doc/latex", True)
92 shutil.rmtree("nsc", True)
94 ## build the name of the traces subdirectory. Will be something like
95 ## ns-3-dev-ref-traces
96 traces_name = APPNAME + '-' + VERSION + REGRESSION_SUFFIX
97 ## Create a tar.bz2 file with the traces
99 regression_dir = env['REGRESSION_TRACES']
100 if not os.path.isdir(regression_dir):
101 Logs.warn("Not creating traces archive: the %s directory does not exist" % regression_dir)
103 traceball = traces_name + wutils.TRACEBALL_SUFFIX
104 tar = tarfile.open(os.path.join("..", traceball), 'w:bz2')
105 files = get_files(regression_dir)
106 for fullfilename,relfilename in files:
107 tar.add(fullfilename,arcname=relfilename)
110 def set_options(opt):
111 # options provided by the modules
112 opt.tool_options('compiler_cxx')
113 opt.tool_options('cflags')
115 opt.add_option('--cwd',
116 help=('Set the working directory for a program.'),
117 action="store", type="string", default=None,
120 opt.add_option('--enable-gcov',
121 help=('Enable code coverage analysis.'
122 ' WARNING: this option only has effect '
123 'with the configure command.'),
124 action="store_true", default=False,
127 opt.add_option('--no-task-lines',
128 help=("Don't print task lines, i.e. messages saying which tasks are being executed by WAF."
129 " Coupled with a single -v will cause WAF to output only the executed commands,"
130 " just like 'make' does by default."),
131 action="store_true", default=False,
132 dest='no_task_lines')
134 opt.add_option('--lcov-report',
135 help=('Generate a code coverage report '
136 '(use this option at build time, not in configure)'),
137 action="store_true", default=False,
140 opt.add_option('--doxygen',
141 help=('Run doxygen to generate html documentation from source comments'),
142 action="store_true", default=False,
145 opt.add_option('--run',
146 help=('Run a locally built program; argument can be a program name,'
147 ' or a command starting with the program name.'),
148 type="string", default='', dest='run')
149 opt.add_option('--command-template',
150 help=('Template of the command used to run the program given by --run;'
151 ' It should be a shell command string containing %s inside,'
152 ' which will be replaced by the actual program.'),
153 type="string", default=None, dest='command_template')
154 opt.add_option('--pyrun',
155 help=('Run a python program using locally built ns3 python module;'
156 ' argument is the path to the python program, optionally followed'
157 ' by command-line options that are passed to the program.'),
158 type="string", default='', dest='pyrun')
159 opt.add_option('--valgrind',
160 help=('Change the default command template to run programs and unit tests with valgrind'),
161 action="store_true", default=False,
163 opt.add_option('--shell',
164 help=('DEPRECATED (run ./waf shell)'),
165 action="store_true", default=False,
167 opt.add_option('--enable-sudo',
168 help=('Use sudo to setup suid bits on ns3 executables.'),
169 dest='enable_sudo', action='store_true',
171 opt.add_option('--regression',
172 help=("Enable regression testing; only used for the 'check' target"),
173 default=False, dest='regression', action="store_true")
174 opt.add_option('--check',
175 help=("Enable unit testing"),
176 default=False, dest='check', action="store_true")
177 opt.add_option('--regression-generate',
178 help=("Generate new regression test traces."),
179 default=False, dest='regression_generate', action="store_true")
180 opt.add_option('--regression-tests',
181 help=('For regression testing, only run/generate the indicated regression tests, '
182 'specified as a comma separated list of test names'),
183 dest='regression_tests', type="string")
184 opt.add_option('--with-regression-traces',
185 help=('Path to the regression reference traces directory'),
187 dest='regression_traces', type="string")
188 opt.add_option('--enable-static',
189 help=('Compile NS-3 statically: works only on linux, without python'),
190 dest='enable_static', action='store_true',
193 # options provided in a script in a subdirectory named "src"
194 opt.sub_options('src')
195 opt.sub_options('bindings/python')
196 opt.sub_options('src/internet-stack')
199 def _check_compilation_flag(conf, flag):
201 Checks if the C++ compiler accepts a certain compilation flag or flags
202 flag: can be a string or a list of strings
205 env = conf.env.copy()
206 env.append_value('CXXFLAGS', flag)
208 retval = conf.run_c_code(code='#include <stdio.h>\nint main() { return 0; }\n',
209 env=env, compile_filename='test.cc',
210 compile_mode='cxx',type='cprogram', execute=False)
211 except Configure.ConfigurationError:
215 conf.check_message_custom(flag, 'support', (ok and 'yes' or 'no'))
219 def report_optional_feature(conf, name, caption, was_enabled, reason_not_enabled):
220 conf.env.append_value('NS3_OPTIONAL_FEATURES', (name, caption, was_enabled, reason_not_enabled))
223 # attach some extra methods
224 conf.check_compilation_flag = types.MethodType(_check_compilation_flag, conf)
225 conf.report_optional_feature = types.MethodType(report_optional_feature, conf)
226 conf.env['NS3_OPTIONAL_FEATURES'] = []
228 conf.env['NS3_BUILDDIR'] = conf.blddir
229 conf.check_tool('compiler_cxx')
230 conf.check_tool('cflags')
232 conf.check_tool('pkgconfig')
233 except Configure.ConfigurationError:
235 conf.check_tool('command')
237 # Check for the location of regression reference traces
238 if Options.options.regression_traces is not None:
239 if os.path.isdir(Options.options.regression_traces):
240 conf.check_message("regression traces location", '', True, ("%s (given)" % Options.options.regression_traces))
241 conf.env['REGRESSION_TRACES'] = os.path.abspath(Options.options.regression_traces)
243 traces = os.path.join('..', "%s-%s%s" % (APPNAME, VERSION, REGRESSION_SUFFIX))
244 if os.path.isdir(traces):
245 conf.check_message("regression reference traces", '', True, ("%s (guessed)" % traces))
246 conf.env['REGRESSION_TRACES'] = os.path.abspath(traces)
248 if not conf.env['REGRESSION_TRACES']:
249 conf.check_message("regression reference traces", '', False)
251 # create the second environment, set the variant and set its name
252 variant_env = conf.env.copy()
253 variant_name = Options.options.build_profile
255 if Options.options.enable_gcov:
256 variant_name += '-gcov'
257 variant_env.append_value('CCFLAGS', '-fprofile-arcs')
258 variant_env.append_value('CCFLAGS', '-ftest-coverage')
259 variant_env.append_value('CXXFLAGS', '-fprofile-arcs')
260 variant_env.append_value('CXXFLAGS', '-ftest-coverage')
261 variant_env.append_value('LINKFLAGS', '-fprofile-arcs')
263 conf.env['NS3_ACTIVE_VARIANT'] = variant_name
264 variant_env['NS3_ACTIVE_VARIANT'] = variant_name
265 variant_env.set_variant(variant_name)
266 conf.set_env_name(variant_name, variant_env)
267 conf.setenv(variant_name)
270 env.append_value('CXXDEFINES', 'RUN_SELF_TESTS')
272 if env['COMPILER_CXX'] == 'g++' and 'CXXFLAGS' not in os.environ:
273 if conf.check_compilation_flag('-Wno-error=deprecated-declarations'):
274 env.append_value('CXXFLAGS', '-Wno-error=deprecated-declarations')
276 if Options.options.build_profile == 'debug':
277 env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
278 env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
280 env['PLATFORM'] = sys.platform
282 if conf.env['CXX_NAME'] == 'gcc':
283 if sys.platform == 'win32':
284 env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
285 elif sys.platform == 'cygwin':
286 env.append_value("LINKFLAGS", "-Wl,--enable-auto-import")
290 p = subprocess.Popen([cxx, '-print-file-name=libstdc++.so'], stdout=subprocess.PIPE)
291 libstdcxx_location = os.path.dirname(p.stdout.read().strip())
293 if libstdcxx_location:
294 conf.env.append_value('NS3_MODULE_PATH', libstdcxx_location)
296 if Options.platform in ['linux']:
297 if conf.check_compilation_flag('-Wl,--soname=foo'):
298 env['WL_SONAME_SUPPORTED'] = True
300 conf.sub_config('src')
301 conf.sub_config('bindings/python')
303 if Options.options.enable_modules:
304 conf.env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in
305 Options.options.enable_modules.split(',')]
308 conf.find_program('sudo', var='SUDO')
310 why_not_sudo = "because we like it"
311 if Options.options.enable_sudo and conf.env['SUDO']:
312 env['ENABLE_SUDO'] = True
314 env['ENABLE_SUDO'] = False
315 if Options.options.enable_sudo:
316 why_not_sudo = "program sudo not found"
318 why_not_sudo = "option --enable-sudo not selected"
320 conf.report_optional_feature("ENABLE_SUDO", "Use sudo to set suid bit", env['ENABLE_SUDO'], why_not_sudo)
322 # we cannot pull regression traces without mercurial
323 conf.find_program('hg', var='MERCURIAL')
325 conf.find_program('valgrind', var='VALGRIND')
327 env['ENABLE_STATIC_NS3'] = False
328 if Options.options.enable_static:
329 if env['PLATFORM'].startswith('linux') and \
330 env['CXX_NAME'] == 'gcc':
331 if re.match('i[3-6]86', os.uname()[4]):
332 conf.report_optional_feature("static", "Static build", True, '')
333 env['ENABLE_STATIC_NS3'] = True
334 elif os.uname()[4] == 'x86_64':
335 if env['ENABLE_PYTHON_BINDINGS'] and \
336 not conf.check_compilation_flag('-mcmodel=large'):
337 conf.report_optional_feature("static", "Static build", False,
338 "Can't enable static builds because " + \
339 "no -mcmodel=large compiler " \
340 "option. Try --disable-python or upgrade your " \
341 "compiler to at least gcc 4.3.x.")
343 conf.report_optional_feature("static", "Static build", True, '')
344 env['ENABLE_STATIC_NS3'] = True
345 elif env['CXX_NAME'] == 'gcc' and \
346 (env['PLATFORM'].startswith('darwin') or \
347 env['PLATFORM'].startswith('cygwin')):
348 conf.report_optional_feature("static", "Static build", True, '')
349 env['ENABLE_STATIC_NS3'] = True
351 conf.report_optional_feature("static", "Static build", False,
352 "Unsupported platform")
354 conf.report_optional_feature("static", "Static build", False,
355 "option --enable-static not selected")
359 # Write a summary of optional features status
360 print "---- Summary of optional NS-3 features:"
361 for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']:
365 status = 'not enabled (%s)' % reason_not_enabled
366 print "%-30s: %s" % (caption, status)
369 class SuidBuildTask(Task.TaskBase):
370 """task that makes a binary Suid
372 after = 'cxx_link cc_link'
374 def __init__(self, bld, program):
376 self.m_display = 'build-suid'
377 self.__program = program
378 self.__env = bld.env.copy ()
379 super(SuidBuildTask, self).__init__(generator=self)
381 program_obj = wutils.find_program(self.__program.target, self.__env)
382 except ValueError, ex:
383 raise Utils.WafError(str(ex))
384 program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
385 self.filename = program_node.abspath(self.__env)
389 print >> sys.stderr, 'setting suid bit on executable ' + self.filename
390 if subprocess.Popen(['sudo', 'chown', 'root', self.filename]).wait():
392 if subprocess.Popen(['sudo', 'chmod', 'u+s', self.filename]).wait():
396 def runnable_status(self):
397 "RUN_ME SKIP_ME or ASK_LATER"
398 st = os.stat(self.filename)
400 return Constants.SKIP_ME
402 return Constants.RUN_ME
405 def create_suid_program(bld, name):
406 program = bld.new_task_gen('cxx', 'program')
407 program.is_ns3_program = True
408 program.module_deps = list()
410 program.target = name
412 if bld.env['ENABLE_SUDO']:
413 SuidBuildTask(bld, program)
417 def create_ns3_program(bld, name, dependencies=('simulator',)):
418 program = bld.new_task_gen('cxx', 'program')
419 program.is_ns3_program = True
421 program.target = program.name
422 program.uselib_local = 'ns3'
423 program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies]
424 if program.env['ENABLE_STATIC_NS3']:
425 if sys.platform == 'darwin':
426 program.env.append_value('LINKFLAGS', '-Wl,-all_load')
427 program.env.append_value('LINKFLAGS', '-lns3')
429 program.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
430 program.env.append_value('LINKFLAGS', '-lns3')
431 program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
434 def add_scratch_programs(bld):
435 all_modules = [mod[len("ns3-"):] for mod in bld.env['NS3_MODULES']]
436 for filename in os.listdir("scratch"):
437 if filename.startswith('.') or filename == 'CVS':
439 if os.path.isdir(os.path.join("scratch", filename)):
440 obj = bld.create_ns3_program(filename, all_modules)
441 obj.path = obj.path.find_dir('scratch').find_dir(filename)
442 obj.find_sources_in_dirs('.')
443 obj.target = filename
444 obj.name = obj.target
445 elif filename.endswith(".cc"):
446 name = filename[:-len(".cc")]
447 obj = bld.create_ns3_program(name, all_modules)
448 obj.path = obj.path.find_dir('scratch')
449 obj.source = filename
451 obj.name = obj.target
456 if Options.options.no_task_lines:
458 def null_printout(s):
460 Runner.printout = null_printout
462 Options.cwd_launch = bld.path.abspath()
463 bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
464 bld.create_suid_program = types.MethodType(create_suid_program, bld)
466 # switch default variant to the one matching our debug level
467 variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
468 variant_env = bld.env_of_name(variant_name)
469 bld.all_envs['default'] = variant_env
471 # process subfolders from here
472 bld.add_subdirs('src')
473 bld.add_subdirs('samples utils examples')
475 add_scratch_programs(bld)
477 ## if --enabled-modules option was given, we disable building the
478 ## modules that were not enabled, and programs that depend on
482 if Options.options.enable_modules:
483 Logs.warn("the option --enable-modules is being applied to this build only;"
484 " to make it permanent it needs to be given to waf configure.")
485 env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in
486 Options.options.enable_modules.split(',')]
488 if env['NS3_ENABLED_MODULES']:
489 modules = env['NS3_ENABLED_MODULES']
493 for module in modules:
494 module_obj = Object.name_to_obj(module)
495 if module_obj is None:
496 raise ValueError("module %s not found" % module)
497 for dep in module_obj.add_objects:
498 if not dep.startswith('ns3-'):
500 if dep not in modules:
504 ## remove objects that depend on modules not listed
505 for obj in list(bld.all_task_gen):
506 if hasattr(obj, 'ns3_module_dependencies'):
507 for dep in obj.ns3_module_dependencies:
508 if dep not in modules:
509 bld.all_task_gen.remove(obj)
511 if obj.name in env['NS3_MODULES'] and obj.name not in modules:
512 bld.all_task_gen.remove(obj)
514 ## Create a single ns3 library containing all enabled modules
515 if env['ENABLE_STATIC_NS3']:
516 lib = bld.new_task_gen('cxx', 'staticlib')
520 lib = bld.new_task_gen('cxx', 'shlib')
523 if lib.env['CXX_NAME'] == 'gcc' and env['WL_SONAME_SUPPORTED']:
524 lib.env.append_value('LINKFLAGS', '-Wl,--soname=%s' % ccroot.get_target_name(lib))
525 if sys.platform == 'cygwin':
526 lib.features.append('implib') # workaround for WAF bug #472
528 if env['NS3_ENABLED_MODULES']:
529 lib.add_objects = list(modules)
530 env['NS3_ENABLED_MODULES'] = list(modules)
531 lib.uselib_local = list(modules)
533 lib.add_objects = list(env['NS3_MODULES'])
534 lib.uselib_local = list(env['NS3_MODULES'])
536 bld.add_subdirs('bindings/python')
538 if Options.options.run:
539 # Check that the requested program name is valid
540 program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, wutils.get_command_template(env))
542 # When --run'ing a program, tell WAF to only build that program,
543 # nothing more; this greatly speeds up compilation when all you
544 # want to do is run a test program.
545 if not Options.options.compile_targets:
546 Options.options.compile_targets = os.path.basename(program_name)
547 for gen in bld.all_task_gen:
548 if type(gen).__name__ in ['ns3header_taskgen', 'ns3moduleheader_taskgen']:
551 if Options.options.regression or Options.options.regression_generate:
552 regression_traces = env['REGRESSION_TRACES']
553 if not regression_traces:
554 raise Utils.WafError("Cannot run regression tests: reference traces directory not given"
555 " (--with-regression-traces configure option)")
556 regression.run_regression(bld, regression_traces)
558 if Options.options.check:
564 if wutils.bld is None:
568 #if Options.commands['check']:
571 if Options.options.lcov_report:
574 if Options.options.run:
575 wutils.run_program(Options.options.run, env, wutils.get_command_template(env))
578 if Options.options.pyrun:
579 wutils.run_python_program(Options.options.pyrun, env)
582 if Options.options.shell:
583 raise Utils.WafError("Run `./waf shell' now, instead of `./waf shell'")
585 if Options.options.doxygen:
591 if Options.options.doxygen:
596 check_context = Build.BuildContext
598 """run the NS-3 unit tests (deprecated in favour of --check option)"""
599 raise Utils.WafError("Please run `./waf --check' instead.")
602 class print_introspected_doxygen_task(Task.TaskBase):
603 after = 'cc cxx cc_link cxx_link'
606 def __init__(self, bld):
608 super(print_introspected_doxygen_task, self).__init__(generator=self)
611 return 'print-introspected-doxygen\n'
613 def runnable_status(self):
617 ## generate the trace sources list docs
619 proc_env = wutils.get_proc_env()
621 program_obj = wutils.find_program('print-introspected-doxygen', env)
622 except ValueError: # could happen if print-introspected-doxygen is
623 # not built because of waf configure
624 # --enable-modules=xxx
627 prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env)
628 out = open(os.path.join('..', 'doc', 'introspected-doxygen.h'), 'w')
629 if subprocess.Popen([prog], stdout=out, env=proc_env).wait():
633 class run_python_unit_tests_task(Task.TaskBase):
634 after = 'cc cxx cc_link cxx_link'
637 def __init__(self, bld):
639 super(run_python_unit_tests_task, self).__init__(generator=self)
642 return 'run-python-unit-tests\n'
644 def runnable_status(self):
648 proc_env = wutils.get_proc_env()
649 wutils.run_argv([self.bld.env['PYTHON'], os.path.join("..", "utils", "python-unit-tests.py")],
650 self.bld.env, proc_env, force_no_valgrind=True)
653 class run_a_unit_test_task(Task.TaskBase):
654 after = 'cc cxx cc_link cxx_link'
657 def __init__(self, bld, name_of_test):
659 super(run_a_unit_test_task, self).__init__(generator=self)
660 self.name_of_test = name_of_test
662 program_obj = wutils.find_program("run-tests", self.bld.env)
663 except ValueError, ex:
664 raise Utils.WafError(str(ex))
665 program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
666 self.program_path = program_node.abspath(self.bld.env)
669 return 'run-unit-test(%s)\n' % self.name_of_test
671 def runnable_status(self):
675 #print repr([self.program_path, self.name_of_test])
677 self.retval = wutils.run_argv([self.program_path, self.name_of_test], self.bld.env)
678 except Utils.WafError:
680 #print "running test %s: exit with %i" % (self.name_of_test, retval)
683 class get_list_of_unit_tests_task(Task.TaskBase):
684 after = 'cc cxx cc_link cxx_link'
687 def __init__(self, bld):
689 super(get_list_of_unit_tests_task, self).__init__(generator=self)
693 return 'get-unit-tests-list\n'
695 def runnable_status(self):
700 program_obj = wutils.find_program("run-tests", self.bld.env)
701 except ValueError, ex:
702 raise Utils.WafError(str(ex))
703 program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
704 program_path = program_node.abspath(self.bld.env)
705 proc = subprocess.Popen([program_path, "--ListTests"], stdout=subprocess.PIPE,
706 env=wutils.get_proc_env())
707 self.tests = [l.rstrip() for l in proc.stdout.readlines()]
712 for name_of_test in self.tests:
713 test_tasks.append(run_a_unit_test_task(self.bld, name_of_test))
714 collector = collect_unit_test_results_task(self.bld, list(test_tasks))
715 collector.run_after = list(test_tasks)
716 self.more_tasks = [collector] + test_tasks
719 class collect_unit_test_results_task(Task.TaskBase):
720 after = 'run_a_unit_test_task'
723 def __init__(self, bld, test_tasks):
725 super(collect_unit_test_results_task, self).__init__(generator=self)
726 self.test_tasks = test_tasks
729 return 'collect-unit-tests-results\n'
731 def runnable_status(self):
732 for t in self.run_after:
734 return Task.ASK_LATER
739 for task in self.test_tasks:
741 failed_tasks.append(task)
743 print "C++ UNIT TESTS: %i tests passed, %i failed (%s)." % \
744 (len(self.test_tasks) - len(failed_tasks), len(failed_tasks),
745 ', '.join(t.name_of_test for t in failed_tasks))
748 print "C++ UNIT TESTS: all %i tests passed." % (len(self.test_tasks),)
753 task = get_list_of_unit_tests_task(bld)
754 print_introspected_doxygen_task(bld)
755 if bld.env['ENABLE_PYTHON_BINDINGS']:
756 run_python_unit_tests_task(bld)
759 def check_shell(bld):
760 if 'NS3_MODULE_PATH' not in os.environ:
763 correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH'])
764 found_modpath = os.environ['NS3_MODULE_PATH']
765 if found_modpath != correct_modpath:
766 msg = ("Detected shell (./waf shell) with incorrect configuration\n"
767 "=========================================================\n"
768 "Possible reasons for this problem:\n"
769 " 1. You switched to another ns-3 tree from inside this shell\n"
770 " 2. You switched ns-3 debug level (waf configure --debug)\n"
771 " 3. You modified the list of built ns-3 modules\n"
772 "You should correct this situation before running any program. Possible solutions:\n"
773 " 1. Exit this shell, and start a new one\n"
774 " 2. Run a new nested shell")
775 raise Utils.WafError(msg)
778 shell_context = Build.BuildContext
780 """run a shell with an environment suitably modified to run locally built programs"""
782 #make sure we build first"
785 if sys.platform == 'win32':
786 shell = os.environ.get("COMSPEC", "cmd.exe")
788 shell = os.environ.get("SHELL", "/bin/sh")
791 wutils.run_argv([shell], env, {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
794 if not os.path.exists('doc/introspected-doxygen.h'):
795 Logs.warn("doc/introspected-doxygen.h does not exist; run waf check to generate it.")
798 doxygen_config = os.path.join('doc', 'doxygen.conf')
799 if subprocess.Popen(['doxygen', doxygen_config]).wait():
804 variant_name = env['NS3_ACTIVE_VARIANT']
806 if 'gcov' not in variant_name:
807 raise Utils.WafError("project not configured for code coverage;"
808 " reconfigure with --enable-gcov")
812 lcov_report_dir = os.path.join(variant_name, 'lcov-report')
813 create_dir_command = "rm -rf " + lcov_report_dir
814 create_dir_command += " && mkdir " + lcov_report_dir + ";"
816 if subprocess.Popen(create_dir_command, shell=True).wait():
819 info_file = os.path.join(lcov_report_dir, variant_name + '.info')
820 lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file
821 lcov_command += " --source-dirs=" + os.getcwd()
822 lcov_command += ":" + os.path.join(
823 os.getcwd(), variant_name, 'include')
824 if subprocess.Popen(lcov_command, shell=True).wait():
827 genhtml_command = "../utils/lcov/genhtml -o " + lcov_report_dir
828 genhtml_command += " " + info_file
829 if subprocess.Popen(genhtml_command, shell=True).wait():
838 ## The default WAF DistDir implementation is rather slow, because it
839 ## first copies everything and only later removes unwanted files and
840 ## directories; this means that it needless copies the full build dir
841 ## and the .hg repository tree. Here we provide a replacement DistDir
842 ## implementation that is more efficient.
845 from Scripting import dist_exts, excludes, BLDDIR
849 def _copytree(src, dst, symlinks=False, excludes=(), build_dir=None):
850 """Recursively copy a directory tree using copy2().
852 The destination directory must not already exist.
853 If exception(s) occur, an Error is raised with a list of reasons.
855 If the optional symlinks flag is true, symbolic links in the
856 source tree result in symbolic links in the destination tree; if
857 it is false, the contents of the files pointed to by symbolic
860 XXX Consider this example code rather than the ultimate tool.
862 Note: this is a modified version of shutil.copytree from python
863 2.5.2 library; modified for WAF purposes to exclude dot dirs and
864 another list of files.
866 names = os.listdir(src)
870 srcname = os.path.join(src, name)
871 dstname = os.path.join(dst, name)
873 if symlinks and os.path.islink(srcname):
874 linkto = os.readlink(srcname)
875 os.symlink(linkto, dstname)
876 elif os.path.isdir(srcname):
879 elif name.startswith('.') or name.startswith(',,') or name.startswith('++') or name.startswith('CVS'):
881 elif name == build_dir:
884 ## build_dir is not passed into the recursive
885 ## copytree, but that is intentional; it is a
886 ## directory name valid only at the top level.
887 copytree(srcname, dstname, symlinks, excludes)
891 if name.startswith('.') or name.startswith('++'):
899 shutil.copy2(srcname, dstname)
900 # XXX What about devices, sockets etc.?
901 except (IOError, os.error), why:
902 errors.append((srcname, dstname, str(why)))
903 # catch the Error from the recursive copytree so that we can
904 # continue with other files
905 except shutil.Error, err:
906 errors.extend(err.args[0])
908 shutil.copystat(src, dst)
910 # can't copy file access times on Windows
913 errors.extend((src, dst, str(why)))
915 raise shutil.Error, errors
918 def DistDir(appname, version):
919 #"make a distribution directory with all the sources in it"
922 # Our temporary folder where to put our files
923 TMPFOLDER=appname+'-'+version
925 # Remove an old package directory
926 if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER)
928 global g_dist_exts, g_excludes
930 # Remove the Build dir
931 build_dir = getattr(Utils.g_module, BLDDIR, None)
933 # Copy everything into the new folder
934 _copytree('.', TMPFOLDER, excludes=excludes, build_dir=build_dir)
936 # TODO undocumented hook
937 dist_hook = getattr(Utils.g_module, 'dist_hook', None)
943 # go back to the root directory
947 Scripting.DistDir = DistDir