bindings/python/ns3modulescan.py
author Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
Wed Sep 02 11:29:23 2009 +0100 (2009-09-02)
changeset 4749 af227579ab64
parent 4086 37dbf76b4c66
child 5249 85cde7d987ed
permissions -rw-r--r--
Don't python-bind the class NscTcpL4Protocol, it is implementation detail.
     1 #! /usr/bin/env python
     2 
     3 import sys
     4 import os.path
     5 
     6 import pybindgen.settings
     7 from pybindgen.gccxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning
     8 from pybindgen.typehandlers.codesink import FileCodeSink
     9 from pygccxml.declarations import templates
    10 from pygccxml.declarations.class_declaration import class_t
    11 from pygccxml.declarations.calldef import free_function_t, member_function_t, constructor_t
    12 
    13 
    14 ## we need the smart pointer type transformation to be active even
    15 ## during gccxml scanning.
    16 import ns3modulegen_core_customizations
    17 
    18 
    19 ## silence gccxmlparser errors; we only want error handling in the
    20 ## generated python script, not while scanning.
    21 class ErrorHandler(pybindgen.settings.ErrorHandler):
    22     def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_):
    23         return True
    24 pybindgen.settings.error_handler = ErrorHandler()
    25 import warnings
    26 warnings.filterwarnings(category=WrapperWarning, action='ignore')
    27 
    28 type_annotations = {
    29     '::ns3::RefCountBase': {
    30         'incref_method': 'Ref',
    31         'decref_method': 'Unref',
    32         'peekref_method': 'GetReferenceCount',
    33         'automatic_type_narrowing': 'true',
    34         },
    35     '::ns3::Object': {
    36         'incref_method': 'Ref',
    37         'decref_method': 'Unref',
    38         'peekref_method': 'GetReferenceCount',
    39         'automatic_type_narrowing': 'true',
    40         },
    41     '::ns3::Packet': {
    42         'incref_method': 'Ref',
    43         'decref_method': 'Unref',
    44         'peekref_method': 'GetReferenceCount',
    45         },
    46     '::ns3::CallbackImplBase': {
    47         'incref_method': 'Ref',
    48         'decref_method': 'Unref',
    49         'peekref_method': 'GetReferenceCount',
    50         },
    51     '::ns3::AttributeChecker': {
    52         'automatic_type_narrowing': 'true',
    53         'allow_subclassing': 'false',
    54         },
    55     '::ns3::AttributeValue': {
    56         'automatic_type_narrowing': 'true',
    57         'allow_subclassing': 'false',
    58         },
    59 
    60     '::ns3::CommandLine': {
    61         'allow_subclassing': 'true', # needed so that AddValue is able to set attributes on the object
    62         },
    63 
    64     '::ns3::NscTcpL4Protocol': {
    65         'ignore': 'true', # this class is implementation detail
    66         },
    67 
    68 
    69     'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': {
    70         'ignore': None,
    71         },
    72     'ns3::RandomVariableBase * ns3::RandomVariable::Peek() const [member function]': {
    73         'ignore': None,
    74         },
    75     'void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function]': {
    76         'params': {'seed':{'direction':'out',
    77                            'array_length':'6'}}
    78         },
    79     'bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInfo * info) const [member function]': {
    80         'params': {'info':{'transfer_ownership': 'false'}}
    81         },
    82     'static bool ns3::TypeId::LookupByNameFailSafe(std::string name, ns3::TypeId * tid) [member function]': {
    83         'ignore': None, # manually wrapped in 
    84         },
    85     'bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
    86         'params': {'obj': {'transfer_ownership':'false'}}
    87         },
    88     'bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
    89         'params': {'obj': {'transfer_ownership':'false'}}
    90         },
    91     'bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
    92         'params': {'obj': {'transfer_ownership':'false'}}
    93         },
    94     'bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
    95         'params': {'obj': {'transfer_ownership':'false'}}
    96         },
    97     'bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function]': {
    98         'params': {'object': {'transfer_ownership':'false'}}
    99         },
   100     'ns3::EmpiricalVariable::EmpiricalVariable(ns3::RandomVariableBase const & variable) [constructor]': {
   101         'ignore': None
   102         },
   103     'static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function]': {
   104         'caller_owns_return': 'false'
   105         },
   106     'void ns3::CommandLine::Parse(int argc, char * * argv) const [member function]': {
   107         'ignore': None # manually wrapped
   108         },
   109     'extern void ns3::PythonCompleteConstruct(ns3::Ptr<ns3::Object> object, ns3::TypeId typeId, ns3::AttributeList const & attributes) [free function]': {
   110         'ignore': None # used transparently by, should not be wrapped
   111         },
   112     }
   113 
   114 def get_ns3_relative_path(path):
   115     l = []
   116     head = path
   117     while head:
   118         head, tail = os.path.split(head)
   119         if tail == 'ns3':
   120             return os.path.join(*l)
   121         l.insert(0, tail)
   122     raise AssertionError("is the path %r inside ns3?!" % path)
   123 
   124 
   125 def pre_scan_hook(dummy_module_parser,
   126                   pygccxml_definition,
   127                   global_annotations,
   128                   parameter_annotations):
   129     ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name)
   130 
   131     ## Note: we don't include line numbers in the comments because
   132     ## those numbers are very likely to change frequently, which would
   133     ## cause needless changes, since the generated python files are
   134     ## kept under version control.
   135 
   136     #global_annotations['pygen_comment'] = "%s:%i: %s" % \
   137     #    (ns3_header, pygccxml_definition.location.line, pygccxml_definition)
   138     global_annotations['pygen_comment'] = "%s: %s" % \
   139         (ns3_header, pygccxml_definition)
   140 
   141 
   142     ## handle ns3::Object::GetObject (left to its own devices,
   143     ## pybindgen will generate a mangled name containing the template
   144     ## argument type name).
   145     if isinstance(pygccxml_definition, member_function_t) \
   146             and pygccxml_definition.parent.name == 'Object' \
   147             and pygccxml_definition.name == 'GetObject':
   148         template_args = templates.args(pygccxml_definition.demangled_name)
   149         if template_args == ['ns3::Object']:
   150             global_annotations['template_instance_names'] = 'ns3::Object=>GetObject'
   151 
   152     ## Don't wrap Simulator::Schedule* (manually wrapped)
   153     if isinstance(pygccxml_definition, member_function_t) \
   154             and pygccxml_definition.parent.name == 'Simulator' \
   155             and pygccxml_definition.name.startswith('Schedule'):
   156         global_annotations['ignore'] = None
   157 
   158     # manually wrapped
   159     if isinstance(pygccxml_definition, member_function_t) \
   160             and pygccxml_definition.parent.name == 'Simulator' \
   161             and pygccxml_definition.name == 'Run':
   162         global_annotations['ignore'] = True
   163 
   164 
   165     ## classes
   166     if isinstance(pygccxml_definition, class_t):
   167         # no need for helper classes to allow subclassing in Python, I think...
   168         if pygccxml_definition.name.endswith('Helper'):
   169             global_annotations['allow_subclassing'] = 'false'
   170 
   171         if pygccxml_definition.decl_string.startswith('::ns3::Callback<'):
   172             # manually handled in ns3modulegen_core_customizations.py
   173             global_annotations['ignore'] = None
   174             return
   175 
   176         if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'):
   177             global_annotations['ignore'] = None
   178             return
   179 
   180         if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'):
   181             # handled by pybindgen "type transformation"
   182             global_annotations['ignore'] = None
   183             return
   184 
   185         # table driven class customization
   186         try:
   187             annotations = type_annotations[pygccxml_definition.decl_string]
   188         except KeyError:
   189             pass
   190         else:
   191             global_annotations.update(annotations)
   192 
   193     ## free functions
   194     if isinstance(pygccxml_definition, free_function_t):
   195         if pygccxml_definition.name == 'PeekPointer':
   196             global_annotations['ignore'] = None
   197             return
   198 
   199     ## table driven methods/constructors/functions customization
   200     if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)):
   201         try:
   202             annotations = type_annotations[str(pygccxml_definition)]
   203         except KeyError:
   204             pass
   205         else:
   206             for key,value in annotations.items():
   207                 if key == 'params':
   208                     parameter_annotations.update (value)
   209                     del annotations['params']
   210             global_annotations.update(annotations)
   211 
   212 
   213 # def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper):
   214 #     ## classes
   215 #     if isinstance(pybindgen_wrapper, CppClass):
   216 #         if pybindgen_wrapper.name.endswith('Checker'):
   217 #             print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper
   218 #             #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function)
   219 
   220 
   221 def scan_callback_classes(module_parser, callback_classes_file):
   222     callback_classes_file.write("callback_classes = [\n")
   223     for cls in module_parser.module_namespace.classes(function=module_parser.location_filter,
   224                                                       recursive=False):
   225         if not cls.name.startswith("Callback<"):
   226             continue
   227         assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls
   228         dummy_cls_name, template_parameters = templates.split(cls.decl_string)
   229         callback_classes_file.write("    %r,\n" % template_parameters)
   230     callback_classes_file.write("]\n")
   231 
   232 
   233 class MyPygenClassifier(PygenClassifier):
   234     def __init__(self, headers_map):
   235         self.headers_map = headers_map
   236 
   237     def classify(self, pygccxml_definition):
   238         name = os.path.basename(pygccxml_definition.location.file_name)
   239         try:
   240             return self.headers_map[name]
   241         except KeyError:
   242             return '__main__'
   243 
   244 
   245 def ns3_module_scan(top_builddir, pygen_file_name, everything_h):
   246 
   247     ns3_modules = eval(sys.stdin.read())
   248 
   249     ## do a topological sort on the modules graph
   250     from topsort import topsort
   251     graph = []
   252     for ns3_module_name, (ns3_module_deps, dummy) in ns3_modules.iteritems():
   253         for dep in ns3_module_deps:
   254             graph.append((dep, ns3_module_name))
   255     sorted_ns3_modules = topsort(graph)
   256     #print >> sys.stderr, "******* topological sort: ", sorted_ns3_modules
   257 
   258     sections = [PygenSection('__main__', FileCodeSink(open(pygen_file_name, "wt")))]
   259     headers_map = {} # header_name -> section_name
   260     for ns3_module in sorted_ns3_modules:
   261         section_name = "ns3_module_%s" % ns3_module.replace('-', '_')
   262         file_name = os.path.join(os.path.dirname(pygen_file_name), "%s.py" % section_name)
   263         sections.append(PygenSection(section_name, FileCodeSink(open(file_name, "wt")),
   264                                      section_name + "__local"))
   265         for header in ns3_modules[ns3_module][1]:
   266             headers_map[header] = section_name
   267 
   268     module_parser = ModuleParser('ns3', 'ns3')
   269 
   270     module_parser.add_pre_scan_hook(pre_scan_hook)
   271     #module_parser.add_post_scan_hook(post_scan_hook)
   272 
   273     gccxml_options = dict(
   274         include_paths=[top_builddir],
   275          define_symbols={
   276             #'NS3_ASSERT_ENABLE': None,
   277             #'NS3_LOG_ENABLE': None,
   278             }
   279         )
   280 
   281     module_parser.parse_init([everything_h],
   282                              None, whitelist_paths=[top_builddir, os.path.dirname(everything_h)],
   283                              #includes=['"ns3/everything.h"'],
   284                              pygen_sink=sections,
   285                              pygen_classifier=MyPygenClassifier(headers_map),
   286                              gccxml_options=gccxml_options)
   287     module_parser.scan_types()
   288 
   289     callback_classes_file = open(os.path.join(os.path.dirname(pygen_file_name), "callbacks_list.py"), "wt")
   290     scan_callback_classes(module_parser, callback_classes_file)
   291     callback_classes_file.close()
   292 
   293 
   294     module_parser.scan_methods()
   295     module_parser.scan_functions()
   296     module_parser.parse_finalize()
   297 
   298     for section in sections:
   299         section.code_sink.file.close()
   300 
   301 
   302 
   303 if __name__ == '__main__':
   304     ns3_module_scan(sys.argv[1], sys.argv[3], sys.argv[2])
   305