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