2008-07-08 10:43:58 -07:00
|
|
|
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
import os
|
|
|
|
|
import pproc as subprocess
|
|
|
|
|
import shutil
|
2008-09-04 18:45:21 +01:00
|
|
|
import sys
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
import Task
|
|
|
|
|
import Options
|
|
|
|
|
import Configure
|
|
|
|
|
import TaskGen
|
|
|
|
|
import Logs
|
|
|
|
|
import Build
|
2008-12-29 15:48:34 +00:00
|
|
|
import Utils
|
2008-12-29 13:28:54 +00:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## https://launchpad.net/pybindgen/
|
2009-11-18 12:03:43 +00:00
|
|
|
REQUIRED_PYBINDGEN_VERSION = (0, 12, 0, 710)
|
2008-07-08 10:43:58 -07:00
|
|
|
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
|
|
|
|
|
|
|
|
|
|
|
2008-11-19 17:32:37 +00:00
|
|
|
def add_to_python_path(path):
|
|
|
|
|
if os.environ.get('PYTHONPATH', ''):
|
|
|
|
|
os.environ['PYTHONPATH'] = path + os.pathsep + os.environ.get('PYTHONPATH')
|
|
|
|
|
else:
|
|
|
|
|
os.environ['PYTHONPATH'] = path
|
|
|
|
|
|
|
|
|
|
def set_pybindgen_pythonpath(env):
|
|
|
|
|
if env['WITH_PYBINDGEN']:
|
|
|
|
|
add_to_python_path(env['WITH_PYBINDGEN'])
|
|
|
|
|
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
def set_options(opt):
|
|
|
|
|
opt.tool_options('python')
|
2008-09-06 14:46:01 +01:00
|
|
|
opt.add_option('--disable-python',
|
2008-07-08 10:43:58 -07:00
|
|
|
help=("Don't build Python bindings."),
|
|
|
|
|
action="store_true", default=False,
|
|
|
|
|
dest='python_disable')
|
|
|
|
|
opt.add_option('--python-scan',
|
|
|
|
|
help=("Rescan Python bindings. Needs working GCCXML / pygccxml environment."),
|
|
|
|
|
action="store_true", default=False,
|
|
|
|
|
dest='python_scan')
|
2008-11-19 17:32:37 +00:00
|
|
|
opt.add_option('--with-pybindgen',
|
|
|
|
|
help=('Path to an existing pybindgen source tree to use.'),
|
|
|
|
|
default=None,
|
|
|
|
|
dest='with_pybindgen', type="string")
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure(conf):
|
|
|
|
|
conf.env['ENABLE_PYTHON_BINDINGS'] = False
|
2008-12-29 13:28:54 +00:00
|
|
|
if Options.options.python_disable:
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"disabled by user request")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
conf.check_tool('misc')
|
|
|
|
|
|
2009-09-25 12:15:27 +01:00
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"unsupported platform 'cygwin'")
|
|
|
|
|
Logs.warn("Python is not supported in CygWin environment. Try MingW instead.")
|
|
|
|
|
return
|
2008-09-04 18:45:21 +01:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## Check for Python
|
|
|
|
|
try:
|
|
|
|
|
conf.check_tool('python')
|
2008-07-22 16:54:24 +01:00
|
|
|
conf.check_python_version((2,3))
|
2008-07-08 10:43:58 -07:00
|
|
|
conf.check_python_headers()
|
2008-09-05 18:16:29 +01:00
|
|
|
except Configure.ConfigurationError, ex:
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False, str(ex))
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
2009-03-03 18:51:16 +00:00
|
|
|
# -fvisibility=hidden optimization
|
2009-04-30 10:57:30 +01:00
|
|
|
if (conf.env['CXX_NAME'] == 'gcc' and [int(x) for x in conf.env['CC_VERSION']] >= [4,0,0]
|
|
|
|
|
and conf.check_compilation_flag('-fvisibility=hidden')):
|
2009-03-03 18:51:16 +00:00
|
|
|
conf.env.append_value('CXXFLAGS_PYEXT', '-fvisibility=hidden')
|
|
|
|
|
conf.env.append_value('CCFLAGS_PYEXT', '-fvisibility=hidden')
|
|
|
|
|
|
2009-01-24 15:28:54 +00:00
|
|
|
# Check for the location of pybindgen
|
|
|
|
|
if Options.options.with_pybindgen is not None:
|
|
|
|
|
if os.path.isdir(Options.options.with_pybindgen):
|
|
|
|
|
conf.check_message("pybindgen location", '', True, ("%s (given)" % Options.options.with_pybindgen))
|
|
|
|
|
conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen)
|
|
|
|
|
else:
|
|
|
|
|
pybindgen_dir = os.path.join('..', "pybindgen")
|
|
|
|
|
if os.path.isdir(pybindgen_dir):
|
|
|
|
|
conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_dir))
|
|
|
|
|
conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_dir)
|
|
|
|
|
del pybindgen_dir
|
|
|
|
|
if not conf.env['WITH_PYBINDGEN']:
|
|
|
|
|
conf.check_message("pybindgen location", '', False)
|
2008-11-19 17:32:37 +00:00
|
|
|
|
2009-01-24 15:28:54 +00:00
|
|
|
# Check for pybindgen
|
2008-11-19 17:32:37 +00:00
|
|
|
|
|
|
|
|
set_pybindgen_pythonpath(conf.env)
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
try:
|
|
|
|
|
conf.check_python_module('pybindgen')
|
|
|
|
|
except Configure.ConfigurationError:
|
2009-01-11 23:26:34 +00:00
|
|
|
Logs.warn("pybindgen missing => no python bindings")
|
|
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
|
|
|
|
"PyBindGen missing")
|
2009-01-12 18:45:03 +00:00
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
else:
|
|
|
|
|
out = subprocess.Popen([conf.env['PYTHON'], "-c",
|
|
|
|
|
"import pybindgen.version; "
|
|
|
|
|
"print '.'.join([str(x) for x in pybindgen.version.__version__])"],
|
|
|
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
|
|
|
pybindgen_version_str = out.strip()
|
|
|
|
|
pybindgen_version = tuple([int(x) for x in pybindgen_version_str.split('.')])
|
|
|
|
|
conf.check_message('pybindgen', 'version',
|
2009-05-24 11:39:41 +01:00
|
|
|
(pybindgen_version == REQUIRED_PYBINDGEN_VERSION),
|
2008-07-08 10:43:58 -07:00
|
|
|
pybindgen_version_str)
|
2009-05-24 11:39:41 +01:00
|
|
|
if not (pybindgen_version == REQUIRED_PYBINDGEN_VERSION):
|
|
|
|
|
Logs.warn("pybindgen (found %s), (need %s)" %
|
2008-07-08 10:43:58 -07:00
|
|
|
(pybindgen_version_str,
|
|
|
|
|
'.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION])))
|
2009-01-24 15:28:54 +00:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", False,
|
2009-05-24 11:39:41 +01:00
|
|
|
"PyBindGen version not correct and newer version could not be retrieved")
|
2009-01-24 15:28:54 +00:00
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
## If all has gone well, we finally enable the Python bindings
|
|
|
|
|
conf.env['ENABLE_PYTHON_BINDINGS'] = True
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("python", "Python Bindings", True, None)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
## Check for pygccxml
|
|
|
|
|
try:
|
|
|
|
|
conf.check_python_module('pygccxml')
|
|
|
|
|
except Configure.ConfigurationError:
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"Missing 'pygccxml' Python module")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
out = subprocess.Popen([conf.env['PYTHON'], "-c",
|
|
|
|
|
"import pygccxml; print pygccxml.__version__"],
|
|
|
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
|
|
|
pygccxml_version_str = out.strip()
|
|
|
|
|
pygccxml_version = tuple([int(x) for x in pygccxml_version_str.split('.')])
|
|
|
|
|
conf.check_message('pygccxml', 'version',
|
|
|
|
|
(pygccxml_version >= REQUIRED_PYGCCXML_VERSION),
|
|
|
|
|
pygccxml_version_str)
|
|
|
|
|
if not (pygccxml_version >= REQUIRED_PYGCCXML_VERSION):
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("pygccxml (found %s) is too old (need %s) => "
|
2008-07-08 10:43:58 -07:00
|
|
|
"automatic scanning of API definitions will not be possible" %
|
|
|
|
|
(pygccxml_version_str,
|
|
|
|
|
'.'.join([str(x) for x in REQUIRED_PYGCCXML_VERSION])))
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"pygccxml too old")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Check gccxml version
|
|
|
|
|
gccxml = conf.find_program('gccxml', var='GCCXML')
|
|
|
|
|
if not gccxml:
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("gccxml missing; automatic scanning of API definitions will not be possible")
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"gccxml missing")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
gccxml_version_line = os.popen(gccxml + " --version").readline().strip()
|
|
|
|
|
m = re.match( "^GCC-XML version (\d\.\d(\.\d)?)$", gccxml_version_line)
|
|
|
|
|
gccxml_version = m.group(1)
|
|
|
|
|
gccxml_version_ok = ([int(s) for s in gccxml_version.split('.')] >= [0, 9])
|
|
|
|
|
conf.check_message('gccxml', 'version', True, gccxml_version)
|
|
|
|
|
if not gccxml_version_ok:
|
2008-12-29 16:54:53 +00:00
|
|
|
Logs.warn("gccxml too old, need version >= 0.9; automatic scanning of API definitions will not be possible")
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", False,
|
|
|
|
|
"gccxml too old")
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
## If we reached
|
|
|
|
|
conf.env['ENABLE_PYTHON_SCANNING'] = True
|
2008-09-05 18:16:29 +01:00
|
|
|
conf.report_optional_feature("pygccxml", "Python API Scanning Support", True, None)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
prio_headers = {
|
|
|
|
|
-2: (
|
|
|
|
|
"string.h", # work around http://www.gccxml.org/Bug/view.php?id=6682
|
|
|
|
|
),
|
|
|
|
|
-1: (
|
|
|
|
|
"propagation-delay-model.h",
|
|
|
|
|
"propagation-loss-model.h",
|
|
|
|
|
"net-device.h",
|
2009-08-31 11:31:32 +01:00
|
|
|
"ipv4-interface.h",
|
2008-07-08 10:43:58 -07:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def get_header_prio(header):
|
|
|
|
|
for prio, headers in prio_headers.iteritems():
|
|
|
|
|
if header in headers:
|
|
|
|
|
return prio
|
|
|
|
|
return 1
|
|
|
|
|
|
2008-07-26 15:10:34 +01:00
|
|
|
|
|
|
|
|
def calc_header_include(path):
|
|
|
|
|
(head, tail) = os.path.split (path)
|
|
|
|
|
if tail == 'ns3':
|
|
|
|
|
return ''
|
|
|
|
|
else:
|
|
|
|
|
return os.path.join (calc_header_include (head), tail)
|
|
|
|
|
|
|
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
class gen_everything_h_task(Task.Task):
|
|
|
|
|
before = 'cc cxx'
|
2008-12-31 11:15:45 +00:00
|
|
|
after = 'ns3header_task'
|
|
|
|
|
color = 'BLUE'
|
2008-12-29 13:28:54 +00:00
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
assert len(self.outputs) == 1
|
2008-07-26 15:10:34 +01:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
header_files = [calc_header_include(node.abspath(self.env)) for node in self.inputs]
|
|
|
|
|
outfile = file(self.outputs[0].bldpath(self.env), "w")
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
def sort_func(h1, h2):
|
|
|
|
|
return cmp((get_header_prio(h1), h1), (get_header_prio(h1), h2))
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
header_files.sort(sort_func)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
print >> outfile, """
|
2008-11-24 12:39:50 +00:00
|
|
|
|
|
|
|
|
/* http://www.nsnam.org/bugzilla/show_bug.cgi?id=413 */
|
|
|
|
|
#ifdef ECHO
|
|
|
|
|
# undef ECHO
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
"""
|
|
|
|
|
for header in header_files:
|
|
|
|
|
print >> outfile, "#include \"ns3/%s\"" % (header,)
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
print >> outfile, """
|
2008-07-08 10:43:58 -07:00
|
|
|
namespace ns3 {
|
|
|
|
|
static inline Ptr<Object>
|
|
|
|
|
__dummy_function_to_force_template_instantiation (Ptr<Object> obj, TypeId typeId)
|
|
|
|
|
{
|
|
|
|
|
return obj->GetObject<Object> (typeId);
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-06 17:39:35 +01:00
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
__dummy_function_to_force_template_instantiation_v2 ()
|
|
|
|
|
{
|
|
|
|
|
Time t1, t2, t3;
|
|
|
|
|
t1 = t2 + t3;
|
|
|
|
|
t1 = t2 - t3;
|
|
|
|
|
TimeSquare tsq = t2*t3;
|
|
|
|
|
Time tsqdiv = tsq/Seconds(1);
|
|
|
|
|
Scalar scal = t2/t3;
|
|
|
|
|
TimeInvert inv = scal/t3;
|
|
|
|
|
t1 = scal*t1;
|
|
|
|
|
t1 = t1/scal;
|
|
|
|
|
t1 < t2;
|
|
|
|
|
t1 <= t2;
|
|
|
|
|
t1 == t2;
|
|
|
|
|
t1 != t2;
|
|
|
|
|
t1 >= t2;
|
|
|
|
|
t1 > t2;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-26 12:11:11 +00:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
}
|
|
|
|
|
"""
|
2008-12-29 13:28:54 +00:00
|
|
|
outfile.close()
|
|
|
|
|
return 0
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
|
2008-08-18 23:04:49 +01:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
class all_ns3_headers_taskgen(TaskGen.task_gen):
|
2008-07-08 10:43:58 -07:00
|
|
|
"""Generates a 'everything.h' header file that includes some/all public ns3 headers.
|
|
|
|
|
This single header file is to be parsed only once by gccxml, for greater efficiency.
|
|
|
|
|
"""
|
2008-12-29 13:28:54 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super(all_ns3_headers_taskgen, self).__init__(*args, **kwargs)
|
|
|
|
|
self.install_path = None
|
2008-07-09 14:58:02 +01:00
|
|
|
#self.inst_dir = 'ns3'
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
def apply(self):
|
|
|
|
|
## get all of the ns3 headers
|
2009-04-13 23:10:37 +01:00
|
|
|
ns3_dir_node = self.bld.path.find_dir("ns3")
|
2008-07-08 10:43:58 -07:00
|
|
|
all_headers_inputs = []
|
|
|
|
|
|
|
|
|
|
for filename in self.to_list(self.source):
|
2008-12-29 13:28:54 +00:00
|
|
|
src_node = ns3_dir_node.find_or_declare(filename)
|
2008-07-08 10:43:58 -07:00
|
|
|
if src_node is None:
|
2008-12-29 13:28:54 +00:00
|
|
|
raise Utils.WafError("source ns3 header file %s not found" % (filename,))
|
2008-07-08 10:43:58 -07:00
|
|
|
all_headers_inputs.append(src_node)
|
|
|
|
|
|
|
|
|
|
## if self.source was empty, include all ns3 headers in enabled modules
|
|
|
|
|
if not all_headers_inputs:
|
2009-04-13 23:10:37 +01:00
|
|
|
for ns3headers in self.bld.all_task_gen:
|
2008-07-08 10:43:58 -07:00
|
|
|
if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare
|
|
|
|
|
## skip headers not part of enabled modules
|
|
|
|
|
if self.env['NS3_ENABLED_MODULES']:
|
|
|
|
|
if ("ns3-%s" % ns3headers.module) not in self.env['NS3_ENABLED_MODULES']:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
for source in ns3headers.to_list(ns3headers.source):
|
2008-07-26 15:10:34 +01:00
|
|
|
#source = os.path.basename(source)
|
2008-12-29 13:28:54 +00:00
|
|
|
node = ns3_dir_node.find_or_declare(source)
|
2008-07-08 10:43:58 -07:00
|
|
|
if node is None:
|
2008-12-29 16:54:53 +00:00
|
|
|
raise Utils.WafError("missing header file %s" % (source,))
|
2008-07-08 10:43:58 -07:00
|
|
|
all_headers_inputs.append(node)
|
|
|
|
|
assert all_headers_inputs
|
2008-12-29 13:28:54 +00:00
|
|
|
all_headers_outputs = [self.path.find_or_declare("everything.h")]
|
|
|
|
|
task = self.create_task('gen_everything_h', self.env)
|
2008-07-08 10:43:58 -07:00
|
|
|
task.set_inputs(all_headers_inputs)
|
|
|
|
|
task.set_outputs(all_headers_outputs)
|
|
|
|
|
|
|
|
|
|
def install(self):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2009-04-13 23:10:37 +01:00
|
|
|
def get_modules_and_headers(bld):
|
2008-07-08 10:43:58 -07:00
|
|
|
"""
|
|
|
|
|
Gets a dict of
|
|
|
|
|
module_name => ([module_dep1, module_dep2, ...], [module_header1, module_header2, ...])
|
|
|
|
|
tuples, one for each module.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
retval = {}
|
2009-04-13 23:10:37 +01:00
|
|
|
for module in bld.all_task_gen:
|
2008-07-08 10:43:58 -07:00
|
|
|
if not module.name.startswith('ns3-'):
|
|
|
|
|
continue
|
|
|
|
|
module_name = module.name[4:] # strip the ns3- prefix
|
|
|
|
|
## find the headers object for this module
|
|
|
|
|
headers = []
|
2009-04-13 23:10:37 +01:00
|
|
|
for ns3headers in bld.all_task_gen:
|
2008-07-08 10:43:58 -07:00
|
|
|
if type(ns3headers).__name__ != 'ns3header_taskgen': # XXX: find less hackish way to compare
|
|
|
|
|
continue
|
|
|
|
|
if ns3headers.module != module_name:
|
|
|
|
|
continue
|
|
|
|
|
for source in ns3headers.to_list(ns3headers.source):
|
|
|
|
|
headers.append(source)
|
|
|
|
|
retval[module_name] = (list(module.module_deps), headers)
|
|
|
|
|
return retval
|
|
|
|
|
|
|
|
|
|
|
2008-08-18 23:04:49 +01:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
class python_scan_task(Task.TaskBase):
|
2008-08-18 23:04:49 +01:00
|
|
|
"""Uses gccxml to scan the file 'everything.h' and extract API definitions.
|
|
|
|
|
"""
|
2008-12-29 15:48:34 +00:00
|
|
|
after = 'gen_everything_h_task'
|
|
|
|
|
before = 'cc cxx'
|
2009-09-22 16:13:42 +01:00
|
|
|
color = "BLUE"
|
|
|
|
|
def __init__(self, curdirnode, env, bld, target, cflags):
|
2009-04-13 23:10:37 +01:00
|
|
|
self.bld = bld
|
|
|
|
|
super(python_scan_task, self).__init__(generator=self)
|
2008-08-18 23:04:49 +01:00
|
|
|
self.curdirnode = curdirnode
|
|
|
|
|
self.env = env
|
2009-09-22 16:13:42 +01:00
|
|
|
self.target = target
|
|
|
|
|
self.cflags = cflags
|
2008-12-29 15:48:34 +00:00
|
|
|
|
|
|
|
|
def display(self):
|
2009-09-22 16:13:42 +01:00
|
|
|
return 'python-scan-%s\n' % (self.target,)
|
2008-08-18 23:04:49 +01:00
|
|
|
|
|
|
|
|
def run(self):
|
2009-09-22 16:13:42 +01:00
|
|
|
defsdir = os.path.join(self.curdirnode.abspath(), 'apidefs', self.target)
|
|
|
|
|
try:
|
|
|
|
|
os.mkdir(defsdir)
|
|
|
|
|
except OSError:
|
|
|
|
|
pass
|
2008-08-18 23:04:49 +01:00
|
|
|
argv = [
|
|
|
|
|
self.env['PYTHON'],
|
|
|
|
|
os.path.join(self.curdirnode.abspath(), 'ns3modulescan.py'), # scanning script
|
|
|
|
|
self.curdirnode.find_dir('../..').abspath(self.env), # include path (where the ns3 include dir is)
|
2008-12-29 13:28:54 +00:00
|
|
|
self.curdirnode.find_or_declare('everything.h').abspath(self.env),
|
2009-09-22 16:13:42 +01:00
|
|
|
os.path.join(defsdir, 'ns3modulegen_generated.py'), # output file
|
|
|
|
|
self.cflags,
|
2008-08-18 23:04:49 +01:00
|
|
|
]
|
|
|
|
|
scan = subprocess.Popen(argv, stdin=subprocess.PIPE)
|
2009-04-13 23:10:37 +01:00
|
|
|
scan.stdin.write(repr(get_modules_and_headers(self.bld)))
|
2008-08-18 23:04:49 +01:00
|
|
|
scan.stdin.close()
|
2008-12-29 15:48:34 +00:00
|
|
|
retval = scan.wait()
|
2009-09-22 16:13:42 +01:00
|
|
|
return retval
|
|
|
|
|
|
|
|
|
|
class python_scan_task_collector(Task.TaskBase):
|
|
|
|
|
"""Tasks that waits for the python-scan-* tasks to complete and then signals WAF to exit
|
|
|
|
|
"""
|
|
|
|
|
after = 'python_scan_task'
|
|
|
|
|
before = 'cc cxx'
|
|
|
|
|
color = "BLUE"
|
|
|
|
|
def __init__(self, curdirnode, env, bld):
|
|
|
|
|
self.bld = bld
|
|
|
|
|
super(python_scan_task_collector, self).__init__(generator=self)
|
|
|
|
|
self.curdirnode = curdirnode
|
|
|
|
|
self.env = env
|
|
|
|
|
|
|
|
|
|
def display(self):
|
|
|
|
|
return 'python-scan-collector\n'
|
|
|
|
|
|
|
|
|
|
def run(self):
|
2008-12-29 15:48:34 +00:00
|
|
|
# signal stop (we generated files into the source dir and WAF
|
|
|
|
|
# can't cope with it, so we have to force the user to restart
|
|
|
|
|
# WAF)
|
2009-04-13 23:10:37 +01:00
|
|
|
self.bld.generator.stop = 1
|
2008-12-29 15:48:34 +00:00
|
|
|
return 0
|
|
|
|
|
|
2008-08-18 23:04:49 +01:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
def build(bld):
|
2008-12-29 13:28:54 +00:00
|
|
|
if Options.options.python_disable:
|
2008-07-08 10:43:58 -07:00
|
|
|
return
|
|
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
env = bld.env
|
|
|
|
|
curdir = bld.path.abspath()
|
2008-09-03 17:42:28 +01:00
|
|
|
|
2008-11-19 17:32:37 +00:00
|
|
|
set_pybindgen_pythonpath(env)
|
|
|
|
|
|
2008-07-26 15:23:41 +01:00
|
|
|
if env['ENABLE_PYTHON_BINDINGS']:
|
2008-12-29 13:28:54 +00:00
|
|
|
obj = bld.new_task_gen('all_ns3_headers')
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
if Options.options.python_scan:
|
2008-07-08 10:43:58 -07:00
|
|
|
if not env['ENABLE_PYTHON_SCANNING']:
|
2008-12-29 13:28:54 +00:00
|
|
|
raise Utils.WafError("Cannot re-scan python bindings: (py)gccxml not available")
|
2009-09-22 16:13:42 +01:00
|
|
|
scan_targets = []
|
|
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
scan_targets.append(('gcc-cygwin', ''))
|
|
|
|
|
else:
|
|
|
|
|
import struct
|
|
|
|
|
if struct.calcsize('I') == 4 and struct.calcsize('L') == 8 and struct.calcsize('P') == 8:
|
|
|
|
|
scan_targets.extend([('gcc-ILP32', '-m32'), ('gcc-LP64', '-m64')])
|
|
|
|
|
elif struct.calcsize('I') == 4 and struct.calcsize('L') == 4 and struct.calcsize('P') == 4:
|
|
|
|
|
scan_targets.append(('gcc-ILP32', ''))
|
|
|
|
|
else:
|
|
|
|
|
raise Utils.WafError("Cannot scan python bindings for unsupported data model")
|
|
|
|
|
for target, cflags in scan_targets:
|
|
|
|
|
python_scan_task(bld.path, env, bld, target, cflags)
|
|
|
|
|
python_scan_task_collector(bld.path, env, bld)
|
2008-12-29 15:48:34 +00:00
|
|
|
return
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
if env['ENABLE_PYTHON_BINDINGS']:
|
2009-09-22 16:13:42 +01:00
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
apidefs = 'gcc-cygwin'
|
|
|
|
|
else:
|
|
|
|
|
import struct
|
|
|
|
|
if struct.calcsize('I') == 4 and struct.calcsize('L') == 8 and struct.calcsize('P') == 8:
|
|
|
|
|
apidefs = 'gcc-LP64'
|
|
|
|
|
elif struct.calcsize('I') == 4 and struct.calcsize('L') == 4 and struct.calcsize('P') == 4:
|
|
|
|
|
apidefs = 'gcc-ILP32'
|
|
|
|
|
else:
|
|
|
|
|
print "Cannot build python bindings for unsupported data model"
|
|
|
|
|
return
|
|
|
|
|
#print "Will build python bindings for target:", apidefs
|
|
|
|
|
|
|
|
|
|
## Get a list of scanned modules; the set of scanned modules
|
|
|
|
|
## may be smaller than the set of all modules, in case a new
|
|
|
|
|
## ns3 module is being developed which wasn't scanned yet.
|
|
|
|
|
scanned_modules = []
|
|
|
|
|
for filename in os.listdir(os.path.join(curdir, 'apidefs', apidefs)):
|
|
|
|
|
m = re.match(r"^ns3_module_(.+)\.py$", filename)
|
|
|
|
|
if m is None:
|
|
|
|
|
continue
|
|
|
|
|
name = m.group(1)
|
|
|
|
|
if name.endswith("__local"):
|
|
|
|
|
continue
|
|
|
|
|
scanned_modules.append(name)
|
|
|
|
|
|
2009-09-16 15:03:25 +01:00
|
|
|
debug = ('PYBINDGEN_DEBUG' in os.environ)
|
2008-12-29 13:28:54 +00:00
|
|
|
source = [
|
|
|
|
|
'ns3modulegen.py',
|
2009-09-22 16:13:42 +01:00
|
|
|
'apidefs/%s/ns3modulegen_generated.py' % (apidefs,),
|
2008-12-29 13:28:54 +00:00
|
|
|
'ns3modulegen_core_customizations.py',
|
|
|
|
|
]
|
|
|
|
|
target = [
|
|
|
|
|
'ns3module.cc',
|
|
|
|
|
'ns3module.h',
|
2008-07-08 10:43:58 -07:00
|
|
|
]
|
2009-09-16 15:03:25 +01:00
|
|
|
if not debug:
|
|
|
|
|
target.append('ns3modulegen.log')
|
|
|
|
|
|
|
|
|
|
argv = ['NS3_ENABLED_FEATURES=${FEATURES}', '${PYTHON}']
|
|
|
|
|
if debug:
|
|
|
|
|
argv.extend(["-m", "pdb"])
|
2009-09-22 16:13:42 +01:00
|
|
|
argv.extend(['${SRC[0]}', '${TGT[0]}', os.path.join(curdir, 'apidefs', apidefs)])
|
|
|
|
|
|
2009-04-13 23:10:37 +01:00
|
|
|
argv.extend(get_modules_and_headers(bld).iterkeys())
|
2008-07-14 11:25:10 +01:00
|
|
|
for module in scanned_modules:
|
2009-09-22 16:13:42 +01:00
|
|
|
source.append("apidefs/%s/ns3_module_%s.py" % (apidefs, module))
|
2008-09-03 17:42:28 +01:00
|
|
|
local = "ns3_module_%s__local.py" % module
|
|
|
|
|
if os.path.exists(os.path.join(curdir, local)):
|
2008-12-29 13:28:54 +00:00
|
|
|
source.append(local)
|
|
|
|
|
|
2009-09-16 15:03:25 +01:00
|
|
|
if not debug:
|
|
|
|
|
argv.extend(['2>', '${TGT[2]}']) # 2> ns3modulegen.log
|
2008-07-14 11:25:10 +01:00
|
|
|
|
|
|
|
|
for module in scanned_modules:
|
2008-12-29 13:28:54 +00:00
|
|
|
target.append("ns3_module_%s.cc" % module)
|
2008-07-14 11:25:10 +01:00
|
|
|
|
2008-09-06 19:24:32 +01:00
|
|
|
features = []
|
|
|
|
|
for (name, caption, was_enabled, reason_not_enabled) in env['NS3_OPTIONAL_FEATURES']:
|
|
|
|
|
if was_enabled:
|
|
|
|
|
features.append(name)
|
2008-12-29 13:28:54 +00:00
|
|
|
|
2009-04-06 13:05:59 +01:00
|
|
|
bindgen = bld.new_task_gen('command', source=source, target=target, command=argv)
|
|
|
|
|
bindgen.env['FEATURES'] = ','.join(features)
|
|
|
|
|
bindgen.dep_vars = ['FEATURES']
|
2009-01-14 11:17:41 +00:00
|
|
|
bindgen.before = 'cxx'
|
|
|
|
|
bindgen.after = 'gen_everything_h_task'
|
2009-04-13 23:10:37 +01:00
|
|
|
bindgen.name = "pybindgen-command"
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
pymod = bld.new_task_gen('cxx', 'shlib', 'pyext')
|
2009-06-17 11:26:36 +01:00
|
|
|
if sys.platform == 'cygwin':
|
|
|
|
|
pymod.features.append('implib') # workaround for WAF bug #472
|
2008-07-08 10:43:58 -07:00
|
|
|
pymod.source = ['ns3module.cc', 'ns3module_helpers.cc']
|
|
|
|
|
pymod.includes = '.'
|
2008-07-14 11:35:58 +01:00
|
|
|
for module in scanned_modules:
|
|
|
|
|
pymod.source.append("ns3_module_%s.cc" % module)
|
2008-07-08 10:43:58 -07:00
|
|
|
pymod.target = 'ns3/_ns3'
|
|
|
|
|
pymod.name = 'ns3module'
|
|
|
|
|
pymod.uselib_local = "ns3"
|
2009-04-22 17:22:41 +02:00
|
|
|
if pymod.env['ENABLE_STATIC_NS3']:
|
2009-05-05 14:55:23 +02:00
|
|
|
if sys.platform == 'darwin':
|
|
|
|
|
pymod.env.append_value('LINKFLAGS', '-Wl,-all_load')
|
|
|
|
|
pymod.env.append_value('LINKFLAGS', '-lns3')
|
|
|
|
|
else:
|
|
|
|
|
pymod.env.append_value('LINKFLAGS', '-Wl,--whole-archive,-Bstatic')
|
|
|
|
|
pymod.env.append_value('LINKFLAGS', '-lns3')
|
|
|
|
|
pymod.env.append_value('LINKFLAGS', '-Wl,-Bdynamic,--no-whole-archive')
|
2009-01-17 16:58:42 +00:00
|
|
|
|
|
|
|
|
defines = list(pymod.env['CXXDEFINES'])
|
|
|
|
|
defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H'])
|
|
|
|
|
if Options.platform == 'win32':
|
|
|
|
|
try:
|
|
|
|
|
defines.remove('_DEBUG') # causes undefined symbols on win32
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass
|
|
|
|
|
pymod.env['CXXDEFINES'] = defines
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2008-12-29 13:28:54 +00:00
|
|
|
# copy the __init__.py file to the build dir. waf can't handle
|
2008-07-08 10:43:58 -07:00
|
|
|
# this, it's against waf's principles to have build dir files
|
|
|
|
|
# with the same name as source dir files, apparently.
|
2008-12-29 13:28:54 +00:00
|
|
|
dirnode = bld.path.find_dir('ns3')
|
2008-07-08 10:43:58 -07:00
|
|
|
src = os.path.join(dirnode.abspath(), '__init__.py')
|
|
|
|
|
dst = os.path.join(dirnode.abspath(env), '__init__.py')
|
|
|
|
|
try:
|
|
|
|
|
need_copy = os.stat(src).st_mtime > os.stat(dst).st_mtime
|
|
|
|
|
except OSError:
|
|
|
|
|
need_copy = True
|
|
|
|
|
if need_copy:
|
|
|
|
|
try:
|
|
|
|
|
os.mkdir(os.path.dirname(dst))
|
|
|
|
|
except OSError:
|
|
|
|
|
pass
|
|
|
|
|
print "%r -> %r" % (src, dst)
|
|
|
|
|
shutil.copy2(src, dst)
|