View | Details | Raw Unified | Return to bug 2884
Collapse All | Expand All

(-)a/contrib/wscript (-493 / +10 lines)
 Lines 1-4    Link Here 
1
2
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
1
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
3
from __future__ import print_function
2
from __future__ import print_function
4
import os, os.path
3
import os, os.path
 Lines 16-24    Link Here 
16
except NameError:
15
except NameError:
17
    from sets import Set as set # Python 2.3 fallback
16
    from sets import Set as set # Python 2.3 fallback
18
17
19
18
all_contrib_modules = []
20
21
all_modules = []
22
for dirname in os.listdir('contrib'):
19
for dirname in os.listdir('contrib'):
23
    if dirname.startswith('.') or dirname == 'CVS':
20
    if dirname.startswith('.') or dirname == 'CVS':
24
        continue
21
        continue
 Lines 26-90    Link Here 
26
    if not os.path.isdir(path):
23
    if not os.path.isdir(path):
27
        continue
24
        continue
28
    if os.path.exists(os.path.join(path, 'wscript')):
25
    if os.path.exists(os.path.join(path, 'wscript')):
29
        all_modules.append(dirname)
26
        all_contrib_modules.append(dirname)
30
all_modules.sort()
27
all_contrib_modules.sort()
31
32
33
28
34
def options(opt):
29
def options(opt):
35
    opt.add_option('--enable-rpath',
30
    for module in all_contrib_modules:
36
                   help=("Link programs with rpath"
37
                         " (normally not needed, see "
38
                         " --run and --shell; moreover, only works in some"
39
                         " specific platforms, such as Linux and Solaris)"),
40
                   action="store_true", dest='enable_rpath', default=False)
41
    
42
    opt.add_option('--enable-modules',
43
                   help=("Build only these modules (and dependencies)"),
44
                   dest='enable_modules')
45
46
    opt.load('boost', tooldir=['waf-tools'])
47
48
    for module in all_modules:
49
        opt.recurse(module, mandatory=False)
31
        opt.recurse(module, mandatory=False)
50
32
51
def configure(conf):
33
def configure(conf):
52
    if not conf.env['REQUIRED_BOOST_LIBS']:
34
    for module in all_contrib_modules:
53
        conf.env['REQUIRED_BOOST_LIBS'] = []
54
    for module in all_modules:
55
        conf.recurse (module, name="required_boost_libs", mandatory=False)
56
57
    if conf.env['REQUIRED_BOOST_LIBS'] is not []:
58
        conf.load('boost')
59
        conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), mandatory=False)
60
        if not conf.env['LIB_BOOST']:
61
            conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), libpath="/usr/lib64", mandatory=False)
62
            if not conf.env['LIB_BOOST']:
63
                conf.env['LIB_BOOST'] = []
64
65
    # Append blddir to the module path before recursing into modules
66
    blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
67
    conf.env.append_value('NS3_MODULE_PATH', blddir)
68
69
    for module in all_modules:
70
        conf.recurse(module, mandatory=False)
35
        conf.recurse(module, mandatory=False)
71
36
72
    # Remove duplicate path items
73
    conf.env['NS3_MODULE_PATH'] = wutils.uniquify_list(conf.env['NS3_MODULE_PATH'])
74
75
    if Options.options.enable_rpath:
76
        conf.env.append_value('RPATH', '-Wl,-rpath,%s' % (os.path.join(blddir),))
77
78
    ## Used to link the 'test-runner' program with all of ns-3 code
37
    ## Used to link the 'test-runner' program with all of ns-3 code
79
    conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
38
    conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_contrib_modules]
80
81
39
82
40
83
# we need the 'ns3module' waf "feature" to be created because code
41
# we need the 'ns3module' waf "feature" to be created because code
84
# elsewhere looks for it to find the ns3 module objects.
42
# elsewhere looks for it to find the ns3 module objects.
85
@TaskGen.feature('ns3module')
86
def _add_test_code(module):
87
    pass
88
43
89
def create_ns3_module(bld, name, dependencies=(), test=False):
44
def create_ns3_module(bld, name, dependencies=(), test=False):
90
    static = bool(bld.env.ENABLE_STATIC_NS3)
45
    static = bool(bld.env.ENABLE_STATIC_NS3)
 Lines 143-157    Link Here 
143
    
98
    
144
    return module
99
    return module
145
100
146
@TaskGen.feature("ns3testlib")
147
@TaskGen.before_method("apply_incpaths")
148
def apply_incpaths_ns3testlib(self):
149
    if not self.source:
150
        return
151
    testdir = self.source[-1].parent.path_from(self.bld.srcnode)
152
    self.env.append_value("DEFINES", 'NS_TEST_SOURCEDIR="%s"' % (testdir,))
153
154
155
def create_ns3_module_test_library(bld, name):
101
def create_ns3_module_test_library(bld, name):
156
    # Create an ns3 module for the test library that depends only on
102
    # Create an ns3 module for the test library that depends only on
157
    # the module being tested.
103
    # the module being tested.
 Lines 183-189    Link Here 
183
129
184
130
185
def ns3_python_bindings(bld):
131
def ns3_python_bindings(bld):
186
187
    # this method is called from a module wscript, so remember bld.path is not bindings/python!
132
    # this method is called from a module wscript, so remember bld.path is not bindings/python!
188
    module_abs_src_path = bld.path.abspath()
133
    module_abs_src_path = bld.path.abspath()
189
    module = os.path.basename(module_abs_src_path)
134
    module = os.path.basename(module_abs_src_path)
 Lines 305-311    Link Here 
305
250
306
    return pymod
251
    return pymod
307
252
308
309
def build(bld):
253
def build(bld):
310
    bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
254
    bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
311
    bld.create_ns3_module_test_library = types.MethodType(create_ns3_module_test_library, bld)
255
    bld.create_ns3_module_test_library = types.MethodType(create_ns3_module_test_library, bld)
 Lines 315-753    Link Here 
315
    # Remove these modules from the list of all modules.
259
    # Remove these modules from the list of all modules.
316
    for not_built in bld.env['MODULES_NOT_BUILT']:
260
    for not_built in bld.env['MODULES_NOT_BUILT']:
317
261
318
        # XXX Because these modules are located in subdirectories of
262
        if not_built in all_contrib_modules:
319
        # test, their names in the all_modules list include the extra
263
            all_contrib_modules.remove(not_built)
320
        # relative path "test/".  If these modules are moved into the
321
        # src directory, then this if block should be removed.
322
        if not_built == 'ns3tcp' or not_built == 'ns3wifi':
323
            not_built = 'test/' + not_built
324
264
325
        if not_built in all_modules:
265
    bld.recurse(list(all_contrib_modules))
326
            all_modules.remove(not_built)
327
266
328
    bld.recurse(list(all_modules))
267
    for module in all_contrib_modules:
329
330
    for module in all_modules:
331
        modheader = bld(features='ns3moduleheader')
268
        modheader = bld(features='ns3moduleheader')
332
        modheader.module = module.split('/')[-1]
269
        modheader.module = module.split('/')[-1]
333
270
334
class ns3pcfile_task(Task.Task):
335
    after = 'cxx'
336
337
    def __str__(self):
338
        "string to display to the user"
339
        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
340
        return 'pcfile: %s\n' % (tgt_str)
341
342
    def runnable_status(self):
343
        return super(ns3pcfile_task, self).runnable_status()
344
345
    def _self_libs(self, env, name, libdir):
346
        if env['ENABLE_STATIC_NS3']:
347
            path_st = 'STLIBPATH_ST'
348
            lib_st = 'STLIB_ST'
349
            lib_marker = 'STLIB_MARKER'
350
        else:
351
            path_st = 'LIBPATH_ST'
352
            lib_st = 'LIB_ST'
353
            lib_marker = 'SHLIB_MARKER'
354
        retval = [env[path_st] % libdir]
355
        if env[lib_marker]:
356
            retval.append(env[lib_marker])
357
        retval.append(env[lib_st] % name)
358
        return retval
359
360
    def _lib(self, env, dep):
361
        libpath = env['LIBPATH_%s' % dep]
362
        linkflags = env['LINKFLAGS_%s' % dep]
363
        libs = env['LIB_%s' % dep]
364
        retval = []
365
        for path in libpath:
366
            retval.append(env['LIBPATH_ST'] % path)
367
            retval = retval + linkflags
368
        for lib in libs:
369
            retval.append(env['LIB_ST'] % lib)
370
        return retval
371
372
    def _listify(self, v):
373
        if isinstance(v, list):
374
            return v
375
        else:
376
            return [v]
377
378
    def _cflags(self, dep):
379
        flags = self.env['CFLAGS_%s' % dep]
380
        return self._listify(flags)
381
382
    def _cxxflags(self, dep):
383
        return self._listify(self.env['CXXFLAGS_%s' % dep])
384
385
    def _defines(self, dep):
386
        return [self.env['DEFINES_ST'] % define for define in self.env['DEFINES_%s' % dep]] 
387
388
    def _includes(self, dep):
389
        includes = self.env['INCLUDES_%s' % dep]
390
        return [self.env['CPPPATH_ST'] % include for include in includes]
391
392
    def _generate_pcfile(self, name, use, env, outfilename):
393
        outfile = open(outfilename, 'wt')
394
        prefix = env.PREFIX
395
        includedir = Utils.subst_vars('${INCLUDEDIR}/%s%s' % (wutils.APPNAME, wutils.VERSION), env)
396
        libdir = env.LIBDIR
397
        libs = self._self_libs(env, "%s%s-%s%s" % (wutils.APPNAME, wutils.VERSION, name[4:], env.BUILD_SUFFIX), '${libdir}')
398
        for dep in use:
399
            libs += self._lib(env, dep)
400
        for dep in env.LIBS:
401
            libs += self.env['LIB_ST'] % dep
402
        cflags = [self.env['CPPPATH_ST'] % '${includedir}']
403
        requires = []
404
        for dep in use:
405
            cflags = cflags + self._cflags(dep) + self._cxxflags(dep) + \
406
                self._defines(dep) + self._includes(dep)
407
            if dep.startswith('ns3-'):
408
                dep_name = dep[4:]
409
                requires.append("libns%s-%s%s" % (wutils.VERSION, dep_name, env.BUILD_SUFFIX))
410
        print("""\
411
prefix=%s
412
libdir=%s
413
includedir=%s
414
415
Name: lib%s
416
Description: ns-3 module %s
417
Version: %s
418
Libs: %s
419
Cflags: %s
420
Requires: %s\
421
""" % (prefix, libdir, includedir,
422
       name, name, wutils.VERSION, ' '.join(libs), ' '.join(cflags), ' '.join(requires)), file=outfile)
423
        outfile.close()
424
425
    def run(self):
426
        output_filename = self.outputs[0].abspath()
427
        self._generate_pcfile(self.module.name, 
428
                              self.module.to_list(self.module.use),
429
                              self.env, output_filename)
430
431
432
@TaskGen.feature('ns3pcfile')
433
@TaskGen.after_method('process_rule')
434
def apply(self):
435
    module = self.bld.find_ns3_module(self.module)
436
    output_filename = 'lib%s.pc' % os.path.basename(module.target)
437
    output_node = self.path.find_or_declare(output_filename)
438
    assert output_node is not None, str(self)
439
    task = self.create_task('ns3pcfile')
440
    self.bld.install_files('${LIBDIR}/pkgconfig', output_node)
441
    task.set_outputs([output_node])
442
    task.module = module
443
444
445
446
@TaskGen.feature('ns3header')
447
@TaskGen.after_method('process_rule')
448
def apply_ns3header(self):
449
    if self.module is None:
450
        raise WafError("'module' missing on ns3headers object %s" % self)
451
    ns3_dir_node = self.bld.path.find_or_declare("ns3")
452
    for filename in set(self.to_list(self.source)):
453
        src_node = self.path.find_resource(filename)
454
        if src_node is None:
455
            raise WafError("source ns3 header file %s not found" % (filename,))
456
        dst_node = ns3_dir_node.find_or_declare(src_node.name)
457
        assert dst_node is not None
458
        task = self.create_task('ns3header')
459
        task.mode = getattr(self, 'mode', 'install')
460
        if task.mode == 'install':
461
            self.bld.install_files('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION), [src_node])
462
            task.set_inputs([src_node])
463
            task.set_outputs([dst_node])
464
        else:
465
            task.header_to_remove = dst_node
466
    self.headers = set(self.to_list(self.source))
467
    self.source = '' # tell WAF not to process these files further
468
469
470
class ns3header_task(Task.Task):
471
    before = 'cxx gen_ns3_module_header'
472
    color = 'BLUE'
473
474
    def __str__(self):
475
        "string to display to the user"
476
        env = self.env
477
        src_str = ' '.join([a.bldpath() for a in self.inputs])
478
        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
479
        if self.outputs: sep = ' -> '
480
        else: sep = ''
481
        if self.mode == 'remove':
482
            return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),)
483
        return 'install-ns3-header: %s' % (tgt_str)
484
485
    def __repr__(self):
486
        return str(self)
487
488
    def uid(self):
489
        try:
490
            return self.uid_
491
        except AttributeError:
492
            m = Utils.md5()
493
            up = m.update
494
            up(self.__class__.__name__.encode())
495
            for x in self.inputs + self.outputs:
496
                up(x.abspath().encode())
497
            up(self.mode.encode())
498
            if self.mode == 'remove':
499
                up(self.header_to_remove.abspath().encode())
500
            self.uid_ = m.digest()
501
            return self.uid_
502
503
    def runnable_status(self):
504
        if self.mode == 'remove':
505
            if os.path.exists(self.header_to_remove.abspath()):
506
                return Task.RUN_ME
507
            else:
508
                return Task.SKIP_ME
509
        else:
510
            return super(ns3header_task, self).runnable_status()
511
512
    def run(self):
513
        if self.mode == 'install':
514
            assert len(self.inputs) == len(self.outputs)
515
            inputs = [node.abspath() for node in self.inputs]
516
            outputs = [node.abspath() for node in self.outputs]
517
            for src, dst in zip(inputs, outputs):
518
                try:
519
                    os.chmod(dst, 0o600)
520
                except OSError:
521
                    pass
522
                shutil.copy2(src, dst)
523
                ## make the headers in builddir read-only, to prevent
524
                ## accidental modification
525
                os.chmod(dst, 0o400)
526
            return 0
527
        else:
528
            assert len(self.inputs) == 0
529
            assert len(self.outputs) == 0
530
            out_file_name = self.header_to_remove.abspath()
531
            try:
532
                os.unlink(out_file_name)
533
            except OSError as ex:
534
                if ex.errno != 2:
535
                    raise
536
            return 0
537
538
539
@TaskGen.feature('ns3privateheader')
540
@TaskGen.after_method('process_rule')
541
def apply_ns3privateheader(self):
542
    if self.module is None:
543
        raise WafError("'module' missing on ns3headers object %s" % self)
544
    ns3_dir_node = self.bld.path.find_or_declare("ns3/private")
545
    for filename in set(self.to_list(self.source)):
546
        src_node = self.path.find_resource(filename)
547
        if src_node is None:
548
            raise WafError("source ns3 header file %s not found" % (filename,))
549
        dst_node = ns3_dir_node.find_or_declare(src_node.name)
550
        assert dst_node is not None
551
        task = self.create_task('ns3privateheader')
552
        task.mode = getattr(self, 'mode', 'install')
553
        if task.mode == 'install':
554
            task.set_inputs([src_node])
555
            task.set_outputs([dst_node])
556
        else:
557
            task.header_to_remove = dst_node
558
    self.headers = set(self.to_list(self.source))
559
    self.source = '' # tell WAF not to process these files further
560
561
class ns3privateheader_task(Task.Task):
562
    before = 'cxx gen_ns3_module_header'
563
    after = 'ns3header'
564
    color = 'BLUE'
565
566
    def __str__(self):
567
        "string to display to the user"
568
        env = self.env
569
        src_str = ' '.join([a.bldpath() for a in self.inputs])
570
        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
571
        if self.outputs: sep = ' -> '
572
        else: sep = ''
573
        if self.mode == 'remove':
574
            return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),)
575
        return 'install-ns3-header: %s' % (tgt_str)
576
577
    def __repr__(self):
578
        return str(self)
579
580
    def uid(self):
581
        try:
582
            return self.uid_
583
        except AttributeError:
584
            m = Utils.md5()
585
            up = m.update
586
            up(self.__class__.__name__.encode())
587
            for x in self.inputs + self.outputs:
588
                up(x.abspath().encode())
589
            up(self.mode.encode())
590
            if self.mode == 'remove':
591
                up(self.header_to_remove.abspath().encode())
592
            self.uid_ = m.digest()
593
            return self.uid_
594
595
    def runnable_status(self):
596
        if self.mode == 'remove':
597
            if os.path.exists(self.header_to_remove.abspath()):
598
                return Task.RUN_ME
599
            else:
600
                return Task.SKIP_ME
601
        else:
602
            return super(ns3privateheader_task, self).runnable_status()
603
604
    def run(self):
605
        if self.mode == 'install':
606
            assert len(self.inputs) == len(self.outputs)
607
            inputs = [node.abspath() for node in self.inputs]
608
            outputs = [node.abspath() for node in self.outputs]
609
            for src, dst in zip(inputs, outputs):
610
                try:
611
                    os.chmod(dst, 0o600)
612
                except OSError:
613
                    pass
614
                shutil.copy2(src, dst)
615
                ## make the headers in builddir read-only, to prevent
616
                ## accidental modification
617
                os.chmod(dst, 0o400)
618
            return 0
619
        else:
620
            assert len(self.inputs) == 0
621
            assert len(self.outputs) == 0
622
            out_file_name = self.header_to_remove.abspath()
623
            try:
624
                os.unlink(out_file_name)
625
            except OSError as ex:
626
                if ex.errno != 2:
627
                    raise
628
            return 0
629
630
631
class gen_ns3_module_header_task(Task.Task):
632
    before = 'cxx'
633
    after = 'ns3header'
634
    color = 'BLUE'
635
636
    def runnable_status(self):
637
        if self.mode == 'remove':
638
            if os.path.exists(self.header_to_remove.abspath()):
639
                return Task.RUN_ME
640
            else:
641
                return Task.SKIP_ME
642
        else:
643
            return super(gen_ns3_module_header_task, self).runnable_status()
644
645
    def __str__(self):
646
        "string to display to the user"
647
        env = self.env
648
        src_str = ' '.join([a.bldpath() for a in self.inputs])
649
        tgt_str = ' '.join([a.bldpath() for a in self.outputs])
650
        if self.outputs: sep = ' -> '
651
        else: sep = ''
652
        if self.mode == 'remove':
653
            return 'rm-module-header %s' % (self.header_to_remove.abspath(),)
654
        return 'gen-module-header: %s' % (tgt_str)
655
656
    def run(self):
657
        if self.mode == 'remove':
658
            assert len(self.inputs) == 0
659
            assert len(self.outputs) == 0
660
            out_file_name = self.header_to_remove.abspath()
661
            try:
662
                os.unlink(out_file_name)
663
            except OSError as ex:
664
                if ex.errno != 2:
665
                    raise
666
            return 0
667
        assert len(self.outputs) == 1
668
        out_file_name = self.outputs[0].get_bld().abspath()#self.env)
669
        header_files = [os.path.basename(node.abspath()) for node in self.inputs]
670
        outfile = open(out_file_name, "w")
671
        header_files.sort()
672
673
        print("""
674
#ifdef NS3_MODULE_COMPILATION
675
# error "Do not include ns3 module aggregator headers from other modules; these are meant only for end user scripts."
676
#endif
677
678
#ifndef NS3_MODULE_%s
679
    """ % (self.module.upper().replace('-', '_'),), file=outfile)
680
681
    #     if self.module_deps:
682
    #         print >> outfile, "// Module dependencies:"
683
    #     for dep in self.module_deps:
684
    #         print >> outfile, "#include \"%s-module.h\"" % dep
685
686
        print(file=outfile)
687
        print("// Module headers:", file=outfile)
688
        for header in header_files:
689
            print("#include \"%s\"" % (header,), file=outfile)
690
691
        print("#endif", file=outfile)
692
693
        outfile.close()
694
        return 0
695
696
    def sig_explicit_deps(self):
697
        self.m.update('\n'.join(sorted([node.abspath() for node in self.inputs])).encode('utf-8'))
698
        return self.m.digest()
699
700
    def unique_id(self):
701
        try:
702
            return self.uid
703
        except AttributeError:
704
            "this is not a real hot zone, but we want to avoid surprizes here"
705
            m = Utils.md5()
706
            m.update("ns-3-module-header-%s" % self.module)
707
            self.uid = m.digest()
708
            return self.uid
709
710
711
# Generates a 'ns3/foo-module.h' header file that includes all public
712
# ns3 headers of a certain module.
713
@TaskGen.feature('ns3moduleheader')
714
@TaskGen.after_method('process_rule')
715
def apply_ns3moduleheader(self):
716
    ## get all of the ns3 headers
717
    ns3_dir_node = self.bld.path.find_or_declare("ns3")
718
    all_headers_inputs = []
719
    found_the_module = False
720
    for ns3headers in self.bld.all_task_gen:
721
        if 'ns3header' in getattr(ns3headers, "features", []):
722
            if ns3headers.module != self.module:
723
                continue
724
            found_the_module = True
725
            for source in sorted(ns3headers.headers):
726
                source = os.path.basename(source)
727
                node = ns3_dir_node.find_or_declare(os.path.basename(source))
728
                if node is None:
729
                    fatal("missing header file %s" % (source,))
730
                all_headers_inputs.append(node)
731
    if not found_the_module:
732
        raise WafError("error finding headers for module %s" % self.module)
733
    if not all_headers_inputs:
734
        return
735
736
    try:
737
        module_obj = self.bld.get_tgen_by_name("ns3-" + self.module)
738
    except WafError: # maybe the module was disabled, and therefore removed
739
        return
740
741
    all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)]
742
    task = self.create_task('gen_ns3_module_header')
743
    task.module = self.module
744
    task.mode = getattr(self, "mode", "install")
745
    if task.mode == 'install':
746
        assert module_obj is not None, self.module
747
        self.bld.install_files('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION),
748
                               ns3_dir_node.find_or_declare("%s-module.h" % self.module))
749
        task.set_inputs(all_headers_inputs)
750
        task.set_outputs(all_headers_outputs)
751
        task.module_deps = module_obj.module_deps
752
    else:
753
        task.header_to_remove = all_headers_outputs[0]

Return to bug 2884