|
|
| 1 |
|
| 2 |
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- |
| 3 |
from __future__ import print_function |
| 4 |
import os, os.path |
| 5 |
import sys |
| 6 |
import shutil |
| 7 |
import types |
| 8 |
import warnings |
| 9 |
|
| 10 |
from waflib import TaskGen, Task, Options, Build, Utils |
| 11 |
from waflib.Errors import WafError |
| 12 |
import wutils |
| 13 |
|
| 14 |
try: |
| 15 |
set |
| 16 |
except NameError: |
| 17 |
from sets import Set as set # Python 2.3 fallback |
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
all_modules = [] |
| 22 |
for dirname in os.listdir('contrib'): |
| 23 |
if dirname.startswith('.') or dirname == 'CVS': |
| 24 |
continue |
| 25 |
path = os.path.join('contrib', dirname) |
| 26 |
if not os.path.isdir(path): |
| 27 |
continue |
| 28 |
if os.path.exists(os.path.join(path, 'wscript')): |
| 29 |
all_modules.append(dirname) |
| 30 |
all_modules.sort() |
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
def options(opt): |
| 35 |
opt.add_option('--enable-rpath', |
| 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) |
| 50 |
|
| 51 |
def configure(conf): |
| 52 |
conf.env['REQUIRED_BOOST_LIBS'] = [] |
| 53 |
for module in all_modules: |
| 54 |
conf.recurse (module, name="required_boost_libs", mandatory=False) |
| 55 |
|
| 56 |
if conf.env['REQUIRED_BOOST_LIBS'] is not []: |
| 57 |
conf.load('boost') |
| 58 |
conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), mandatory=False) |
| 59 |
if not conf.env['LIB_BOOST']: |
| 60 |
conf.check_boost(lib=' '.join (conf.env['REQUIRED_BOOST_LIBS']), libpath="/usr/lib64", mandatory=False) |
| 61 |
if not conf.env['LIB_BOOST']: |
| 62 |
conf.env['LIB_BOOST'] = [] |
| 63 |
|
| 64 |
# Append blddir to the module path before recursing into modules |
| 65 |
blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant)) |
| 66 |
conf.env.append_value('NS3_MODULE_PATH', blddir) |
| 67 |
|
| 68 |
for module in all_modules: |
| 69 |
conf.recurse(module, mandatory=False) |
| 70 |
|
| 71 |
# Remove duplicate path items |
| 72 |
conf.env['NS3_MODULE_PATH'] = wutils.uniquify_list(conf.env['NS3_MODULE_PATH']) |
| 73 |
|
| 74 |
if Options.options.enable_rpath: |
| 75 |
conf.env.append_value('RPATH', '-Wl,-rpath,%s' % (os.path.join(blddir),)) |
| 76 |
|
| 77 |
## Used to link the 'test-runner' program with all of ns-3 code |
| 78 |
conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] |
| 79 |
|
| 80 |
|
| 81 |
|
| 82 |
# we need the 'ns3module' waf "feature" to be created because code |
| 83 |
# elsewhere looks for it to find the ns3 module objects. |
| 84 |
@TaskGen.feature('ns3module') |
| 85 |
def _add_test_code(module): |
| 86 |
pass |
| 87 |
|
| 88 |
def create_ns3_module(bld, name, dependencies=(), test=False): |
| 89 |
static = bool(bld.env.ENABLE_STATIC_NS3) |
| 90 |
# Create a separate library for this module. |
| 91 |
if static: |
| 92 |
module = bld(features='cxx cxxstlib ns3module') |
| 93 |
else: |
| 94 |
module = bld(features='cxx cxxshlib ns3module') |
| 95 |
module.target = '%s/ns%s-%s%s' % (bld.srcnode.path_from(module.path), wutils.VERSION, |
| 96 |
name, bld.env.BUILD_SUFFIX) |
| 97 |
linkflags = [] |
| 98 |
cxxflags = [] |
| 99 |
ccflags = [] |
| 100 |
if not static: |
| 101 |
cxxflags = module.env['shlib_CXXFLAGS'] |
| 102 |
ccflags = module.env['shlib_CXXFLAGS'] |
| 103 |
# Turn on the link flags for shared libraries if we have the |
| 104 |
# proper compiler and platform. |
| 105 |
if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']: |
| 106 |
# Get the module library name without any relative paths |
| 107 |
# at its beginning because all of the libraries will end |
| 108 |
# up in the same directory. |
| 109 |
module_library_name = module.env.cshlib_PATTERN % (os.path.basename(module.target),) |
| 110 |
linkflags = '-Wl,--soname=' + module_library_name |
| 111 |
cxxdefines = ["NS3_MODULE_COMPILATION"] |
| 112 |
ccdefines = ["NS3_MODULE_COMPILATION"] |
| 113 |
|
| 114 |
module.env.append_value('CXXFLAGS', cxxflags) |
| 115 |
module.env.append_value('CCFLAGS', ccflags) |
| 116 |
module.env.append_value('LINKFLAGS', linkflags) |
| 117 |
module.env.append_value('CXXDEFINES', cxxdefines) |
| 118 |
module.env.append_value('CCDEFINES', ccdefines) |
| 119 |
|
| 120 |
module.is_static = static |
| 121 |
module.vnum = wutils.VNUM |
| 122 |
# Add the proper path to the module's name. |
| 123 |
# Set the libraries this module depends on. |
| 124 |
module.module_deps = list(dependencies) |
| 125 |
|
| 126 |
module.install_path = "${LIBDIR}" |
| 127 |
|
| 128 |
module.name = "ns3-" + name |
| 129 |
module.dependencies = dependencies |
| 130 |
# Initially create an empty value for this because the pcfile |
| 131 |
# writing task assumes every module has a uselib attribute. |
| 132 |
module.uselib = '' |
| 133 |
module.use = ['ns3-' + dep for dep in dependencies] |
| 134 |
module.test = test |
| 135 |
module.is_ns3_module = True |
| 136 |
module.ns3_dir_location = bld.path.path_from(bld.srcnode) |
| 137 |
|
| 138 |
module.env.append_value("INCLUDES", '#') |
| 139 |
|
| 140 |
module.pcfilegen = bld(features='ns3pcfile') |
| 141 |
module.pcfilegen.module = module.name |
| 142 |
|
| 143 |
return module |
| 144 |
|
| 145 |
@TaskGen.feature("ns3testlib") |
| 146 |
@TaskGen.before_method("apply_incpaths") |
| 147 |
def apply_incpaths_ns3testlib(self): |
| 148 |
if not self.source: |
| 149 |
return |
| 150 |
testdir = self.source[-1].parent.path_from(self.bld.srcnode) |
| 151 |
self.env.append_value("DEFINES", 'NS_TEST_SOURCEDIR="%s"' % (testdir,)) |
| 152 |
|
| 153 |
|
| 154 |
def create_ns3_module_test_library(bld, name): |
| 155 |
# Create an ns3 module for the test library that depends only on |
| 156 |
# the module being tested. |
| 157 |
library_name = name + "-test" |
| 158 |
library = bld.create_ns3_module(library_name, [name], test=True) |
| 159 |
library.features += " ns3testlib" |
| 160 |
|
| 161 |
# Modify attributes for the test library that are different from a |
| 162 |
# normal module. |
| 163 |
del library.is_ns3_module |
| 164 |
library.is_ns3_module_test_library = True |
| 165 |
library.module_name = 'ns3-' + name |
| 166 |
|
| 167 |
# Add this module and test library to the list. |
| 168 |
bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', [(library.module_name, library.name)]) |
| 169 |
|
| 170 |
# Set the include path from the build directory to modules. |
| 171 |
relative_path_from_build_to_here = bld.path.path_from(bld.bldnode) |
| 172 |
include_flag = '-I' + relative_path_from_build_to_here |
| 173 |
library.env.append_value('CXXFLAGS', include_flag) |
| 174 |
library.env.append_value('CCFLAGS', include_flag) |
| 175 |
|
| 176 |
return library |
| 177 |
|
| 178 |
def create_obj(bld, *args): |
| 179 |
warnings.warn("(in %s) Use bld(...) call now, instead of bld.create_obj(...)" % str(bld.path), |
| 180 |
DeprecationWarning, stacklevel=2) |
| 181 |
return bld(*args) |
| 182 |
|
| 183 |
|
| 184 |
def ns3_python_bindings(bld): |
| 185 |
|
| 186 |
# this method is called from a module wscript, so remember bld.path is not bindings/python! |
| 187 |
module_abs_src_path = bld.path.abspath() |
| 188 |
module = os.path.basename(module_abs_src_path) |
| 189 |
env = bld.env |
| 190 |
env.append_value("MODULAR_BINDINGS_MODULES", "ns3-"+module) |
| 191 |
|
| 192 |
if Options.options.apiscan: |
| 193 |
return |
| 194 |
|
| 195 |
if not env['ENABLE_PYTHON_BINDINGS']: |
| 196 |
return |
| 197 |
|
| 198 |
bindings_dir = bld.path.find_dir("bindings") |
| 199 |
if bindings_dir is None or not os.path.exists(bindings_dir.abspath()): |
| 200 |
warnings.warn("(in %s) Requested to build modular python bindings, but apidefs dir not found " |
| 201 |
"=> skipped the bindings." % str(bld.path), |
| 202 |
Warning, stacklevel=2) |
| 203 |
return |
| 204 |
|
| 205 |
if ("ns3-%s" % (module,)) not in env.NS3_ENABLED_MODULES: |
| 206 |
#print "bindings for module %s which is not enabled, skip" % module |
| 207 |
return |
| 208 |
|
| 209 |
env.append_value('PYTHON_MODULES_BUILT', module) |
| 210 |
try: |
| 211 |
apidefs = env['PYTHON_BINDINGS_APIDEFS'].replace("-", "_") |
| 212 |
except AttributeError: |
| 213 |
# we likely got an empty list for env['PYTHON_BINDINGS_APIDEFS'] |
| 214 |
return |
| 215 |
|
| 216 |
#debug = ('PYBINDGEN_DEBUG' in os.environ) |
| 217 |
debug = True # XXX |
| 218 |
source = [bld.srcnode.find_resource('bindings/python/ns3modulegen-modular.py'), |
| 219 |
bld.path.find_resource("bindings/modulegen__%s.py" % apidefs)] |
| 220 |
|
| 221 |
modulegen_customizations = bindings_dir.find_resource("modulegen_customizations.py") |
| 222 |
if modulegen_customizations is not None: |
| 223 |
source.append(modulegen_customizations) |
| 224 |
|
| 225 |
modulegen_local = bld.path.find_resource("bindings/modulegen_local.py") |
| 226 |
# the local customization file may or not exist |
| 227 |
if modulegen_local is not None: |
| 228 |
source.append("bindings/modulegen_local.py") |
| 229 |
|
| 230 |
module_py_name = module.replace('-', '_') |
| 231 |
module_target_dir = bld.srcnode.find_dir("bindings/python/ns").path_from(bld.path) |
| 232 |
|
| 233 |
# if bindings/<module>.py exists, it becomes the module frontend, and the C extension befomes _<module> |
| 234 |
if bld.path.find_resource("bindings/%s.py" % (module_py_name,)) is not None: |
| 235 |
bld(features='copy', |
| 236 |
source=("bindings/%s.py" % (module_py_name,)), |
| 237 |
target=('%s/%s.py' % (module_target_dir, module_py_name))) |
| 238 |
extension_name = '_%s' % (module_py_name,) |
| 239 |
bld.install_files('${PYTHONARCHDIR}/ns', ["bindings/%s.py" % (module_py_name,)]) |
| 240 |
else: |
| 241 |
extension_name = module_py_name |
| 242 |
|
| 243 |
target = ['bindings/ns3module.cc', 'bindings/ns3module.h', 'bindings/ns3modulegen.log'] |
| 244 |
#if not debug: |
| 245 |
# target.append('ns3modulegen.log') |
| 246 |
|
| 247 |
argv = ['NS3_ENABLED_FEATURES=${FEATURES}', |
| 248 |
'GCC_RTTI_ABI_COMPLETE=${GCC_RTTI_ABI_COMPLETE}', |
| 249 |
'${PYTHON}'] |
| 250 |
#if debug: |
| 251 |
# argv.extend(["-m", "pdb"]) |
| 252 |
|
| 253 |
argv.extend(['${SRC[0]}', module_abs_src_path, apidefs, extension_name, '${TGT[0]}']) |
| 254 |
|
| 255 |
argv.extend(['2>', '${TGT[2]}']) # 2> ns3modulegen.log |
| 256 |
|
| 257 |
features = [] |
| 258 |
for (name, caption, was_enabled, reason_not_enabled) in env['NS3_OPTIONAL_FEATURES']: |
| 259 |
if was_enabled: |
| 260 |
features.append(name) |
| 261 |
|
| 262 |
bindgen = bld(features='command', source=source, target=target, command=argv) |
| 263 |
bindgen.env['FEATURES'] = ','.join(features) |
| 264 |
bindgen.dep_vars = ['FEATURES', "GCC_RTTI_ABI_COMPLETE"] |
| 265 |
bindgen.before = 'cxx' |
| 266 |
bindgen.after = 'gen_ns3_module_header' |
| 267 |
bindgen.name = "pybindgen(ns3 module %s)" % module |
| 268 |
bindgen.install_path = None |
| 269 |
|
| 270 |
# generate the extension module |
| 271 |
pymod = bld(features='cxx cxxshlib pyext') |
| 272 |
pymod.source = ['bindings/ns3module.cc'] |
| 273 |
pymod.target = '%s/%s' % (module_target_dir, extension_name) |
| 274 |
pymod.name = 'ns3module_%s' % module |
| 275 |
pymod.use = ["%s" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117 |
| 276 |
if pymod.env['ENABLE_STATIC_NS3']: |
| 277 |
if sys.platform == 'darwin': |
| 278 |
pymod.env.append_value('LINKFLAGS', '-Wl,-all_load') |
| 279 |
for mod in pymod.usel: |
| 280 |
#mod = mod.split("--lib")[0] |
| 281 |
pymod.env.append_value('LINKFLAGS', '-l' + mod) |
| 282 |
else: |
| 283 |
pymod.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic') |
| 284 |
for mod in pymod.use: |
| 285 |
#mod = mod.split("--lib")[0] |
| 286 |
pymod.env.append_value('LINKFLAGS', '-l' + mod) |
| 287 |
pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive') |
| 288 |
defines = list(pymod.env['DEFINES']) |
| 289 |
defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H']) |
| 290 |
if Options.platform == 'win32': |
| 291 |
try: |
| 292 |
defines.remove('_DEBUG') # causes undefined symbols on win32 |
| 293 |
except ValueError: |
| 294 |
pass |
| 295 |
pymod.env['DEFINES'] = defines |
| 296 |
pymod.includes = '# bindings' |
| 297 |
pymod.install_path = '${PYTHONARCHDIR}/ns' |
| 298 |
|
| 299 |
# Workaround to a WAF bug, remove this when ns-3 upgrades to WAF > 1.6.10 |
| 300 |
# https://www.nsnam.org/bugzilla/show_bug.cgi?id=1335 |
| 301 |
# http://code.google.com/p/waf/issues/detail?id=1098 |
| 302 |
if Utils.unversioned_sys_platform() == 'darwin': |
| 303 |
pymod.mac_bundle = True |
| 304 |
|
| 305 |
return pymod |
| 306 |
|
| 307 |
|
| 308 |
def build(bld): |
| 309 |
bld.create_ns3_module = types.MethodType(create_ns3_module, bld) |
| 310 |
bld.create_ns3_module_test_library = types.MethodType(create_ns3_module_test_library, bld) |
| 311 |
bld.create_obj = types.MethodType(create_obj, bld) |
| 312 |
bld.ns3_python_bindings = types.MethodType(ns3_python_bindings, bld) |
| 313 |
|
| 314 |
# Remove these modules from the list of all modules. |
| 315 |
for not_built in bld.env['MODULES_NOT_BUILT']: |
| 316 |
|
| 317 |
# XXX Because these modules are located in subdirectories of |
| 318 |
# test, their names in the all_modules list include the extra |
| 319 |
# relative path "test/". If these modules are moved into the |
| 320 |
# src directory, then this if block should be removed. |
| 321 |
if not_built == 'ns3tcp' or not_built == 'ns3wifi': |
| 322 |
not_built = 'test/' + not_built |
| 323 |
|
| 324 |
if not_built in all_modules: |
| 325 |
all_modules.remove(not_built) |
| 326 |
|
| 327 |
bld.recurse(list(all_modules)) |
| 328 |
|
| 329 |
for module in all_modules: |
| 330 |
modheader = bld(features='ns3moduleheader') |
| 331 |
modheader.module = module.split('/')[-1] |
| 332 |
|
| 333 |
class ns3pcfile_task(Task.Task): |
| 334 |
after = 'cxx' |
| 335 |
|
| 336 |
def __str__(self): |
| 337 |
"string to display to the user" |
| 338 |
tgt_str = ' '.join([a.bldpath() for a in self.outputs]) |
| 339 |
return 'pcfile: %s\n' % (tgt_str) |
| 340 |
|
| 341 |
def runnable_status(self): |
| 342 |
return super(ns3pcfile_task, self).runnable_status() |
| 343 |
|
| 344 |
def _self_libs(self, env, name, libdir): |
| 345 |
if env['ENABLE_STATIC_NS3']: |
| 346 |
path_st = 'STLIBPATH_ST' |
| 347 |
lib_st = 'STLIB_ST' |
| 348 |
lib_marker = 'STLIB_MARKER' |
| 349 |
else: |
| 350 |
path_st = 'LIBPATH_ST' |
| 351 |
lib_st = 'LIB_ST' |
| 352 |
lib_marker = 'SHLIB_MARKER' |
| 353 |
retval = [env[path_st] % libdir] |
| 354 |
if env[lib_marker]: |
| 355 |
retval.append(env[lib_marker]) |
| 356 |
retval.append(env[lib_st] % name) |
| 357 |
return retval |
| 358 |
|
| 359 |
def _lib(self, env, dep): |
| 360 |
libpath = env['LIBPATH_%s' % dep] |
| 361 |
linkflags = env['LINKFLAGS_%s' % dep] |
| 362 |
libs = env['LIB_%s' % dep] |
| 363 |
retval = [] |
| 364 |
for path in libpath: |
| 365 |
retval.append(env['LIBPATH_ST'] % path) |
| 366 |
retval = retval + linkflags |
| 367 |
for lib in libs: |
| 368 |
retval.append(env['LIB_ST'] % lib) |
| 369 |
return retval |
| 370 |
|
| 371 |
def _listify(self, v): |
| 372 |
if isinstance(v, list): |
| 373 |
return v |
| 374 |
else: |
| 375 |
return [v] |
| 376 |
|
| 377 |
def _cflags(self, dep): |
| 378 |
flags = self.env['CFLAGS_%s' % dep] |
| 379 |
return self._listify(flags) |
| 380 |
|
| 381 |
def _cxxflags(self, dep): |
| 382 |
return self._listify(self.env['CXXFLAGS_%s' % dep]) |
| 383 |
|
| 384 |
def _defines(self, dep): |
| 385 |
return [self.env['DEFINES_ST'] % define for define in self.env['DEFINES_%s' % dep]] |
| 386 |
|
| 387 |
def _includes(self, dep): |
| 388 |
includes = self.env['INCLUDES_%s' % dep] |
| 389 |
return [self.env['CPPPATH_ST'] % include for include in includes] |
| 390 |
|
| 391 |
def _generate_pcfile(self, name, use, env, outfilename): |
| 392 |
outfile = open(outfilename, 'wt') |
| 393 |
prefix = env.PREFIX |
| 394 |
includedir = Utils.subst_vars('${INCLUDEDIR}/%s%s' % (wutils.APPNAME, wutils.VERSION), env) |
| 395 |
libdir = env.LIBDIR |
| 396 |
libs = self._self_libs(env, "%s%s-%s%s" % (wutils.APPNAME, wutils.VERSION, name[4:], env.BUILD_SUFFIX), '${libdir}') |
| 397 |
for dep in use: |
| 398 |
libs += self._lib(env, dep) |
| 399 |
for dep in env.LIBS: |
| 400 |
libs += self.env['LIB_ST'] % dep |
| 401 |
cflags = [self.env['CPPPATH_ST'] % '${includedir}'] |
| 402 |
requires = [] |
| 403 |
for dep in use: |
| 404 |
cflags = cflags + self._cflags(dep) + self._cxxflags(dep) + \ |
| 405 |
self._defines(dep) + self._includes(dep) |
| 406 |
if dep.startswith('ns3-'): |
| 407 |
dep_name = dep[4:] |
| 408 |
requires.append("libns%s-%s%s" % (wutils.VERSION, dep_name, env.BUILD_SUFFIX)) |
| 409 |
print("""\ |
| 410 |
prefix=%s |
| 411 |
libdir=%s |
| 412 |
includedir=%s |
| 413 |
|
| 414 |
Name: lib%s |
| 415 |
Description: ns-3 module %s |
| 416 |
Version: %s |
| 417 |
Libs: %s |
| 418 |
Cflags: %s |
| 419 |
Requires: %s\ |
| 420 |
""" % (prefix, libdir, includedir, |
| 421 |
name, name, wutils.VERSION, ' '.join(libs), ' '.join(cflags), ' '.join(requires)), file=outfile) |
| 422 |
outfile.close() |
| 423 |
|
| 424 |
def run(self): |
| 425 |
output_filename = self.outputs[0].abspath() |
| 426 |
self._generate_pcfile(self.module.name, |
| 427 |
self.module.to_list(self.module.use), |
| 428 |
self.env, output_filename) |
| 429 |
|
| 430 |
|
| 431 |
@TaskGen.feature('ns3pcfile') |
| 432 |
@TaskGen.after_method('process_rule') |
| 433 |
def apply(self): |
| 434 |
module = self.bld.find_ns3_module(self.module) |
| 435 |
output_filename = 'lib%s.pc' % os.path.basename(module.target) |
| 436 |
output_node = self.path.find_or_declare(output_filename) |
| 437 |
assert output_node is not None, str(self) |
| 438 |
task = self.create_task('ns3pcfile') |
| 439 |
self.bld.install_files('${LIBDIR}/pkgconfig', output_node) |
| 440 |
task.set_outputs([output_node]) |
| 441 |
task.module = module |
| 442 |
|
| 443 |
|
| 444 |
|
| 445 |
@TaskGen.feature('ns3header') |
| 446 |
@TaskGen.after_method('process_rule') |
| 447 |
def apply_ns3header(self): |
| 448 |
if self.module is None: |
| 449 |
raise WafError("'module' missing on ns3headers object %s" % self) |
| 450 |
ns3_dir_node = self.bld.path.find_or_declare("ns3") |
| 451 |
for filename in set(self.to_list(self.source)): |
| 452 |
src_node = self.path.find_resource(filename) |
| 453 |
if src_node is None: |
| 454 |
raise WafError("source ns3 header file %s not found" % (filename,)) |
| 455 |
dst_node = ns3_dir_node.find_or_declare(src_node.name) |
| 456 |
assert dst_node is not None |
| 457 |
task = self.create_task('ns3header') |
| 458 |
task.mode = getattr(self, 'mode', 'install') |
| 459 |
if task.mode == 'install': |
| 460 |
self.bld.install_files('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION), [src_node]) |
| 461 |
task.set_inputs([src_node]) |
| 462 |
task.set_outputs([dst_node]) |
| 463 |
else: |
| 464 |
task.header_to_remove = dst_node |
| 465 |
self.headers = set(self.to_list(self.source)) |
| 466 |
self.source = '' # tell WAF not to process these files further |
| 467 |
|
| 468 |
|
| 469 |
class ns3header_task(Task.Task): |
| 470 |
before = 'cxx gen_ns3_module_header' |
| 471 |
color = 'BLUE' |
| 472 |
|
| 473 |
def __str__(self): |
| 474 |
"string to display to the user" |
| 475 |
env = self.env |
| 476 |
src_str = ' '.join([a.bldpath() for a in self.inputs]) |
| 477 |
tgt_str = ' '.join([a.bldpath() for a in self.outputs]) |
| 478 |
if self.outputs: sep = ' -> ' |
| 479 |
else: sep = '' |
| 480 |
if self.mode == 'remove': |
| 481 |
return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),) |
| 482 |
return 'install-ns3-header: %s' % (tgt_str) |
| 483 |
|
| 484 |
def __repr__(self): |
| 485 |
return str(self) |
| 486 |
|
| 487 |
def uid(self): |
| 488 |
try: |
| 489 |
return self.uid_ |
| 490 |
except AttributeError: |
| 491 |
m = Utils.md5() |
| 492 |
up = m.update |
| 493 |
up(self.__class__.__name__.encode()) |
| 494 |
for x in self.inputs + self.outputs: |
| 495 |
up(x.abspath().encode()) |
| 496 |
up(self.mode.encode()) |
| 497 |
if self.mode == 'remove': |
| 498 |
up(self.header_to_remove.abspath().encode()) |
| 499 |
self.uid_ = m.digest() |
| 500 |
return self.uid_ |
| 501 |
|
| 502 |
def runnable_status(self): |
| 503 |
if self.mode == 'remove': |
| 504 |
if os.path.exists(self.header_to_remove.abspath()): |
| 505 |
return Task.RUN_ME |
| 506 |
else: |
| 507 |
return Task.SKIP_ME |
| 508 |
else: |
| 509 |
return super(ns3header_task, self).runnable_status() |
| 510 |
|
| 511 |
def run(self): |
| 512 |
if self.mode == 'install': |
| 513 |
assert len(self.inputs) == len(self.outputs) |
| 514 |
inputs = [node.abspath() for node in self.inputs] |
| 515 |
outputs = [node.abspath() for node in self.outputs] |
| 516 |
for src, dst in zip(inputs, outputs): |
| 517 |
try: |
| 518 |
os.chmod(dst, 0o600) |
| 519 |
except OSError: |
| 520 |
pass |
| 521 |
shutil.copy2(src, dst) |
| 522 |
## make the headers in builddir read-only, to prevent |
| 523 |
## accidental modification |
| 524 |
os.chmod(dst, 0o400) |
| 525 |
return 0 |
| 526 |
else: |
| 527 |
assert len(self.inputs) == 0 |
| 528 |
assert len(self.outputs) == 0 |
| 529 |
out_file_name = self.header_to_remove.abspath() |
| 530 |
try: |
| 531 |
os.unlink(out_file_name) |
| 532 |
except OSError as ex: |
| 533 |
if ex.errno != 2: |
| 534 |
raise |
| 535 |
return 0 |
| 536 |
|
| 537 |
|
| 538 |
@TaskGen.feature('ns3privateheader') |
| 539 |
@TaskGen.after_method('process_rule') |
| 540 |
def apply_ns3privateheader(self): |
| 541 |
if self.module is None: |
| 542 |
raise WafError("'module' missing on ns3headers object %s" % self) |
| 543 |
ns3_dir_node = self.bld.path.find_or_declare("ns3/private") |
| 544 |
for filename in set(self.to_list(self.source)): |
| 545 |
src_node = self.path.find_resource(filename) |
| 546 |
if src_node is None: |
| 547 |
raise WafError("source ns3 header file %s not found" % (filename,)) |
| 548 |
dst_node = ns3_dir_node.find_or_declare(src_node.name) |
| 549 |
assert dst_node is not None |
| 550 |
task = self.create_task('ns3privateheader') |
| 551 |
task.mode = getattr(self, 'mode', 'install') |
| 552 |
if task.mode == 'install': |
| 553 |
task.set_inputs([src_node]) |
| 554 |
task.set_outputs([dst_node]) |
| 555 |
else: |
| 556 |
task.header_to_remove = dst_node |
| 557 |
self.headers = set(self.to_list(self.source)) |
| 558 |
self.source = '' # tell WAF not to process these files further |
| 559 |
|
| 560 |
class ns3privateheader_task(Task.Task): |
| 561 |
before = 'cxx gen_ns3_module_header' |
| 562 |
after = 'ns3header' |
| 563 |
color = 'BLUE' |
| 564 |
|
| 565 |
def __str__(self): |
| 566 |
"string to display to the user" |
| 567 |
env = self.env |
| 568 |
src_str = ' '.join([a.bldpath() for a in self.inputs]) |
| 569 |
tgt_str = ' '.join([a.bldpath() for a in self.outputs]) |
| 570 |
if self.outputs: sep = ' -> ' |
| 571 |
else: sep = '' |
| 572 |
if self.mode == 'remove': |
| 573 |
return 'rm-ns3-header %s' % (self.header_to_remove.abspath(),) |
| 574 |
return 'install-ns3-header: %s' % (tgt_str) |
| 575 |
|
| 576 |
def __repr__(self): |
| 577 |
return str(self) |
| 578 |
|
| 579 |
def uid(self): |
| 580 |
try: |
| 581 |
return self.uid_ |
| 582 |
except AttributeError: |
| 583 |
m = Utils.md5() |
| 584 |
up = m.update |
| 585 |
up(self.__class__.__name__.encode()) |
| 586 |
for x in self.inputs + self.outputs: |
| 587 |
up(x.abspath().encode()) |
| 588 |
up(self.mode.encode()) |
| 589 |
if self.mode == 'remove': |
| 590 |
up(self.header_to_remove.abspath().encode()) |
| 591 |
self.uid_ = m.digest() |
| 592 |
return self.uid_ |
| 593 |
|
| 594 |
def runnable_status(self): |
| 595 |
if self.mode == 'remove': |
| 596 |
if os.path.exists(self.header_to_remove.abspath()): |
| 597 |
return Task.RUN_ME |
| 598 |
else: |
| 599 |
return Task.SKIP_ME |
| 600 |
else: |
| 601 |
return super(ns3privateheader_task, self).runnable_status() |
| 602 |
|
| 603 |
def run(self): |
| 604 |
if self.mode == 'install': |
| 605 |
assert len(self.inputs) == len(self.outputs) |
| 606 |
inputs = [node.abspath() for node in self.inputs] |
| 607 |
outputs = [node.abspath() for node in self.outputs] |
| 608 |
for src, dst in zip(inputs, outputs): |
| 609 |
try: |
| 610 |
os.chmod(dst, 0o600) |
| 611 |
except OSError: |
| 612 |
pass |
| 613 |
shutil.copy2(src, dst) |
| 614 |
## make the headers in builddir read-only, to prevent |
| 615 |
## accidental modification |
| 616 |
os.chmod(dst, 0o400) |
| 617 |
return 0 |
| 618 |
else: |
| 619 |
assert len(self.inputs) == 0 |
| 620 |
assert len(self.outputs) == 0 |
| 621 |
out_file_name = self.header_to_remove.abspath() |
| 622 |
try: |
| 623 |
os.unlink(out_file_name) |
| 624 |
except OSError as ex: |
| 625 |
if ex.errno != 2: |
| 626 |
raise |
| 627 |
return 0 |
| 628 |
|
| 629 |
|
| 630 |
class gen_ns3_module_header_task(Task.Task): |
| 631 |
before = 'cxx' |
| 632 |
after = 'ns3header' |
| 633 |
color = 'BLUE' |
| 634 |
|
| 635 |
def runnable_status(self): |
| 636 |
if self.mode == 'remove': |
| 637 |
if os.path.exists(self.header_to_remove.abspath()): |
| 638 |
return Task.RUN_ME |
| 639 |
else: |
| 640 |
return Task.SKIP_ME |
| 641 |
else: |
| 642 |
return super(gen_ns3_module_header_task, self).runnable_status() |
| 643 |
|
| 644 |
def __str__(self): |
| 645 |
"string to display to the user" |
| 646 |
env = self.env |
| 647 |
src_str = ' '.join([a.bldpath() for a in self.inputs]) |
| 648 |
tgt_str = ' '.join([a.bldpath() for a in self.outputs]) |
| 649 |
if self.outputs: sep = ' -> ' |
| 650 |
else: sep = '' |
| 651 |
if self.mode == 'remove': |
| 652 |
return 'rm-module-header %s' % (self.header_to_remove.abspath(),) |
| 653 |
return 'gen-module-header: %s' % (tgt_str) |
| 654 |
|
| 655 |
def run(self): |
| 656 |
if self.mode == 'remove': |
| 657 |
assert len(self.inputs) == 0 |
| 658 |
assert len(self.outputs) == 0 |
| 659 |
out_file_name = self.header_to_remove.abspath() |
| 660 |
try: |
| 661 |
os.unlink(out_file_name) |
| 662 |
except OSError as ex: |
| 663 |
if ex.errno != 2: |
| 664 |
raise |
| 665 |
return 0 |
| 666 |
assert len(self.outputs) == 1 |
| 667 |
out_file_name = self.outputs[0].get_bld().abspath()#self.env) |
| 668 |
header_files = [os.path.basename(node.abspath()) for node in self.inputs] |
| 669 |
outfile = open(out_file_name, "w") |
| 670 |
header_files.sort() |
| 671 |
|
| 672 |
print(""" |
| 673 |
#ifdef NS3_MODULE_COMPILATION |
| 674 |
# error "Do not include ns3 module aggregator headers from other modules; these are meant only for end user scripts." |
| 675 |
#endif |
| 676 |
|
| 677 |
#ifndef NS3_MODULE_%s |
| 678 |
""" % (self.module.upper().replace('-', '_'),), file=outfile) |
| 679 |
|
| 680 |
# if self.module_deps: |
| 681 |
# print >> outfile, "// Module dependencies:" |
| 682 |
# for dep in self.module_deps: |
| 683 |
# print >> outfile, "#include \"%s-module.h\"" % dep |
| 684 |
|
| 685 |
print(file=outfile) |
| 686 |
print("// Module headers:", file=outfile) |
| 687 |
for header in header_files: |
| 688 |
print("#include \"%s\"" % (header,), file=outfile) |
| 689 |
|
| 690 |
print("#endif", file=outfile) |
| 691 |
|
| 692 |
outfile.close() |
| 693 |
return 0 |
| 694 |
|
| 695 |
def sig_explicit_deps(self): |
| 696 |
self.m.update('\n'.join(sorted([node.abspath() for node in self.inputs])).encode('utf-8')) |
| 697 |
return self.m.digest() |
| 698 |
|
| 699 |
def unique_id(self): |
| 700 |
try: |
| 701 |
return self.uid |
| 702 |
except AttributeError: |
| 703 |
"this is not a real hot zone, but we want to avoid surprizes here" |
| 704 |
m = Utils.md5() |
| 705 |
m.update("ns-3-module-header-%s" % self.module) |
| 706 |
self.uid = m.digest() |
| 707 |
return self.uid |
| 708 |
|
| 709 |
|
| 710 |
# Generates a 'ns3/foo-module.h' header file that includes all public |
| 711 |
# ns3 headers of a certain module. |
| 712 |
@TaskGen.feature('ns3moduleheader') |
| 713 |
@TaskGen.after_method('process_rule') |
| 714 |
def apply_ns3moduleheader(self): |
| 715 |
## get all of the ns3 headers |
| 716 |
ns3_dir_node = self.bld.path.find_or_declare("ns3") |
| 717 |
all_headers_inputs = [] |
| 718 |
found_the_module = False |
| 719 |
for ns3headers in self.bld.all_task_gen: |
| 720 |
if 'ns3header' in getattr(ns3headers, "features", []): |
| 721 |
if ns3headers.module != self.module: |
| 722 |
continue |
| 723 |
found_the_module = True |
| 724 |
for source in sorted(ns3headers.headers): |
| 725 |
source = os.path.basename(source) |
| 726 |
node = ns3_dir_node.find_or_declare(os.path.basename(source)) |
| 727 |
if node is None: |
| 728 |
fatal("missing header file %s" % (source,)) |
| 729 |
all_headers_inputs.append(node) |
| 730 |
if not found_the_module: |
| 731 |
raise WafError("error finding headers for module %s" % self.module) |
| 732 |
if not all_headers_inputs: |
| 733 |
return |
| 734 |
|
| 735 |
try: |
| 736 |
module_obj = self.bld.get_tgen_by_name("ns3-" + self.module) |
| 737 |
except WafError: # maybe the module was disabled, and therefore removed |
| 738 |
return |
| 739 |
|
| 740 |
all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)] |
| 741 |
task = self.create_task('gen_ns3_module_header') |
| 742 |
task.module = self.module |
| 743 |
task.mode = getattr(self, "mode", "install") |
| 744 |
if task.mode == 'install': |
| 745 |
assert module_obj is not None, self.module |
| 746 |
self.bld.install_files('${INCLUDEDIR}/%s%s/ns3' % (wutils.APPNAME, wutils.VERSION), |
| 747 |
ns3_dir_node.find_or_declare("%s-module.h" % self.module)) |
| 748 |
task.set_inputs(all_headers_inputs) |
| 749 |
task.set_outputs(all_headers_outputs) |
| 750 |
task.module_deps = module_obj.module_deps |
| 751 |
else: |
| 752 |
task.header_to_remove = all_headers_outputs[0] |