2008-07-08 10:43:58 -07:00
|
|
|
#! /usr/bin/env python
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import os.path
|
|
|
|
|
|
|
|
|
|
import pybindgen.settings
|
|
|
|
|
from pybindgen.gccxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning
|
|
|
|
|
from pybindgen.typehandlers.codesink import FileCodeSink
|
|
|
|
|
from pygccxml.declarations import templates
|
|
|
|
|
from pygccxml.declarations.class_declaration import class_t
|
2009-11-19 11:19:39 +00:00
|
|
|
from pygccxml.declarations.calldef import free_function_t, member_function_t, constructor_t, calldef_t
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
## we need the smart pointer type transformation to be active even
|
|
|
|
|
## during gccxml scanning.
|
|
|
|
|
import ns3modulegen_core_customizations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## silence gccxmlparser errors; we only want error handling in the
|
|
|
|
|
## generated python script, not while scanning.
|
|
|
|
|
class ErrorHandler(pybindgen.settings.ErrorHandler):
|
|
|
|
|
def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_):
|
|
|
|
|
return True
|
|
|
|
|
pybindgen.settings.error_handler = ErrorHandler()
|
|
|
|
|
import warnings
|
|
|
|
|
warnings.filterwarnings(category=WrapperWarning, action='ignore')
|
|
|
|
|
|
|
|
|
|
type_annotations = {
|
|
|
|
|
'::ns3::RefCountBase': {
|
|
|
|
|
'incref_method': 'Ref',
|
|
|
|
|
'decref_method': 'Unref',
|
|
|
|
|
'peekref_method': 'GetReferenceCount',
|
|
|
|
|
'automatic_type_narrowing': 'true',
|
|
|
|
|
},
|
|
|
|
|
'::ns3::Object': {
|
|
|
|
|
'incref_method': 'Ref',
|
|
|
|
|
'decref_method': 'Unref',
|
|
|
|
|
'peekref_method': 'GetReferenceCount',
|
|
|
|
|
'automatic_type_narrowing': 'true',
|
|
|
|
|
},
|
|
|
|
|
'::ns3::Packet': {
|
|
|
|
|
'incref_method': 'Ref',
|
|
|
|
|
'decref_method': 'Unref',
|
|
|
|
|
'peekref_method': 'GetReferenceCount',
|
|
|
|
|
},
|
|
|
|
|
'::ns3::CallbackImplBase': {
|
|
|
|
|
'incref_method': 'Ref',
|
|
|
|
|
'decref_method': 'Unref',
|
|
|
|
|
'peekref_method': 'GetReferenceCount',
|
|
|
|
|
},
|
|
|
|
|
'::ns3::AttributeChecker': {
|
|
|
|
|
'automatic_type_narrowing': 'true',
|
|
|
|
|
'allow_subclassing': 'false',
|
|
|
|
|
},
|
|
|
|
|
'::ns3::AttributeValue': {
|
|
|
|
|
'automatic_type_narrowing': 'true',
|
|
|
|
|
'allow_subclassing': 'false',
|
|
|
|
|
},
|
2008-11-26 12:11:11 +00:00
|
|
|
|
|
|
|
|
'::ns3::CommandLine': {
|
|
|
|
|
'allow_subclassing': 'true', # needed so that AddValue is able to set attributes on the object
|
|
|
|
|
},
|
|
|
|
|
|
2009-09-02 11:29:23 +01:00
|
|
|
'::ns3::NscTcpL4Protocol': {
|
|
|
|
|
'ignore': 'true', # this class is implementation detail
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': {
|
|
|
|
|
'ignore': None,
|
|
|
|
|
},
|
|
|
|
|
'ns3::RandomVariableBase * ns3::RandomVariable::Peek() const [member function]': {
|
|
|
|
|
'ignore': None,
|
|
|
|
|
},
|
|
|
|
|
'void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function]': {
|
|
|
|
|
'params': {'seed':{'direction':'out',
|
|
|
|
|
'array_length':'6'}}
|
|
|
|
|
},
|
|
|
|
|
'bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInfo * info) const [member function]': {
|
|
|
|
|
'params': {'info':{'transfer_ownership': 'false'}}
|
|
|
|
|
},
|
|
|
|
|
'static bool ns3::TypeId::LookupByNameFailSafe(std::string name, ns3::TypeId * tid) [member function]': {
|
2008-10-15 15:55:09 +01:00
|
|
|
'ignore': None, # manually wrapped in
|
2008-07-08 10:43:58 -07:00
|
|
|
},
|
|
|
|
|
'bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
|
|
|
|
|
'params': {'obj': {'transfer_ownership':'false'}}
|
|
|
|
|
},
|
|
|
|
|
'bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
|
|
|
|
|
'params': {'obj': {'transfer_ownership':'false'}}
|
|
|
|
|
},
|
|
|
|
|
'bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
|
|
|
|
|
'params': {'obj': {'transfer_ownership':'false'}}
|
|
|
|
|
},
|
|
|
|
|
'bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
|
|
|
|
|
'params': {'obj': {'transfer_ownership':'false'}}
|
|
|
|
|
},
|
|
|
|
|
'bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function]': {
|
|
|
|
|
'params': {'object': {'transfer_ownership':'false'}}
|
|
|
|
|
},
|
|
|
|
|
'ns3::EmpiricalVariable::EmpiricalVariable(ns3::RandomVariableBase const & variable) [constructor]': {
|
|
|
|
|
'ignore': None
|
|
|
|
|
},
|
|
|
|
|
'static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function]': {
|
|
|
|
|
'caller_owns_return': 'false'
|
|
|
|
|
},
|
|
|
|
|
'void ns3::CommandLine::Parse(int argc, char * * argv) const [member function]': {
|
|
|
|
|
'ignore': None # manually wrapped
|
|
|
|
|
},
|
|
|
|
|
'extern void ns3::PythonCompleteConstruct(ns3::Ptr<ns3::Object> object, ns3::TypeId typeId, ns3::AttributeList const & attributes) [free function]': {
|
|
|
|
|
'ignore': None # used transparently by, should not be wrapped
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def get_ns3_relative_path(path):
|
|
|
|
|
l = []
|
|
|
|
|
head = path
|
|
|
|
|
while head:
|
|
|
|
|
head, tail = os.path.split(head)
|
|
|
|
|
if tail == 'ns3':
|
|
|
|
|
return os.path.join(*l)
|
|
|
|
|
l.insert(0, tail)
|
|
|
|
|
raise AssertionError("is the path %r inside ns3?!" % path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pre_scan_hook(dummy_module_parser,
|
|
|
|
|
pygccxml_definition,
|
|
|
|
|
global_annotations,
|
|
|
|
|
parameter_annotations):
|
|
|
|
|
ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name)
|
|
|
|
|
|
|
|
|
|
## Note: we don't include line numbers in the comments because
|
|
|
|
|
## those numbers are very likely to change frequently, which would
|
|
|
|
|
## cause needless changes, since the generated python files are
|
|
|
|
|
## kept under version control.
|
|
|
|
|
|
|
|
|
|
#global_annotations['pygen_comment'] = "%s:%i: %s" % \
|
|
|
|
|
# (ns3_header, pygccxml_definition.location.line, pygccxml_definition)
|
|
|
|
|
global_annotations['pygen_comment'] = "%s: %s" % \
|
|
|
|
|
(ns3_header, pygccxml_definition)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## handle ns3::Object::GetObject (left to its own devices,
|
|
|
|
|
## pybindgen will generate a mangled name containing the template
|
|
|
|
|
## argument type name).
|
|
|
|
|
if isinstance(pygccxml_definition, member_function_t) \
|
|
|
|
|
and pygccxml_definition.parent.name == 'Object' \
|
|
|
|
|
and pygccxml_definition.name == 'GetObject':
|
|
|
|
|
template_args = templates.args(pygccxml_definition.demangled_name)
|
|
|
|
|
if template_args == ['ns3::Object']:
|
|
|
|
|
global_annotations['template_instance_names'] = 'ns3::Object=>GetObject'
|
|
|
|
|
|
|
|
|
|
## Don't wrap Simulator::Schedule* (manually wrapped)
|
|
|
|
|
if isinstance(pygccxml_definition, member_function_t) \
|
|
|
|
|
and pygccxml_definition.parent.name == 'Simulator' \
|
|
|
|
|
and pygccxml_definition.name.startswith('Schedule'):
|
|
|
|
|
global_annotations['ignore'] = None
|
|
|
|
|
|
2009-01-13 19:28:26 +00:00
|
|
|
# manually wrapped
|
2008-08-05 19:42:53 +01:00
|
|
|
if isinstance(pygccxml_definition, member_function_t) \
|
|
|
|
|
and pygccxml_definition.parent.name == 'Simulator' \
|
|
|
|
|
and pygccxml_definition.name == 'Run':
|
2009-01-13 19:28:26 +00:00
|
|
|
global_annotations['ignore'] = True
|
2008-08-05 19:42:53 +01:00
|
|
|
|
2009-11-19 11:19:39 +00:00
|
|
|
## http://www.gccxml.org/Bug/view.php?id=9915
|
|
|
|
|
if isinstance(pygccxml_definition, calldef_t):
|
|
|
|
|
for arg in pygccxml_definition.arguments:
|
|
|
|
|
if arg.default_value is None:
|
|
|
|
|
continue
|
|
|
|
|
if "ns3::MilliSeconds( )" == arg.default_value:
|
|
|
|
|
arg.default_value = "ns3::MilliSeconds(0)"
|
2008-08-05 19:42:53 +01:00
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
## classes
|
|
|
|
|
if isinstance(pygccxml_definition, class_t):
|
|
|
|
|
# no need for helper classes to allow subclassing in Python, I think...
|
|
|
|
|
if pygccxml_definition.name.endswith('Helper'):
|
|
|
|
|
global_annotations['allow_subclassing'] = 'false'
|
|
|
|
|
|
|
|
|
|
if pygccxml_definition.decl_string.startswith('::ns3::Callback<'):
|
|
|
|
|
# manually handled in ns3modulegen_core_customizations.py
|
|
|
|
|
global_annotations['ignore'] = None
|
|
|
|
|
return
|
|
|
|
|
|
2008-08-18 16:00:10 +01:00
|
|
|
if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'):
|
|
|
|
|
global_annotations['ignore'] = None
|
|
|
|
|
return
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'):
|
|
|
|
|
# handled by pybindgen "type transformation"
|
|
|
|
|
global_annotations['ignore'] = None
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# table driven class customization
|
|
|
|
|
try:
|
|
|
|
|
annotations = type_annotations[pygccxml_definition.decl_string]
|
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
global_annotations.update(annotations)
|
|
|
|
|
|
|
|
|
|
## free functions
|
|
|
|
|
if isinstance(pygccxml_definition, free_function_t):
|
|
|
|
|
if pygccxml_definition.name == 'PeekPointer':
|
|
|
|
|
global_annotations['ignore'] = None
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
## table driven methods/constructors/functions customization
|
|
|
|
|
if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)):
|
|
|
|
|
try:
|
|
|
|
|
annotations = type_annotations[str(pygccxml_definition)]
|
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
for key,value in annotations.items():
|
|
|
|
|
if key == 'params':
|
|
|
|
|
parameter_annotations.update (value)
|
|
|
|
|
del annotations['params']
|
|
|
|
|
global_annotations.update(annotations)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper):
|
|
|
|
|
# ## classes
|
|
|
|
|
# if isinstance(pybindgen_wrapper, CppClass):
|
|
|
|
|
# if pybindgen_wrapper.name.endswith('Checker'):
|
|
|
|
|
# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper
|
|
|
|
|
# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def scan_callback_classes(module_parser, callback_classes_file):
|
|
|
|
|
callback_classes_file.write("callback_classes = [\n")
|
|
|
|
|
for cls in module_parser.module_namespace.classes(function=module_parser.location_filter,
|
|
|
|
|
recursive=False):
|
|
|
|
|
if not cls.name.startswith("Callback<"):
|
|
|
|
|
continue
|
|
|
|
|
assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls
|
|
|
|
|
dummy_cls_name, template_parameters = templates.split(cls.decl_string)
|
|
|
|
|
callback_classes_file.write(" %r,\n" % template_parameters)
|
|
|
|
|
callback_classes_file.write("]\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyPygenClassifier(PygenClassifier):
|
2009-11-18 12:03:43 +00:00
|
|
|
def __init__(self, headers_map, section_precendences):
|
2008-07-08 10:43:58 -07:00
|
|
|
self.headers_map = headers_map
|
2009-11-18 12:03:43 +00:00
|
|
|
self.section_precendences = section_precendences
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
def classify(self, pygccxml_definition):
|
|
|
|
|
name = os.path.basename(pygccxml_definition.location.file_name)
|
|
|
|
|
try:
|
|
|
|
|
return self.headers_map[name]
|
|
|
|
|
except KeyError:
|
|
|
|
|
return '__main__'
|
|
|
|
|
|
2009-11-18 12:03:43 +00:00
|
|
|
def get_section_precedence(self, section_name):
|
|
|
|
|
if section_name == '__main__':
|
|
|
|
|
return -1
|
|
|
|
|
return self.section_precendences[section_name]
|
|
|
|
|
|
2008-07-08 10:43:58 -07:00
|
|
|
|
2009-09-22 16:13:42 +01:00
|
|
|
def ns3_module_scan(top_builddir, pygen_file_name, everything_h, cflags):
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
ns3_modules = eval(sys.stdin.read())
|
|
|
|
|
|
|
|
|
|
## do a topological sort on the modules graph
|
|
|
|
|
from topsort import topsort
|
|
|
|
|
graph = []
|
|
|
|
|
for ns3_module_name, (ns3_module_deps, dummy) in ns3_modules.iteritems():
|
|
|
|
|
for dep in ns3_module_deps:
|
|
|
|
|
graph.append((dep, ns3_module_name))
|
|
|
|
|
sorted_ns3_modules = topsort(graph)
|
2008-07-09 14:58:02 +01:00
|
|
|
#print >> sys.stderr, "******* topological sort: ", sorted_ns3_modules
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
sections = [PygenSection('__main__', FileCodeSink(open(pygen_file_name, "wt")))]
|
|
|
|
|
headers_map = {} # header_name -> section_name
|
2009-11-18 12:03:43 +00:00
|
|
|
section_precendences = {} # section_name -> precedence
|
|
|
|
|
for prec, ns3_module in enumerate(sorted_ns3_modules):
|
2008-07-08 10:43:58 -07:00
|
|
|
section_name = "ns3_module_%s" % ns3_module.replace('-', '_')
|
|
|
|
|
file_name = os.path.join(os.path.dirname(pygen_file_name), "%s.py" % section_name)
|
|
|
|
|
sections.append(PygenSection(section_name, FileCodeSink(open(file_name, "wt")),
|
|
|
|
|
section_name + "__local"))
|
|
|
|
|
for header in ns3_modules[ns3_module][1]:
|
|
|
|
|
headers_map[header] = section_name
|
2009-11-18 12:03:43 +00:00
|
|
|
section_precendences[section_name] = prec
|
2008-07-08 10:43:58 -07:00
|
|
|
|
|
|
|
|
module_parser = ModuleParser('ns3', 'ns3')
|
|
|
|
|
|
|
|
|
|
module_parser.add_pre_scan_hook(pre_scan_hook)
|
|
|
|
|
#module_parser.add_post_scan_hook(post_scan_hook)
|
2008-07-23 11:48:17 +01:00
|
|
|
|
|
|
|
|
gccxml_options = dict(
|
|
|
|
|
include_paths=[top_builddir],
|
|
|
|
|
define_symbols={
|
2008-07-25 16:54:29 +01:00
|
|
|
#'NS3_ASSERT_ENABLE': None,
|
|
|
|
|
#'NS3_LOG_ENABLE': None,
|
2009-09-22 16:13:42 +01:00
|
|
|
},
|
|
|
|
|
cflags=('--gccxml-cxxflags %r' % (cflags,))
|
2008-07-23 11:48:17 +01:00
|
|
|
)
|
|
|
|
|
|
2008-07-09 14:58:02 +01:00
|
|
|
module_parser.parse_init([everything_h],
|
2008-07-23 11:48:17 +01:00
|
|
|
None, whitelist_paths=[top_builddir, os.path.dirname(everything_h)],
|
2008-07-08 10:43:58 -07:00
|
|
|
#includes=['"ns3/everything.h"'],
|
|
|
|
|
pygen_sink=sections,
|
2009-11-18 12:03:43 +00:00
|
|
|
pygen_classifier=MyPygenClassifier(headers_map, section_precendences),
|
2008-07-23 11:48:17 +01:00
|
|
|
gccxml_options=gccxml_options)
|
2008-07-08 10:43:58 -07:00
|
|
|
module_parser.scan_types()
|
|
|
|
|
|
|
|
|
|
callback_classes_file = open(os.path.join(os.path.dirname(pygen_file_name), "callbacks_list.py"), "wt")
|
|
|
|
|
scan_callback_classes(module_parser, callback_classes_file)
|
|
|
|
|
callback_classes_file.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module_parser.scan_methods()
|
|
|
|
|
module_parser.scan_functions()
|
|
|
|
|
module_parser.parse_finalize()
|
|
|
|
|
|
|
|
|
|
for section in sections:
|
|
|
|
|
section.code_sink.file.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2009-09-22 16:13:42 +01:00
|
|
|
ns3_module_scan(sys.argv[1], sys.argv[3], sys.argv[2], sys.argv[4])
|
2008-07-08 10:43:58 -07:00
|
|
|
|