Bug 1174 - Ns-3 does not generate static libraries

This commit is contained in:
Gustavo J. A. M. Carneiro
2011-07-03 12:01:29 +01:00
parent cae6446d9e
commit 681bd950be
2 changed files with 177 additions and 57 deletions

View File

@@ -103,52 +103,126 @@ def configure(conf):
conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
def create_ns3_module(bld, name, dependencies=(), test=False):
# Create a separate library for this module.
if bld.env['ENABLE_STATIC_NS3']:
module = bld.new_task_gen('cxx', 'cstaticlib')
else:
module = bld.new_task_gen('cxx', 'cshlib')
if not test:
pcfile = bld.new_task_gen('ns3pcfile')
pcfile.module = module
class ns3module_taskgen(TaskGen.task_gen):
def __init__(self, *args, **kwargs):
super(ns3module_taskgen, self).__init__(*args, **kwargs)
self.libs = []
def apply(self):
static_enabled = False
shared_enabled = True
bld = self.bld
if bld.env['ENABLE_STATIC_NS3']:
static_enabled = True
shared_enabled = False
if bld.env['ENABLE_SHARED_AND_STATIC_NS3']:
static_enabled = True
shared_enabled = True
assert self.name.startswith("ns3-")
name = self.name.split("ns3-")[1]
if static_enabled:
static = self._create_ns3_module(self.bld, name, self.dependencies, True)
self.libs.append(static)
else:
static = None
if shared_enabled:
shared = self._create_ns3_module(self.bld, name, self.dependencies, False)
self.libs.append(shared)
else:
shared = None
if static is not None and shared is None:
static.name = self.name + "--lib"
static.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
elif shared is not None and static is None:
shared.name = self.name + "--lib"
shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
else:
shared.name = self.name + "--lib"
shared.uselib_local = ['ns3-%s--lib' % (dep,) for dep in self.dependencies]
static.name = self.name + "--static"
static.uselib_local = ['ns3-%s--static' % (dep,) for dep in self.dependencies]
if not self.test:
pcfile = bld.new_task_gen('ns3pcfile')
pcfile.module = self
def _create_ns3_module(self, bld, name, dependencies, static):
# FIXME: env modifications are overwritten by parent caller
# Create a separate library for this module.
if static:
module = bld.new_task_gen('cxx', 'cstaticlib')
else:
module = bld.new_task_gen('cxx', 'cshlib')
module.source = self.source
module.env = self.env.copy()
features = list(self.features)
features.remove("ns3module")
module.features.extend(features)
module.path = self.path
module.uselib = self.uselib
if hasattr(self, 'includes'):
module.includes = self.includes
if hasattr(self, "is_ns3_module"):
module.is_ns3_module = self.is_ns3_module
module.is_static = static
module.vnum = wutils.VNUM
# Add the proper path to the module's name.
module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(self.path), name)
# Set the libraries this module depends on.
module.module_deps = list(dependencies)
if not static:
module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
module.env.append_value('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 = os.path.basename(ccroot.get_target_name(module))
module.env.append_value('LINKFLAGS', '-Wl,--soname=%s' % module_library_name)
elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \
os.uname()[4] == 'x86_64' and \
module.env['ENABLE_PYTHON_BINDINGS']:
# enable that flag for static builds only on x86-64 platforms
# when gcc is present and only when we want python bindings
# (it's more efficient to not use this option if we can avoid it)
module.env.append_value('CXXFLAGS', '-mcmodel=large')
module.env.append_value('CCFLAGS', '-mcmodel=large')
module.env.append_value('CXXDEFINES', "NS3_MODULE_COMPILATION")
module.env.append_value('CCDEFINES', "NS3_MODULE_COMPILATION")
module.install_path = "${LIBDIR}"
return module
def create_ns3_module(bld, name, dependencies=(), test=False):
module = bld.new_task_gen('ns3module')
module.bld = bld
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.is_ns3_module = True
module.name = 'ns3-' + name
module.vnum = wutils.VNUM
# Add the proper path to the module's name.
module.target = '%s/ns3-%s' % (bld.srcnode.relpath_gen(bld.path), name)
# Set the libraries this module depends on.
module.uselib_local = ['ns3-' + dep for dep in dependencies]
module.module_deps = list(dependencies)
if not module.env['ENABLE_STATIC_NS3']:
module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
module.env.append_value('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 = os.path.basename(ccroot.get_target_name(module))
module.env.append_value('LINKFLAGS', '-Wl,--soname=%s' % module_library_name)
elif module.env['CXX_NAME'] in ['gcc', 'icc'] and \
os.uname()[4] == 'x86_64' and \
module.env['ENABLE_PYTHON_BINDINGS']:
# enable that flag for static builds only on x86-64 platforms
# when gcc is present and only when we want python bindings
# (it's more efficient to not use this option if we can avoid it)
module.env.append_value('CXXFLAGS', '-mcmodel=large')
module.env.append_value('CCFLAGS', '-mcmodel=large')
module.env.append_value('CXXDEFINES', "NS3_MODULE_COMPILATION")
module.env.append_value('CCDEFINES', "NS3_MODULE_COMPILATION")
module.test = test
module.is_ns3_module = True
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.
@@ -258,15 +332,17 @@ def ns3_python_bindings(bld):
pymod.source = ['bindings/ns3module.cc']
pymod.target = '%s/%s' % (module_target_dir, extension_name)
pymod.name = 'ns3module_%s' % module
pymod.uselib_local = pymod.env['NS3_ENABLED_MODULES'] # Should be '"ns3-"+module', but see bug 1117
pymod.uselib_local = ["%s--lib" % mod for mod in pymod.env['NS3_ENABLED_MODULES']] # Should be '"ns3-"+module', but see bug 1117
if pymod.env['ENABLE_STATIC_NS3']:
if sys.platform == 'darwin':
pymod.env.append_value('LINKFLAGS', '-Wl,-all_load')
for mod in pymod.uselib_local:
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.uselib_local:
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['CXXDEFINES'])
@@ -416,7 +492,6 @@ class ns3header_taskgen(TaskGen.task_gen):
def apply(self):
for filename in set(self.to_list(self.source)):
src_node = self.path.find_resource(filename)
self.bld.install_files('${PREFIX}/include/ns3', [src_node])
if self.module is None:
raise Utils.WafError("'module' missing on ns3headers object %s" % self)
ns3_dir_node = self.bld.path.find_dir("ns3")
@@ -431,6 +506,7 @@ class ns3header_taskgen(TaskGen.task_gen):
task = self.create_task('ns3header', env=self.env)
task.mode = self.mode
if self.mode == 'install':
self.bld.install_files('${PREFIX}/include/ns3', [src_node])
task.set_inputs([src_node])
task.set_outputs([dst_node])
else:
@@ -598,13 +674,13 @@ class ns3moduleheader_taskgen(TaskGen.task_gen):
raise Utils.WscriptError("error finding headers for module %s" % self.module)
if not all_headers_inputs:
return
self.bld.install_files('${PREFIX}/include/ns3',
ns3_dir_node.find_or_declare("%s-module.h" % self.module))
all_headers_outputs = [ns3_dir_node.find_or_declare("%s-module.h" % self.module)]
task = self.create_task('gen_ns3_module_header', env=self.env)
task.module = self.module
task.mode = self.mode
if self.mode == 'install':
self.bld.install_files('${PREFIX}/include/ns3',
ns3_dir_node.find_or_declare("%s-module.h" % self.module))
task.set_inputs(all_headers_inputs)
task.set_outputs(all_headers_outputs)
module_obj = self.bld.name_to_obj("ns3-" + self.module, self.env)

74
wscript
View File

@@ -207,6 +207,10 @@ def set_options(opt):
help=('Compile NS-3 statically: works only on linux, without python'),
dest='enable_static', action='store_true',
default=False)
opt.add_option('--enable-shared-and-static',
help=('Compile NS-3 both shared and static libraries at the same time: static works only on linux'),
dest='enable_shared_and_static', action='store_true',
default=False)
opt.add_option('--enable-mpi',
help=('Compile NS-3 with MPI and distributed simulation support'),
dest='enable_mpi', action='store_true',
@@ -316,12 +320,15 @@ def configure(conf):
env['WL_SONAME_SUPPORTED'] = True
env['ENABLE_STATIC_NS3'] = False
if Options.options.enable_static:
if Options.options.enable_static or Options.options.enable_shared_and_static:
if env['PLATFORM'].startswith('linux') and \
env['CXX_NAME'] in ['gcc', 'icc']:
if re.match('i[3-6]86', os.uname()[4]):
conf.report_optional_feature("static", "Static build", True, '')
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_static:
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_shared_and_static:
env['ENABLE_SHARED_AND_STATIC_NS3'] = True
elif os.uname()[4] == 'x86_64':
if env['ENABLE_PYTHON_BINDINGS'] and \
not conf.check_compilation_flag('-mcmodel=large'):
@@ -332,12 +339,18 @@ def configure(conf):
"compiler to at least gcc 4.3.x.")
else:
conf.report_optional_feature("static", "Static build", True, '')
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_static:
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_shared_and_static:
env['ENABLE_SHARED_AND_STATIC_NS3'] = True
elif env['CXX_NAME'] == 'gcc' and \
(env['PLATFORM'].startswith('darwin') or \
env['PLATFORM'].startswith('cygwin')):
conf.report_optional_feature("static", "Static build", True, '')
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_static:
env['ENABLE_STATIC_NS3'] = True
if Options.options.enable_shared_and_static:
env['ENABLE_SHARED_AND_STATIC_NS3'] = True
else:
conf.report_optional_feature("static", "Static build", False,
"Unsupported platform")
@@ -558,18 +571,7 @@ def create_ns3_program(bld, name, dependencies=('core',)):
program.name = name
program.target = program.name
# Each of the modules this program depends on has its own library.
program.uselib_local = ['ns3-' + dep for dep in dependencies]
program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies]
if program.env['ENABLE_STATIC_NS3']:
if sys.platform == 'darwin':
program.env.append_value('LINKFLAGS', '-Wl,-all_load')
for dep in dependencies:
program.env.append_value('LINKFLAGS', '-lns3-' + dep)
else:
program.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
for dep in dependencies:
program.env.append_value('LINKFLAGS', '-lns3-' + dep)
program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
return program
def register_ns3_script(bld, name, dependencies=('core',)):
@@ -606,6 +608,22 @@ def add_scratch_programs(bld):
obj.name = obj.target
def _add_ns3_program_missing_deps(bld, program):
deps_found = program.ns3_module_dependencies
program.uselib_local = [dep + "--lib" for dep in deps_found]
if program.env['ENABLE_STATIC_NS3'] and not program.env['ENABLE_SHARED_AND_STATIC_NS3']:
if sys.platform == 'darwin':
program.env.append_value('LINKFLAGS', '-Wl,-all_load')
for dep in deps_found:
program.env.append_value('LINKFLAGS', '-l' + dep)
else:
program.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
for dep in deps_found:
program.env.append_value('LINKFLAGS', '-l' + dep)
program.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
def build(bld):
# If --enabled-modules option was given, then print a warning
# message and exit this function.
@@ -751,6 +769,32 @@ def build(bld):
bld.add_subdirs('bindings/python')
## do a topological sort on the modules graph
dep_graph = []
for gen in bld.all_task_gen:
if type(gen).__name__ in ['ns3module_taskgen']:
for dep in gen.dependencies:
dep_graph.append(("ns3-"+dep, gen.name))
dep_graph.sort()
sys.path.insert(0, "bindings/python")
from topsort import topsort
sorted_ns3_modules = topsort(dep_graph)
#print sorted_ns3_modules
# we need to post() the ns3 modules, so they create libraries underneath, and programs can list them in uselib_local
for module in sorted_ns3_modules:
gen = bld.name_to_obj(module, bld.env)
if type(gen).__name__ in ['ns3module_taskgen']:
gen.post()
for lib in gen.libs:
lib.post()
for gen in bld.all_task_gen:
if not getattr(gen, "is_ns3_program", False) or not hasattr(gen, "ns3_module_dependencies"):
continue
_add_ns3_program_missing_deps(bld, gen)
if Options.options.run:
# Check that the requested program name is valid
program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, wutils.get_command_template(env))