Files
unison/contrib/wscript
2021-08-14 15:24:47 +00:00

327 lines
12 KiB
Python

## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
from __future__ import print_function
from collections import deque
import os, os.path
import sys
import shutil
import types
import warnings
from waflib import TaskGen, Task, Options, Build, Utils, Context
from waflib.Errors import WafError
import wutils
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
# Allow mulitple modules to live in a single directory in contrib.
# For example, a directory structure like:
# contrib/package/module1
# /module2
# Useful for external projects that are building interdependent modules that
# are logically packaged together.
def find_contrib_modules(ctx, log=False):
modules = []
entries = deque( (ctx.path, d) for d in ctx.path.listdir() )
while entries:
parent, entry = entries.popleft()
if not entry or entry[0] == '.' or entry.endswith('CVS'):
continue
node = parent.find_node(entry)
if not node:
continue
if node.isdir():
#does this directory have a wscript file?
wscript_node = node.find_node('wscript')
if wscript_node:
#found a wscript file, treat this directory as a module.
#get the path relative to the context path
module_path = node.path_from(ctx.path)
modules.append(module_path)
if log:
ctx.msg("Found contrib module", module_path)
else:
#maybe this directory is a project,
#add its children to the list of entries to process
entries.extend( (node, d) for d in node.listdir() )
return sorted(modules)
def get_required_boost_libs(conf):
for module in find_contrib_modules(conf):
conf.recurse (module, name="required_boost_libs", mandatory=False)
def options(opt):
for module in find_contrib_modules(opt):
opt.recurse(module, mandatory=False)
def configure(conf):
all_contrib_modules = find_contrib_modules(conf, True)
# Append blddir to the module path before recursing into modules
# This is required for contrib modules with test suites
blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
conf.env.append_value('NS3_MODULE_PATH', blddir)
# Remove duplicate path items
conf.env['NS3_MODULE_PATH'] = wutils.uniquify_list(conf.env['NS3_MODULE_PATH'])
for module in all_contrib_modules:
conf.recurse(module, mandatory=False)
## Used to link the 'test-runner' program with all of ns-3 code
conf.env['NS3_CONTRIBUTED_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_contrib_modules]
# we need the 'ns3module' waf "feature" to be created because code
# elsewhere looks for it to find the ns3 module objects.
def create_ns3_module(bld, name, dependencies=(), test=False):
static = bool(bld.env.ENABLE_STATIC_NS3)
# Create a separate library for this module.
if static:
module = bld(features='cxx cxxstlib ns3module')
else:
module = bld(features='cxx cxxshlib ns3module')
target = '%s/lib/ns%s-%s%s' % (bld.srcnode.path_from(module.path),
wutils.VERSION,
name, bld.env.BUILD_SUFFIX)
module.target = target
linkflags = []
cxxflags = []
ccflags = []
if not static:
cxxflags = module.env['shlib_CXXFLAGS']
ccflags = module.env['shlib_CXXFLAGS']
# Turn on the link flags for shared libraries if we have the
# proper compiler and platform.
if module.env['CXX_NAME'] in ['gcc', 'icc'] and module.env['WL_SONAME_SUPPORTED']:
# Get the module library name without any relative paths
# at its beginning because all of the libraries will end
# up in the same directory.
module_library_name = module.env.cshlib_PATTERN % (os.path.basename(module.target),)
linkflags = '-Wl,--soname=' + module_library_name
cxxdefines = ["NS3_MODULE_COMPILATION"]
ccdefines = ["NS3_MODULE_COMPILATION"]
module.env.append_value('CXXFLAGS', cxxflags)
module.env.append_value('CCFLAGS', ccflags)
module.env.append_value('LINKFLAGS', linkflags)
module.env.append_value('CXXDEFINES', cxxdefines)
module.env.append_value('CCDEFINES', ccdefines)
module.is_static = static
module.vnum = wutils.VNUM
# Add the proper path to the module's name.
# Set the libraries this module depends on.
module.module_deps = list(dependencies)
module.install_path = "${LIBDIR}"
module.name = "ns3-" + name
module.dependencies = dependencies
# Initially create an empty value for this because the pcfile
# writing task assumes every module has a uselib attribute.
module.uselib = ''
module.use = ['ns3-' + dep for dep in dependencies]
module.test = test
module.is_ns3_module = True
module.ns3_dir_location = bld.path.path_from(bld.srcnode)
module.env.append_value("INCLUDES", Context.out_dir)
module.pcfilegen = bld(features='ns3pcfile')
module.pcfilegen.module = module.name
return module
def create_ns3_module_test_library(bld, name):
# Create an ns3 module for the test library that depends only on
# the module being tested.
library_name = name + "-test"
library = bld.create_ns3_module(library_name, [name], test=True)
library.features += " ns3testlib"
# Modify attributes for the test library that are different from a
# normal module.
del library.is_ns3_module
library.is_ns3_module_test_library = True
library.module_name = 'ns3-' + name
# Add this module and test library to the list.
bld.env.append_value('NS3_MODULES_WITH_TEST_LIBRARIES', [(library.module_name, library.name)])
# Set the include path from the build directory to modules.
relative_path_from_build_to_here = bld.path.path_from(bld.bldnode)
include_flag = '-I' + relative_path_from_build_to_here
library.env.append_value('CXXFLAGS', include_flag)
library.env.append_value('CCFLAGS', include_flag)
return library
def create_obj(bld, *args):
warnings.warn("(in %s) Use bld(...) call now, instead of bld.create_obj(...)" % str(bld.path),
DeprecationWarning, stacklevel=2)
return bld(*args)
def ns3_python_bindings(bld):
# this method is called from a module wscript, so remember bld.path is not bindings/python!
module_abs_src_path = bld.path.abspath()
module = os.path.basename(module_abs_src_path)
env = bld.env
env.append_value("MODULAR_BINDINGS_MODULES", "ns3-"+module)
if Options.options.apiscan:
return
if not env['ENABLE_PYTHON_BINDINGS']:
return
bindings_dir = bld.path.find_dir("bindings")
if bindings_dir is None or not os.path.exists(bindings_dir.abspath()):
warnings.warn("(in %s) Requested to build modular python bindings, but apidefs dir not found "
"=> skipped the bindings." % str(bld.path),
Warning, stacklevel=2)
return
if ("ns3-%s" % (module,)) not in env.NS3_ENABLED_CONTRIBUTED_MODULES:
#print "bindings for module %s which is not enabled, skip" % module)
return
env.append_value('PYTHON_MODULES_BUILT', module)
try:
apidefs = env['PYTHON_BINDINGS_APIDEFS'].replace("-", "_")
except AttributeError:
# we likely got an empty list for env['PYTHON_BINDINGS_APIDEFS']
return
#debug = ('PYBINDGEN_DEBUG' in os.environ)
debug = True # XXX
source = [bld.srcnode.find_resource('bindings/python/ns3modulegen-modular.py'),
bld.path.find_resource("bindings/modulegen__%s.py" % apidefs)]
modulegen_customizations = bindings_dir.find_resource("modulegen_customizations.py")
if modulegen_customizations is not None:
source.append(modulegen_customizations)
modulegen_local = bld.path.find_resource("bindings/modulegen_local.py")
# the local customization file may or not exist
if modulegen_local is not None:
source.append("bindings/modulegen_local.py")
module_py_name = module.replace('-', '_')
module_target_dir = bld.srcnode.find_dir("bindings/python/ns").path_from(bld.path)
# if bindings/<module>.py exists, it becomes the module frontend, and the C extension befomes _<module>
if bld.path.find_resource("bindings/%s.py" % (module_py_name,)) is not None:
bld(features='copy',
source=("bindings/%s.py" % (module_py_name,)),
target=('%s/%s.py' % (module_target_dir, module_py_name)))
extension_name = '_%s' % (module_py_name,)
bld.install_files('${PYTHONARCHDIR}/ns', ["bindings/%s.py" % (module_py_name,)])
else:
extension_name = module_py_name
target = ['bindings/ns3module.cc', 'bindings/ns3module.h', 'bindings/ns3modulegen.log']
#if not debug:
# target.append('ns3modulegen.log')
argv = ['NS3_ENABLED_FEATURES=${FEATURES}',
'GCC_RTTI_ABI_COMPLETE=${GCC_RTTI_ABI_COMPLETE}',
'${PYTHON}']
#if debug:
# argv.extend(["-m", "pdb"])
argv.extend(['${SRC[0]}', module_abs_src_path, apidefs, extension_name, '${TGT[0]}'])
argv.extend(['2>', '${TGT[2]}']) # 2> ns3modulegen.log
features = []
for (name, caption, was_enabled, reason_not_enabled) in env['NS3_OPTIONAL_FEATURES']:
if was_enabled:
features.append(name)
bindgen = bld(features='command', source=source, target=target, command=argv)
bindgen.env['FEATURES'] = ','.join(features)
bindgen.dep_vars = ['FEATURES', "GCC_RTTI_ABI_COMPLETE"]
bindgen.before = ['cxxprogram', 'cxxshlib', 'cxxstlib']
bindgen.after = 'gen_ns3_module_header'
bindgen.name = "pybindgen(ns3 module %s)" % module
bindgen.module = module
bindgen.install_path = None
# generate the extension module
pymod = bld(features='cxx cxxshlib pyext')
pymod.source = ['bindings/ns3module.cc']
pymod.target = '%s/%s' % (module_target_dir, extension_name)
pymod.name = 'ns3module_%s' % module
pymod.module = module
pymod.use = ["%s" % mod for mod in pymod.env['NS3_ENABLED_CONTRIBUTED_MODULES']]
if pymod.env['ENABLE_STATIC_NS3']:
if sys.platform == 'darwin':
pymod.env.append_value('LINKFLAGS', '-Wl,-all_load')
for mod in pymod.usel:
#mod = mod.split("--lib")[0]
pymod.env.append_value('LINKFLAGS', '-l' + mod)
else:
pymod.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
for mod in pymod.use:
#mod = mod.split("--lib")[0]
pymod.env.append_value('LINKFLAGS', '-l' + mod)
pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
defines = list(pymod.env['DEFINES'])
defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H'])
defines.extend(['NS_DEPRECATED_3_35=', 'NS3_DEPRECATED_H'])
defines.extend(['NS_DEPRECATED_3_34=', 'NS3_DEPRECATED_H'])
if Utils.unversioned_sys_platform() == 'win32':
try:
defines.remove('_DEBUG') # causes undefined symbols on win32
except ValueError:
pass
pymod.env['DEFINES'] = defines
# The following string should lead to includes of
# '-I.', '-Isrc/core/bindings' when compiling module_helpers.cc
pymod.includes = Context.out_dir + ' ' + Context.out_dir + '/src/core/bindings'
pymod.install_path = '${PYTHONARCHDIR}/ns'
# Workaround to a WAF bug, remove this when ns-3 upgrades to WAF > 1.6.10
# https://www.nsnam.org/bugzilla/show_bug.cgi?id=1335
# http://code.google.com/p/waf/issues/detail?id=1098
if Utils.unversioned_sys_platform() == 'darwin':
pymod.mac_bundle = True
return pymod
def build(bld):
bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
bld.create_ns3_module_test_library = types.MethodType(create_ns3_module_test_library, bld)
bld.create_obj = types.MethodType(create_obj, bld)
bld.ns3_python_bindings = types.MethodType(ns3_python_bindings, bld)
all_contrib_modules = find_contrib_modules(bld)
# Remove these modules from the list of all modules.
for not_built in bld.env['MODULES_NOT_BUILT']:
if not_built in all_contrib_modules:
all_contrib_modules.remove(not_built)
bld.recurse(list(all_contrib_modules))
for module in all_contrib_modules:
modheader = bld(features='ns3moduleheader')
modheader.module = module.split('/')[-1]