Exemple #1
0
    def __init__(self):
        # read enums
        filepath = 'db_ic.h'

        allData = self.readFile(filepath)

        cppheader = CppHeader(allData, argType='string')
        self.devices = cppheader.enums[0].get('values')

        data = allData.split('};')[2].split('\n')

        r = r"{(.*),(.*),(.*)}"

        for line in data:
            try:
                items = [x.strip() for x in re.search(r, line).groups()]
                self.addPropToDevice(items[0].strip(), 'phys_max',
                                     items[1].strip())
                self.addPropToDevice(items[0].strip(), 'phys_min',
                                     items[2].strip())
            except AttributeError:
                pass

        treeData = allData.split('};')[1]
        self.parseTree(treeData)
Exemple #2
0
 def parse_header(self, path: str, c_include_path: str):
     with open(path) as f:
         data = self.preprocess_header(f.read())
     header = CppHeader(data, 'string')
     self.parse_typedefs(c_include_path, header.typedefs)
     self.parse_enums(c_include_path, header.enums)
     self.parse_classes_and_structs(c_include_path, header.classes)
     self.parse_functions(c_include_path, header.functions)
Exemple #3
0
 def parse_header(self, path: str, c_include_path: str):
     try:
         with self.context('header', path, c_include_path):
             with open(path) as f:
                 data = self.preprocess_header(f.read())
             header = CppHeader(data, 'string')
             self.parse_typedefs(c_include_path, header.typedefs)
             self.parse_enums(c_include_path, header.enums)
             self.parse_classes_and_structs(c_include_path, header.classes)
             self.parse_functions(c_include_path, header.functions)
     except Exception as e:
         raise ParseError(self.context) from e
Exemple #4
0
 def __init__(self, module_name, original_text):
     self.module_name = module_name
     self.original_text = original_text
     self.use_generated_header = True
     with open('temp.c', 'w') as f:
         f.write(original_text)
     self.cpp_header = CppHeader('temp.c')
     self.cpp_file = "{}.cpp".format(module_name)
     if os.path.isfile(self.cpp_file):
         os.remove(self.cpp_file)
     self.hpp_file = "{}.hpp".format(module_name)
     if os.path.isfile(self.hpp_file):
         os.remove(self.hpp_file)
     self.generate_cpp()
     self.generate_hpp()
Exemple #5
0
    def __init__(self, module_name, original_text):
        try:
            from CppHeaderParser import CppHeader
        except ImportError:
            raise ImportError("Requires CppHeaderParser to be installed.")

        self.module_name = module_name
        self.original_text = original_text
        self.use_generated_header = True
        with open('temp.c', 'w') as f:
            f.write(original_text)
        self.cpp_header = CppHeader('temp.c')
        self.cpp_file = "{}.cpp".format(module_name)
        if os.path.isfile(self.cpp_file):
            os.remove(self.cpp_file)
        self.hpp_file = "{}.hpp".format(module_name)
        if os.path.isfile(self.hpp_file):
            os.remove(self.hpp_file)
        self.generate_cpp()
        self.generate_hpp()
Exemple #6
0
def read_robot_config(robot_name):

    header = CppHeader(header_path('SL_user.h', robot_name))
    defines, enums = parse_defines(header, include_enums=True)
    defines = replace_defines(defines, _defines)
    defines.update(_defines)

    return {
        'joints':
        [enums['RobotDOFs'][i + 1] for i in range(defines['N_DOFS'])],
        'endeffectors': [
            enums['RobotEndeffectors'][i + 1]
            for i in range(defines['N_ENDEFFS'])
        ],
        'links':
        [enums['RobotLinks'][i + 1] for i in range(defines['N_LINKS'])],
        'defines':
        defines,
        'enums':
        enums,
    }
Exemple #7
0
def _load(module):

    if len(_defines):
        return

    with open(header_path(), 'r') as fp:
        header_file = fp.read()

    header = CppHeader(header_file, argType='string')
    defines = parse_defines(header)

    setattr(modules[module], 'SEM_ID', ctypes.c_long)

    types = {'SEM_ID': ctypes.c_long}
    for struct_name in header.classes.keys():
        fields = read_struct_format(header_file, struct_name, defines=defines)
        struct_type = type(struct_name, (CStruct, ), {'_fields_': fields})
        setattr(modules[module], struct_name, struct_type)
        types[struct_name] = struct_type

    _defines.update(defines)
    _types.update(types)
def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--msg-dir',
                        type=str,
                        metavar='DIR',
                        default='msg',
                        help='Directory to write (updated) msg files to')
    parser.add_argument('HDR', help='Path to Ruckig input_parameter.hpp')
    args = parser.parse_args()

    msg_dir = os.path.abspath(args.msg_dir)
    if not os.path.isdir(msg_dir):
        sys.stderr.write(
            f"Can't seem to find the 'msg' dir at '{msg_dir}', aborting\n")
        sys.exit(1)

    parsed_h = CppHeader(args.HDR)
    if not parsed_h.enums:
        sys.stderr.write(
            f"No enums found in header (is this the correct header?), aborting\n"
        )
        sys.exit(2)
    # we expect at least some enums we know in there
    flambda = lambda enum: enum['name'] in ['Result', 'DurationDiscretization']
    if not list(filter(flambda, parsed_h.enums)):
        sys.stderr.write(
            "Probably not a Ruckig header (could not find any known enums), "
            "aborting\n")
        sys.exit(3)

    parse_stamp = datetime.datetime.now().isoformat()
    source_file = os.path.abspath(args.HDR)

    for enum in parsed_h.enums:
        sys.stdout.write(f"Processing '{enum['name']}': ")

        ename = enum['name']
        efilename = f'{ename}.msg'
        edoxy = enum.get('doxygen', '').replace('//!', '').strip()
        etype = cpp_type_to_ros_msg_idl_type(enum['type'])

        # InternalState.msg already exists, and is not auto-generated
        if ename == 'InternalState':
            raise ValueError(
                "Conflict with existing InternalState message, aborting")

        enum_vals = []
        for val in enum['values']:
            enum_vals.append({
                'name':
                to_snake_case(val['name']).upper(),
                'doxy':
                val.get('doxygen', '').replace('///<', '').strip(),
                'val':
                str(val['value']).replace(' ', '').strip(),
                'type':
                etype,
            })

        outputf = f'{msg_dir}/{efilename}'
        print(f"writing {len(enum_vals)} constants to '{outputf}' ..")

        with open(outputf, 'w') as fout:
            tdict = {
                'source_file': source_file,
                'stamp': parse_stamp,
                'enum_name': ename,
                'enum_doxy': edoxy,
            }
            write_msg_file(tdict, enum_vals, fout)

    print(f"Generated {len(parsed_h.enums)} messages")
Exemple #9
0
def parse_and_extract_type_info(code):
    """
    Parse header code and return declared types, used types, and any bases
    """

    used_types = set()
    declared_types = OrderedDict()

    # Use CppHeader to extract
    cppheader = CppHeader(code, argType="string")

    # Collect used types from the code
    used_types = set()

    # Iterate over typedefs and collect types
    for typedef in cppheader.typedefs:
        if "dolfin::" in typedef:
            typedef = typedef.replace("dolfin::", "")

        # Store type information
        declared_types[typedef] = []

    # Iterate over free functions and collect dependant types
    for function in cppheader.functions:

        # Check return type
        if function["rtnType"] != "void":
            used_types.update(strip_templates(function["rtnType"]))

        # Check argument types
        for argument in function["parameters"]:
            used_types.update(strip_templates(argument["type"]))

    # Iterate over classed and collect info
    for class_name, class_repr in cppheader.classes.items():

        # Check if class is private
        if class_repr["parent"] is not None:
            continue

        # Get bases
        bases = set()
        for base in class_repr["inherits"]:
            bases.update(strip_templates(base["class"]))

        # Remove itself from any bases
        bases.difference_update([class_name])

        # Register the class
        declared_types[class_name] = list(bases)

        # Iterate over public properties
        for prop in class_repr["properties"]["public"]:
            used_types.update(strip_templates(prop["type"]))

        # Iterate over methods and collect dependant types
        for method in class_repr["methods"]["public"]+\
                class_repr["methods"]["protected"]:

            # Check return type
            if method["rtnType"] != "void":
                used_types.update(strip_templates(method["rtnType"]))

            # Check argument types
            for argument in method["parameters"]:
                used_types.update(strip_templates(argument["type"]))

        # Remove any self dependencies
        used_types = set(used_type for used_type in used_types
                         if class_name not in used_type)

    return used_types, declared_types
Exemple #10
0
    if (len(sys.argv) < 4):
        print("gen.py output include_directory input files ...")
        exit(1)

    handle = "m"
    fout = sys.argv[1]
    includedir = sys.argv[2]
    fsin = sys.argv[3:]

    out = []
    includes = []

    for fname in fsin:
        includes.append(fname)

        hdr = CppHeader(os.path.join(includedir, fname))
        # note .strip("::"), inconsistent behavior for classes vs enum/func

        for data in hdr.enums:
            ns = data["namespace"].strip("::")  # bug? in parser
            out.append(create_enum_bindigs(data, [ns], handle) + ";")

        for data in hdr.classes.values():
            ns = data["namespace"]
            # workaround: parser does not save debug in same way as for funcs
            data["debug"] = read_line(data["filename"], data["line_number"])

            if "PY_SINGLETON_OBJECT" in data["debug"]:
                out.append(
                    create_singleton_bindings("instance_" + data["name"], data,
                                              [ns], handle, False))
Exemple #11
0
#!/usr/bin/env python
import pprint
import sys

sys.path = ["../"] + sys.path
from CppHeaderParser import CppHeader, CppParseError

try:
    cppHeader = CppHeader("SampleClass.h")
except CppParseError as e:
    print(e)
    sys.exit(1)

print("CppHeaderParser view of %s" % cppHeader)

sampleClass = cppHeader.classes["SampleClass"]
print("Number of public methods %d" % (len(sampleClass["methods"]["public"])))
print("Number of private properties %d" %
      (len(sampleClass["properties"]["private"])))
meth3 = [m for m in sampleClass["methods"]["public"]
         if m["name"] == "meth3"][0]  # get meth3
meth3ParamTypes = [t["type"]
                   for t in meth3["parameters"]]  # get meth3s parameters
print("Parameter Types for public method meth3")
pprint.pprint(meth3ParamTypes)

print("\nReturn type for meth1:")
print(cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"])

print("\nDoxygen for meth2:")
print(cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"])
    file.write(');\n')
    file.write('\tdisable_lib(id);\n')
    file.write('\t//Sanitize data here:\n')
    file.write('\t\n')
    if not ('void' in rtrn_type and '*' not in rtrn_type):
        file.write('\treturn ret;\n')
    file.write('}\n')


sys.path = ["../"] + sys.path
from CppHeaderParser import CppHeader, CppParseError

file_name = sys.argv[1]

try:
    cppHeader = CppHeader(file_name)
except CppParseError as e:
    print(e)
    sys.exit(1)

#print("CppHeaderParser view of %s" % cppHeader)

print("\nFree functions are:")
for func in cppHeader.functions:
    print("name %s" % func["name"])
    print("type  %s" % func["rtnType"])
    #print(" %s" % func["parameters"])
    for param in func["parameters"]:
        print("param name: %s" % param['name'])
        print("param is pointer: %s" % param['pointer'])
        print("param type: %s" % param['type'])
Exemple #13
0
def createSIP(headerFile, sipDir, headerTemplate):
    print("Processing file: ", headerFile)

    def checkRanges(lineNumber):
        for r in skip_ranges:
            if r[0] <= lineNumber <= r[1]:
                return True
        return False

    def createMethods(s, methods, includeConstructors=True):
        for method in methods:
            if method['constructor'] and not includeConstructors: continue

            if checkRanges(method['line_number']):
                print("SKIP:", method['name'], method['line_number'])
                continue

            line = "  "
            if method['virtual']: line += "virtual "
            if method['explicit']: line += "explicit "
            if not (method['constructor'] or method['destructor']):
                rtnType = method['rtnType'].replace('inline ', '')
                line += rtnType
                if not rtnType.endswith('*'): line += ' '
            if method['destructor']: line += '~'
            line += method['name'] + '('

            parameters = []
            for param in method['parameters']:
                param_str = ""
                if param['constant']: param_str += 'const '

                paramType = param['raw_type']
                if paramType.startswith('::'): paramType = paramType[2:]
                param_str += paramType
                if param['pointer']: param_str += " *"
                elif param['reference']: param_str += " &"
                else: param_str += " "
                param_str += param['name']

                if method['constructor'] and 'parent' in param['name'].lower():
                    param_str += " /TransferThis/"

                if 'defaultValue' in param:
                    param_str += ' = ' + param['defaultValue']
                parameters.append(param_str)

            line += ", ".join(parameters)
            line += ")"
            if method['const']: line += " const"

            line += ';\n'
            s.write(line)

        s.write("\n")

    headerFileStr = open(headerFile, 'r').read()

    ### Pre-Parse
    ### This is kind of like Qt's MOC - we're basically removing/replacing
    ### all of Qt's macro's to make the code straight C++.

    headerFileStr = headerFileStr.replace("Qt::UserRole", "32")

    ### We *really* don't need the following
    headerFileStr = headerFileStr.replace('Q_OBJECT', '')
    headerFileStr = headerFileStr.replace('Q_INVOKABLE', '')

    for macro in ('Q_PRIVATE_SLOT', 'Q_PROPERTY', 'Q_ENUMS', 'Q_FLAGS',
                  'Q_DECLARE_PUBLIC'):
        start = headerFileStr.find('{}('.format(macro))
        declarations = []
        while start >= 0:
            end = headerFileStr.find('\n', start) + 1
            declarations.append(headerFileStr[start:end])
            start = headerFileStr.find('{}('.format(macro), end)
        for declaration in declarations:
            headerFileStr = headerFileStr.replace(declaration, '')

    ### Remember which enums are declared via Q_DECLARE_FLAGS for later and then remove
    ### the declaration.
    declare_flags = {}
    start = headerFileStr.find("Q_DECLARE_FLAGS(")
    declarations = []
    while start >= 0:
        end = headerFileStr.find(")", start) + 1
        declarations.append(headerFileStr[start:end])
        declareFlags = headerFileStr[start:end].replace(
            "Q_DECLARE_FLAGS(", '').replace(')', '')
        flags, enum = declareFlags.replace(' ', '').split(',')
        declare_flags[enum] = flags
        start = headerFileStr.find("Q_DECLARE_FLAGS(", end)
    for declaration in declarations:
        headerFileStr = headerFileStr.replace(declaration, '')

    ### Remember which enums have operators declared via Q_DECLARE_OPERATORS_FOR_FLAGS
    ### for later and then remove the declaration.
    declare_operators = {}
    start = headerFileStr.find("Q_DECLARE_OPERATORS_FOR_FLAGS(")
    declarations = []
    while start >= 0:
        end = headerFileStr.find(")", start) + 1
        declarations.append(headerFileStr[start:end])
        declareOperators = headerFileStr[start:end].replace(
            "Q_DECLARE_OPERATORS_FOR_FLAGS(", '').replace(')', '')
        ns, flags = declareOperators.replace(' ', '').strip().split('::')
        for enum, f in declare_flags.items():
            if f == flags: break
        else: raise Exception(ns, flags)
        declare_operators[ns] = enum
        start = headerFileStr.find("Q_DECLARE_OPERATORS_FOR_FLAGS(", end)
    for declaration in declarations:
        headerFileStr = headerFileStr.replace(declaration, '')

    ### Remember which classes are decalred as private via Q_DECLARE_PRIVATE and then
    ### remove the declaration
    declare_private = []
    start = headerFileStr.find("Q_DECLARE_PRIVATE(")
    declarations = []
    while start >= 0:
        end = headerFileStr.find(")", start) + 1
        declarations.append(headerFileStr[start:end])
        declarePrivate = headerFileStr[start:end].replace(
            "Q_DECLARE_PRIVATE(", '').replace(')', '')
        declare_private.append(declarePrivate)
        start = headerFileStr.find("Q_DECLARE_PRIVATE(", end)
    for declaration in declarations:
        headerFileStr = headerFileStr.replace(declaration, '')

    ### Remember which classes have copying disabled via Q_DECLARE_COPY and then
    ### remove the declaration
    disable_copy = []
    start = headerFileStr.find("Q_DISABLE_COPY(")
    declarations = []
    while start >= 0:
        end = headerFileStr.find(")", start) + 1
        declarations.append(headerFileStr[start:end])
        disableCopy = headerFileStr[start:end].replace("Q_DISABLE_COPY(",
                                                       '').replace(')', '')
        disable_copy.append(disableCopy)
        start = headerFileStr.find("Q_DISABLE_COPY(", end)
    for declaration in declarations:
        headerFileStr = headerFileStr.replace(declaration, '')

    ### Read header file as lines rather than single string
    #with open(headerFile, 'r') as f:
    #    headerLines=f.readlines()
    headerLines = headerFileStr.split('\n')

    ### Make a list of export symbols and exported objects...
    exports = []
    export_symbols = []
    for line in headerLines:
        if '_EXPORT' not in line or line.strip().startswith('//'): continue

        pieces = line.strip().replace(":", '').replace('{', '').split(' ')
        assert '_EXPORT' in pieces[1]
        export_symbols.append(pieces[1])
        exports.append(pieces[2])

    ### ... then remove symbols to simplify parsing
    for sym in set(export_symbols):
        headerFileStr = headerFileStr.replace(sym, '')

    ### Parse header
    try:
        cppHeader = CppHeader(headerFileStr, argType="string")
    except CppHeaderParser.CppParseError as e:
        print(e)
        exit(1)

    ### 'Process' pre-processor macros...
    conditionals = cppHeader.conditionals[1:-1]
    _conditionals = []
    for n, line in enumerate(headerLines):
        if not line.strip().startswith(('#if', '#else', '#endif')): continue
        if line.strip() not in conditionals: continue

        try:
            assert line.strip() == conditionals[0]
        except AssertionError:
            print("CONDITIONALS:", n, line.strip(), conditionals)
            print(headerFileStr)
            raise

        _conditionals.append((conditionals.pop(0), n + 1))

    defines = ['USE_QFILEDIALOG_OPTIONS']
    skip = True
    start, stop = None, None
    skip_ranges = []
    for condition, n in _conditionals:
        if condition.startswith('#if'):
            pieces = condition.strip().split()
            cond, name = pieces[:2]

            check = False
            if name == 'QT_VERSION':
                assert len(pieces) >= 4
                operator, version = pieces[2:4]
                assert operator in ('>', '>=', '<', '<=')
                if 'QT_VERSION_CHECK' in version:
                    version = ''.join(pieces[3:])
                    version = version.replace('QT_VERSION_CHECK(',
                                              '').replace(')', '')
                    version = '0x' + ''.join(version.split(',')) + '00'
                check = eval("{}{}{}".format(QT_VERSION, operator, version))

            if (name in defines or check) and cond == '#ifdef': skip = False
            elif (name in defines and cond == '#ifndef'): skip = True
            if skip: start = n

        elif condition.startswith('#else'):
            skip = not skip
            if skip: start = n
            else: stop = n

        elif condition.startswith('#endif'):
            if skip: stop = n
            if not skip: skip = True
        else: raise Exception

        if start and stop:
            skip_ranges.append((start, stop))
            start, stop = None, None

    sipFile = os.path.splitext(os.path.split(headerFile)[1])[0] + '.sip'
    sipFile = os.path.abspath(os.path.join(sipDir, sipFile))
    sipIncludes = []
    exported_objects = []

    s = StringIO()

    ### NAMESPACES
    namespace_funtions = {}
    for function in cppHeader.functions:
        if not len(function['namespace']): continue

        namespace = function['namespace'].replace(':', '')
        namespace_funtions.setdefault(namespace, []).append(function)

    for namespace, functions in namespace_funtions.items():
        print("  namespace: ", namespace)
        s.write('namespace {} {{\n\n'.format(namespace))

        ## TYPEHEADERCODE
        s.write("%TypeHeaderCode\n")
        s.write("#include \"{}\"\n".format(os.path.split(headerFile)[1]))
        s.write("%End\n\n")

        createMethods(s, functions)

        s.write('};\n\n')

    ### CLASSSES
    for className, classObject in cppHeader.classes.items():
        if not className in exports: continue
        exported_objects.append(className)
        print("  object: ", className)

        ## DECLARATION
        declarationMethod = classObject['declaration_method']
        declarationLine = "{} {} ".format(declarationMethod, className)
        inherits = classObject['inherits']
        if len(inherits):
            declarationLine += ": "

            inheritStrings = []
            for inherit in inherits:
                inheritStrings.append(inherit['access'] + " " +
                                      inherit['class'])
                if not inherit['class'].startswith('Q'):
                    sipIncludes.append(inherit['class'])

            declarationLine += ', '.join(inheritStrings)

        declarationLine += " {"
        s.write(declarationLine)
        s.write('\n\n')

        ## TYPEHEADERCODE
        s.write("%TypeHeaderCode\n")
        s.write("#include \"{}\"\n".format(os.path.split(headerFile)[1]))
        s.write("%End\n\n")

        ## PUBLIC
        s.write("public:\n")
        for enum in classObject['enums']['public']:
            if checkRanges(enum['line_number']):
                print("SKIP:", enum.get('name', '[ENUM]'), enum['line_number'])
                continue
            s.write("  enum {} {{\n".format(enum.get('name', '')))
            for value in enum['values']:
                _value = str(value['value'])
                if '+' in _value or '|' in _value:
                    try:
                        _value = eval(_value)
                    except NameError:
                        assert '|' in _value
                        bits = _value.replace(' ', '').split('|')
                        bits_vals = []
                        for v in enum['values']:
                            if v['name'] in bits:
                                bits_vals.append(str(v['value']))
                        _value = eval('|'.join(bits_vals))

                s.write("    {}={},\n".format(value['name'], _value))

            s.write("  };\n")

            if enum.get('name', None) in declare_flags:
                s.write("  typedef QFlags<{0}::{1}> {2};\n".format(
                    className, enum['name'], declare_flags[enum['name']]))
            s.write('\n')

        methods = classObject['methods']['public']
        createMethods(s, methods)

        ## PUBLIC SLOTS
        methods = classObject['methods']['public slots'] + classObject[
            'methods']['public Q_SLOTS']
        if len(methods):
            s.write("public slots:\n")
            createMethods(s, methods)

        ## PROTECTED
        enums = classObject['enums']['protected']
        methods = classObject['methods']['protected']
        if len(methods) or len(enums):
            s.write("protected:\n")

            for enum in enums:
                s.write("  enum {} {{\n".format(enum.get('name', '')))
                for value in enum['values']:
                    _value = str(value['value'])
                    if '+' in _value or '|' in _value:
                        try:
                            _value = eval(_value)
                        except NameError:
                            assert '|' in _value
                            bits = _value.replace(' ', '').split('|')
                            bits_vals = []
                            for v in enum['values']:
                                if v['name'] in bits:
                                    bits_vals.append(str(v['value']))
                            _value = eval('|'.join(bits_vals))

                    s.write("    {}={},\n".format(value['name'], _value))

                s.write("  };\n")

                if enum.get('name', None) in declare_flags:
                    s.write("  typedef QFlags<{0}::{1}> {2};\n".format(
                        className, enum['name'], declare_flags[enum['name']]))
                s.write('\n')

            createMethods(s, methods, includeConstructors=False)

        ## PROTECTED SLOTS
        methods = classObject['methods']['protected slots'] + classObject[
            'methods']['protected Q_SLOTS']
        if len(methods):
            s.write("protected slots:\n")
            createMethods(s, methods)

        ## SIGNALS
        methods = classObject['methods']['signals'] + classObject['methods'][
            'Q_SIGNALS']
        if len(methods):
            s.write("signals:\n")
            createMethods(s, methods)

        if className in declare_private or className in disable_copy:
            s.write("private:\n")
            if className in declare_private:
                s.write('  {0}(const {0} &);\n'.format(className))
            if className in disable_copy:
                s.write('  {0} &operator=(const {0} &);\n'.format(className))

        s.write("\n};\n\n")

    # if len(declare_operators):
    #     for ns,enum in declare_operators.items():
    #         s.write("\nQFlags<{0}::{1}> operator|({0}::{1} f1, QFlags<{0}::{1}> f2);".format(ns,enum))

    s.seek(0)
    sipFileStr = s.read().replace("Qt : : ", "Qt::")
    sipFileStr = sipFileStr.replace(' : : ', '::')
    if not len(sipFileStr) or sipFileStr.isspace(): return

    with open(sipFile, 'w') as ss:
        ss.write(headerTemplate.format(file_name=os.path.split(sipFile)[1]))
        ss.write('\n\n')

        if len(sipIncludes):
            for include in sipIncludes:
                if include in exported_objects: continue
                ss.write('%Include {}.sip\n'.format(include))
            ss.write('\n')

        ss.write(sipFileStr)