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