ns3waf/__init__.py
changeset 66 2fe1f3e576c9
child 69 19d7af80f47f
equal deleted inserted replaced
65:227f6347e4e1 66:2fe1f3e576c9
       
     1 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
       
     2 
       
     3 import waflib
       
     4 
       
     5 def options(opt):
       
     6     opt.tool_options('compiler_cc')
       
     7     opt.tool_options('compiler_cxx')
       
     8     opt.add_option('--enable-static',
       
     9                    help=('Compile module statically: works only on linux, without python'),
       
    10                    dest='enable_static', action='store_true',
       
    11                    default=False)
       
    12     opt.add_option('--disable-log',
       
    13                    help=('Do not compile into the code the log output instructions.'),
       
    14                    dest='enable_log', action='store_false',
       
    15                    default=True)
       
    16     opt.add_option('--disable-assert',
       
    17                    help='Do not compile into the code the assert checks.',
       
    18                    dest='enable_assert', action='store_false',
       
    19                    default=True)
       
    20     opt.add_option('--enable-gcov',
       
    21                    help='Enable code coverage collection.',
       
    22                    dest='enable_gcov', action='store_true',
       
    23                    default=False)
       
    24     opt.add_option('--disable-examples', help='Disable compilation of examples',
       
    25                    dest='enable_examples', action='store_false',
       
    26                    default=True)
       
    27     opt.add_option('--disable-tests', help='Disable compilation of tests',
       
    28                    dest='enable_tests', action='store_false',
       
    29                    default=True)
       
    30     opt.add_option('--disable-debug', help='Disable generation of debug information',
       
    31                    dest='enable_debug', action='store_false',
       
    32                    default=True)
       
    33 
       
    34 def _report_optional_feature(conf, name, caption, was_enabled, reason_not_enabled):
       
    35     if not 'NS3_OPTIONAL_FEATURES' in conf.env:
       
    36         conf.env['NS3_OPTIONAL_FEATURES'] = []
       
    37     conf.env['NS3_OPTIONAL_FEATURES'].append((name, caption, was_enabled, reason_not_enabled))
       
    38 
       
    39 
       
    40 def _check_compilation_flag(conf, flag, mode='cxx'):
       
    41     """
       
    42     Checks if the C++ compiler accepts a certain compilation flag or flags
       
    43     flag: can be a string or a list of strings
       
    44     """
       
    45     try:
       
    46         if mode == 'cxx':
       
    47             conf.check_cc(fragment='#include <stdio.h>\nint main() { return 0; }\n',
       
    48                           cflags=flag,
       
    49                           execute = False, msg = "Checking for %s" % flag)
       
    50         else:
       
    51             conf.check_cxx(fragment='#include <stdio.h>\nint main() { return 0; }\n',
       
    52                            cxxflags=flag,
       
    53                            execute = False, msg = "Checking for %s" % flag)
       
    54 
       
    55     except conf.errors.ConfigurationError:
       
    56         ok = False
       
    57     else:
       
    58         ok = True
       
    59     return ok
       
    60 
       
    61 
       
    62 def _print_optional_features(conf):
       
    63     # Write a summary of optional features status
       
    64     print "---- Summary of optional NS-3 features:"
       
    65     for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']:
       
    66         if was_enabled:
       
    67             status = 'enabled'
       
    68         else:
       
    69             status = 'not enabled (%s)' % reason_not_enabled
       
    70         print "%-30s: %s" % (caption, status)
       
    71 
       
    72 def _check_static(conf):
       
    73     import Options
       
    74     import sys
       
    75     import re
       
    76     import os
       
    77     env = conf.env
       
    78     env['NS3_ENABLE_STATIC'] = False
       
    79     if Options.options.enable_static:
       
    80         if sys.platform.startswith('linux') and \
       
    81                 env['CXX_NAME'] in ['gcc', 'icc']:
       
    82             if re.match('i[3-6]86', os.uname()[4]):
       
    83                 _report_optional_feature(conf, "static", "Static build", True, '')
       
    84                 env['NS3_ENABLE_STATIC'] = True
       
    85             elif os.uname()[4] == 'x86_64':
       
    86                 if env['NS3_ENABLE_PYTHON_BINDINGS'] and \
       
    87                         not _check_compilation_flag(conf, '-mcmodel=large'):
       
    88                     _report_optional_feature(conf, "static", "Static build", False,
       
    89                                              "Can't enable static builds because " + \
       
    90                                                  "no -mcmodel=large compiler " \
       
    91                                                  "option. Try --disable-python or upgrade your " \
       
    92                                                  "compiler to at least gcc 4.3.x.")
       
    93                 else:
       
    94                     _report_optional_feature(conf, "static", "Static build", True, '')
       
    95                     env['NS3_ENABLE_STATIC'] = True                    
       
    96         elif env['CXX_NAME'] == 'gcc' and \
       
    97                 (sys.platform.startswith('darwin') or \
       
    98                      sys.platform.startswith('cygwin')):
       
    99                 _report_optional_feature(conf, "static", "Static build", True, '')
       
   100                 env['NS3_ENABLE_STATIC'] = True
       
   101         else:
       
   102             _report_optional_feature(conf, "static", "Static build", False,
       
   103                                      "Unsupported platform")
       
   104     else:
       
   105         _report_optional_feature(conf, "static", "Static build", False,
       
   106                                  "option --enable-static not selected")
       
   107     # These flags are used for the implicitly dependent modules.
       
   108     if env['NS3_ENABLE_STATIC']:
       
   109         if sys.platform == 'darwin':
       
   110             env['STLIB_MARKER'] = '-Wl,-all_load'
       
   111         else:
       
   112             env['STLIB_MARKER'] = '-Wl,--whole-archive,-Bstatic'
       
   113             env['SHLIB_MARKER'] = '-Wl,-Bdynamic,--no-whole-archive'
       
   114 
       
   115 def _check_win32(conf):
       
   116     import Options
       
   117     import sys
       
   118     import subprocess
       
   119     import os
       
   120     env = conf.env
       
   121     if conf.env['CXX_NAME'] in ['gcc', 'icc']:
       
   122         if sys.platform == 'win32':
       
   123             env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
       
   124         elif sys.platform == 'cygwin':
       
   125             env.append_value("LINKFLAGS", "-Wl,--enable-auto-import")
       
   126 
       
   127         cxx, = env['CXX']
       
   128 
       
   129         p = subprocess.Popen([cxx, '-print-file-name=libstdc++.so'], stdout=subprocess.PIPE)
       
   130         libstdcxx_location = os.path.dirname(p.stdout.read().strip())
       
   131         p.wait()
       
   132         if libstdcxx_location:
       
   133             conf.env.append_value('NS3_MODULE_PATH', libstdcxx_location)
       
   134 
       
   135         if Options.platform in ['linux']:
       
   136             if _check_compilation_flag(conf, '-Wl,--soname=foo'):
       
   137                 env['WL_SONAME_SUPPORTED'] = True
       
   138 
       
   139 
       
   140 def _check_dependencies(conf, required, mandatory):
       
   141     found = []
       
   142     for module in required:
       
   143         retval = conf.check_cfg(package = 'libns3-%s' % module.lower(),
       
   144                                 args='--cflags --libs', mandatory=mandatory,
       
   145                                 msg="Checking for ns3-%s" % module.lower(),
       
   146                                 uselib_store='NS3_%s' % module.upper())
       
   147         if not retval is None:
       
   148             found.append(module)
       
   149     import copy
       
   150     if not 'NS3_MODULES_FOUND' in conf.env:
       
   151         conf.env['NS3_MODULES_FOUND'] = []
       
   152     conf.env['NS3_MODULES_FOUND'] = conf.env['NS3_MODULES_FOUND'] + copy.copy(found)
       
   153 
       
   154 def modules_uselib(bld, names):
       
   155     return ['NS3_%s' % name.upper() for name in names] + \
       
   156         ['NS3_LIBRARY_%s' % name.upper() for name in names] + \
       
   157         ['NS3_HEADERS_%s' % name.upper() for name in names]
       
   158 
       
   159 def modules_found(bld, needed):
       
   160     for module in needed:
       
   161         if not module in bld.env['NS3_MODULES_FOUND']:
       
   162             return False
       
   163     return True
       
   164 
       
   165 def _c_libname(bld, name):
       
   166     libname = 'ns3-' + name
       
   167     if bld.env['NS3_ENABLE_STATIC']:
       
   168         return bld.env['cstlib_PATTERN'] % libname
       
   169     else:
       
   170         return bld.env['cshlib_PATTERN'] % libname
       
   171 
       
   172 def check_modules(conf, modules, mandatory = True):
       
   173     import Options
       
   174     import os
       
   175 
       
   176     if not 'NS3_CHECK_MODULE_ONCE' in conf.env:
       
   177         conf.env['NS3_CHECK_MODULE_ONCE'] = ''
       
   178         conf.check_tool('compiler_cc')
       
   179         conf.check_tool('compiler_cxx')
       
   180         conf.check_cfg(atleast_pkgconfig_version='0.0.0')
       
   181         _check_win32(conf)
       
   182         _check_static(conf)
       
   183         if Options.options.enable_log:
       
   184             _report_optional_feature(conf, "log", "Logging", True, '')
       
   185             conf.env.append_value('DEFINES', 'NS3_LOG_ENABLE')
       
   186         else:
       
   187             _report_optional_feature(conf, "log", "Logging", False, 
       
   188                                      'option --disable-log selected')
       
   189         if Options.options.enable_assert:
       
   190             _report_optional_feature(conf, "assert", "Assert checks", True, '')
       
   191             conf.env.append_value('DEFINES', 'NS3_ASSERT_ENABLE')
       
   192         else:
       
   193             _report_optional_feature(conf, "assert", "Assert checks", False, 
       
   194                                      'option --disable-assert selected')
       
   195         if Options.options.enable_gcov:
       
   196             _report_optional_feature(conf, "coverage", "Code coverage", True, '')
       
   197             conf.env.append_value('CFLAGS', '-fprofile-arcs')
       
   198             conf.env.append_value('CFLAGS', '-ftest-coverage')
       
   199             conf.env.append_value('CXXFLAGS', '-fprofile-arcs')
       
   200             conf.env.append_value('CXXFLAGS', '-ftest-coverage')
       
   201             conf.env.append_value('LINKFLAGS', '-fprofile-arcs')
       
   202         else:
       
   203             _report_optional_feature(conf, "coverage", "Code coverage", False, 
       
   204                                      'option --enable-gcov not selected')
       
   205         if Options.options.enable_examples:
       
   206             _report_optional_feature(conf, "examples", "Example programs", True, '')
       
   207             conf.env['NS3_ENABLE_EXAMPLES'] = True
       
   208         else:
       
   209             _report_optional_feature(conf, "examples", "Example programs", False, 
       
   210                                      'option --disable-examples selected')
       
   211             conf.env['NS3_ENABLE_EXAMPLES'] = False
       
   212 
       
   213         if Options.options.enable_tests:
       
   214             _report_optional_feature(conf, "tests", "Test programs", True, '')
       
   215             conf.env['NS3_ENABLE_TESTS'] = True
       
   216         else:
       
   217             _report_optional_feature(conf, "tests", "Test programs", False, 
       
   218                                      'option --disable-tests selected')
       
   219             conf.env['NS3_ENABLE_TESTS'] = False            
       
   220 
       
   221         if Options.options.enable_debug:
       
   222             if 'CXXFLAGS' in conf.env:
       
   223                 tmp = conf.env['CXXFLAGS']
       
   224             else:
       
   225                 tmp = []
       
   226             conf.env['CXXFLAGS'] = tmp + ['-g']
       
   227             if 'CFLAGS' in conf.env:
       
   228                 tmp = conf.env['CFLAGS']
       
   229             else:
       
   230                 tmp = []
       
   231             conf.env['CFLAGS'] = tmp + ['-g']
       
   232             _report_optional_feature(conf, "debug", "Debug Symbols", True, '')
       
   233         else:
       
   234             _report_optional_feature(conf, "debug", "Debug Symbols", False, 
       
   235                                      'option --disable-debug selected')
       
   236 
       
   237     _check_dependencies(conf, modules, mandatory)
       
   238 
       
   239 def print_feature_summary(conf):
       
   240     _print_optional_features(conf)
       
   241 
       
   242 def _dirs(source):
       
   243     import os
       
   244     dirs = [os.path.dirname(s) for s in source]
       
   245     def uniq(l):
       
   246         d = dict()
       
   247         for i in l:
       
   248             d[i] = True
       
   249         return d.keys()
       
   250     return uniq(dirs)
       
   251 
       
   252 def _build_library(bld, name, *k, **kw):
       
   253     import os
       
   254     source = kw.get('source')
       
   255     if source is None:
       
   256         return
       
   257     cxxflags = []
       
   258     cflags = []
       
   259     linkflags = []
       
   260     ccdefines = ['NS3_MODULE_COMPILATION']
       
   261     cxxdefines = ['NS3_MODULE_COMPILATION']
       
   262     includes = _dirs(source)
       
   263     target = os.path.join('lib', 'ns3-%s' % name)
       
   264     if not bld.env['NS3_ENABLE_STATIC']:
       
   265         if bld.env['CXX_NAME'] in ['gcc', 'icc'] and bld.env['WL_SONAME_SUPPORTED']:
       
   266             linkflags.append('-Wl,--soname=%s' % _c_libname(bld, name))
       
   267             pass
       
   268         elif bld.env['CXX_NAME'] in ['gcc', 'icc'] and \
       
   269                 os.uname()[4] == 'x86_64' and \
       
   270                 bld.env['NS3_ENABLE_PYTHON_BINDINGS']:
       
   271             # enable that flag for static builds only on x86-64 platforms
       
   272             # when gcc is present and only when we want python bindings
       
   273             # (it's more efficient to not use this option if we can avoid it)
       
   274             cxxflags.append('-mcmodel=large')
       
   275             cflags.append('-mcmodel=large')
       
   276     if bld.env['NS3_ENABLE_STATIC']:
       
   277         lib_type = 'stlib'
       
   278     else:
       
   279         lib_type = 'shlib'
       
   280     features = waflib.Tools.c_aliases.sniff_features(source=source, _type=lib_type)
       
   281     kw['features'] = features
       
   282     kw['target'] = target
       
   283     kw['cxxflags'] = kw.get('cxxflags', []) + cxxflags
       
   284     kw['cflags'] = kw.get('cflags', []) + cflags
       
   285     kw['linkflags'] = kw.get('linkflags', []) + linkflags
       
   286     kw['ccdefines'] = kw.get('ccdefines', []) + ccdefines
       
   287     kw['cxxdefines'] = kw.get('cxxdefines', []) + cxxdefines
       
   288     kw['includes'] = kw.get('includes', []) + includes
       
   289     bld(*k, **kw)
       
   290     bld(name='NS3_LIBRARY_%s' % name.upper(), use=[target])
       
   291 
       
   292 
       
   293 def _build_headers(bld, name, headers):
       
   294     if headers is None:
       
   295         return
       
   296     import os
       
   297     import shutil
       
   298     def run(task):
       
   299         out_dir = os.path.dirname(task.outputs[0].abspath())
       
   300         for header in task.inputs:
       
   301             dst = os.path.join(out_dir, os.path.basename(header.abspath()))
       
   302             src = header.abspath()
       
   303             shutil.copyfile(src, dst)
       
   304 
       
   305         outfile = file(task.outputs[0].abspath(), "w")
       
   306 
       
   307         print >> outfile, """
       
   308 #ifdef NS3_MODULE_COMPILATION
       
   309 # error "Do not include ns3 module aggregator headers from other modules; these are meant only for end user scripts."
       
   310 #endif
       
   311 
       
   312 #ifndef NS3_MODULE_%s
       
   313     """ % (name.upper().replace('-', '_'),)
       
   314 
       
   315         print >> outfile
       
   316         print >> outfile, "// Module headers:"
       
   317         for header in [src.abspath() for src in task.inputs]:
       
   318             print >> outfile, "#include \"%s\"" % (os.path.basename(header),)
       
   319 
       
   320         print >> outfile, "#endif"
       
   321 
       
   322         outfile.close()
       
   323     target = os.path.join('include', 'ns3', '%s-module.h' % name)
       
   324     bld(rule=run, source=headers, target=target)
       
   325     bld(use=[target], target='NS3_HEADERS_%s' % name.upper(),
       
   326         export_includes=['include'])
       
   327     bld.install_files(os.path.join('${PREFIX}', 'include', 'ns3'), headers + [target])
       
   328 
       
   329 
       
   330 
       
   331 def _lib(bld, dep):
       
   332     libpath = bld.env['LIBPATH_%s' % dep.upper()]
       
   333     linkflags = bld.env['LINKFLAGS_%s' % dep.upper()]
       
   334     libs = bld.env['LIB_%s' % dep.upper()]
       
   335     retval = []
       
   336     for path in libpath:
       
   337         retval.append(bld.env['LIBPATH_ST'] % path)
       
   338     retval = retval + linkflags
       
   339     for lib in libs:
       
   340         retval.append(bld.env['LIB_ST'] % lib)
       
   341     return retval
       
   342 
       
   343 def _cflags(bld, dep):
       
   344     return bld.env['CFLAGS_%s' % dep]
       
   345 def _cxxflags(bld, dep):
       
   346     return bld.env['CXXFLAGS_%s' % dep]
       
   347 def _defines(bld, dep):
       
   348     return [bld.env['DEFINES_ST'] % define for define in bld.env['DEFINES_%s' % dep]]
       
   349 def _includes(bld, dep):
       
   350     return [bld.env['CPPPATH_ST'] % include for include in bld.env['INCLUDES_%s' % dep]]
       
   351 
       
   352 def _self_lib(bld, name, libdir):
       
   353     if bld.env['NS3_ENABLE_STATIC']:
       
   354         path_st = 'STLIBPATH_ST'
       
   355         lib_st = 'STLIB_ST'
       
   356         lib_marker = 'STLIB_MARKER'
       
   357     else:
       
   358         path_st = 'LIBPATH_ST'
       
   359         lib_st = 'LIB_ST'
       
   360         lib_marker = 'SHLIB_MARKER'
       
   361     libname = 'ns3-' + name
       
   362     return [bld.env[path_st] % libdir,
       
   363             bld.env[lib_marker],
       
   364             bld.env[lib_st] % libname]
       
   365 
       
   366 def _generate_pcfile(bld, name, use, prefix, outfilename):
       
   367     import os
       
   368     outfile = open(outfilename, 'w')
       
   369     includedir = os.path.join(prefix, 'include')
       
   370     libdir = os.path.join(prefix, 'lib')
       
   371     libs = _self_lib(bld, name, '${libdir}')
       
   372     for dep in use:
       
   373         libs = libs + _lib(bld,dep)
       
   374     cflags = [bld.env['CPPPATH_ST'] % '${includedir}']
       
   375     for dep in use:
       
   376         cflags = cflags + _cflags(bld, dep) + _cxxflags(bld, dep) + \
       
   377             _defines(bld, dep) + _includes(bld, dep)
       
   378     print >> outfile, """
       
   379 prefix=%s
       
   380 libdir=%s
       
   381 includedir=%s
       
   382 
       
   383 Name: libns3-%s
       
   384 Description: ns-3 module %s
       
   385 Version: devel
       
   386 Libs: %s
       
   387 Cflags: %s
       
   388 """ % (prefix, libdir, includedir,
       
   389        name, name, ' '.join(libs), ' '.join(cflags))
       
   390     outfile.close()
       
   391 
       
   392 def _build_pkgconfig(bld, name, use):
       
   393     import os
       
   394     def run(task):
       
   395         _generate_pcfile(bld, name, use, bld.env['PREFIX'], task.outputs[0].abspath())
       
   396         return 0
       
   397     target = os.path.join('lib', 'pkgconfig', 'libns3-%s.pc' % name)
       
   398     bld(rule=run, target=target, always=True)
       
   399     bld.install_files(os.path.join('${PREFIX}', 'lib', 'pkgconfig'), [target])
       
   400 
       
   401 class Module:
       
   402     def __init__(self, dirs, bld, name):
       
   403         self._source_dirs = dirs
       
   404         self._bld = bld
       
   405         self._name = name
       
   406     def add_tests(self, name = None, **kw):
       
   407         import copy
       
   408         import os
       
   409         import tempfile
       
   410 
       
   411         if not name is None:
       
   412             target='ns3test-%s-%s' % (self._name, name)
       
   413         else:
       
   414             target='ns3test-%s' % self._name
       
   415         target = os.path.join('bin', target)
       
   416 
       
   417         uselib = kw.get('use', [])
       
   418         if not modules_uselib(self._bld, [self._name]) in uselib:
       
   419             uselib = uselib + modules_uselib(self._bld, [self._name])
       
   420         kw['use'] = uselib
       
   421         kw['includes'] = kw.get('includes', []) + self._source_dirs
       
   422 
       
   423         tmp = self._bld.path.relpath_gen(self._bld.srcnode)
       
   424         objects = []
       
   425         for src in kw['source']:
       
   426             src_target = '%s_object' % src
       
   427             objects.append(src_target)
       
   428             kw_copy = copy.copy (kw)
       
   429             path = os.path.dirname(os.path.join(tmp, src))
       
   430             kw_copy['source'] = [src]
       
   431             kw_copy['target'] = src_target
       
   432             kw_copy['defines'] = kw_copy.get('defines', []) + ['NS_TEST_SOURCEDIR=%s' % path]
       
   433             self._bld.objects(**kw_copy)
       
   434         handle, filename = tempfile.mkstemp(suffix='.cc')
       
   435         os.write (handle, """
       
   436 #include "ns3/test.h"
       
   437 
       
   438 int main (int argc, char *argv[])
       
   439 {
       
   440   return ns3::TestRunner::Run(argc, argv);
       
   441 }
       
   442 """)
       
   443         os.close(handle)
       
   444         kw['source'] = [os.path.relpath(filename, self._bld.bldnode.abspath())]
       
   445         kw['use'] = uselib + objects
       
   446         kw['target'] = target
       
   447         kw['install_path'] = None
       
   448         self._bld.program(**kw)
       
   449 
       
   450 
       
   451 def create_module(bld, name, *k, **kw):
       
   452     _build_library(bld, name, *k, **kw)
       
   453     _build_headers(bld, name, kw.get('headers'))
       
   454     _build_pkgconfig(bld, name, kw.get('use'))
       
   455     return Module(_dirs(kw.get('source')), bld, name)
       
   456 
       
   457 def build_program(bld, target=None, source = None, use = None):
       
   458     bld.program(source=source, target=target, use=use)
       
   459 
       
   460 def build_example(bld, target=None, source = None, use = None):
       
   461     if bld.env['NS3_ENABLE_EXAMPLES']:
       
   462         bld.program(source=source, target=target, use=use)
       
   463 
       
   464 
       
   465