Skip to content

Instantly share code, notes, and snippets.

@YashMakan
Forked from katyo/cpp2c.py
Created November 24, 2020 15:13
Show Gist options
  • Save YashMakan/2711746b59b4feddaa64c775bfc29518 to your computer and use it in GitHub Desktop.
Save YashMakan/2711746b59b4feddaa64c775bfc29518 to your computer and use it in GitHub Desktop.
import sys
import os
import re
from optparse import OptionParser
import ConfigParser
try:
import pygccxml
except ImportError:
print "You must instal pygccxml in-order to run this script."
sys.exit(1)
from pygccxml.declarations.cpptypes import *
from pygccxml.declarations.type_traits import *
from pygccxml.declarations.type_traits_classes import *
from pygccxml.declarations.calldef import *
from pygccxml.declarations.calldef_types import *
from pygccxml.declarations.free_calldef import *
from pygccxml.declarations.calldef_members import *
from pygccxml.declarations.class_declaration import ACCESS_TYPES, class_declaration_t
from pygccxml.declarations.typedef import typedef_t
class UnsupportedError(NotImplementedError):
"""Exception for unsupported features."""
pass
DEBUG = False
ARRAY_SIZE_VAR_NAME = 'arr_size'
RET_VAL_ON_EXCEPTION = 'NULL'
GENERATED_FILE_SUFFIX = "_C_Wrapper"
THIS_VAR_NAME = 'class_this'
RET_VAL_CLASS_NAME = 'ptr_ret_val_class'
WAS_EXCEPTION_ARG_NAME = 'ptr_was_exception'
C_BOOL_TYPE_NAME = 'BOOL_C'
C_TRUE_VAL = 'TRUE_C'
C_FALSE_VAL = 'FALSE_C'
# TODO: check whether those vars are in [arg_info.arg_name for arg_info in func_info.func_args_info_list], and if so - add a suffix.
PYGCCXML_DTOR_TOKEN = re.compile(r"._\d+")
PYGCCXML_FUNC_DECL_ARGS = re.compile(r".*\((.*?)\)") # =The last ()'s contents.
OPERATOR_MAP = {
'+': "plus",
'-': "minus",
'*': "multiply",
'/': "divison",
'%': "mod",
'^': "bitwise_xor",
'&': "bitwise_and",
'|': "bitwise_or",
'~': "bitwise_not",
'!': "not",
'=': "assign",
'<': "smaller",
'>': "bigger",
'+=': "plus_assign",
'-=': "minus_assign",
'*=': "multiply_assign",
'/=': "division_assign",
'%=': "mod_assign",
'^=': "bitwise_xor_assign",
'&=': "bitwise_and_assign",
'|=': "bitwise_or_assign",
'<<': "shift_left",
'>>': "shift_right",
'<<=': "shift_left_assign",
'>>=': "shift_right_assign",
'==': "equal",
'!=': "not_assign",
'<=': "smaller_or_equal",
'>=': "bigger_or_equal",
'&&': "and",
'||': "or",
'++': "plus_plus",
'--': "minus_minus",
',': "comma",
'->*': "pointer_redirect",
'->': "redirect",
'()': "function_call",
'[]': "subscript",
'new': "new",
'new []': "new_array",
'delete': "delete",
'delete []': "delete_array"
} # TODO: Check the function_call op.
OPERATORS_LIST_BY_LENGTH = sorted(OPERATOR_MAP.keys(), key=len, reverse=True) # From the longest to the shortest, to check '+=' before '+' (or '=').
# Proxy funcs to shield from possible pygccxml implementation changes:
def is_declarated_type(arg):
"""Returns whether the argument is a declaration type."""
return isinstance(arg, declarated_t)
def is_ellipsis(arg):
"""Returns whether the argument is ellipsis (...)."""
return isinstance(arg, ellipsis_t)
def is_qualifier(arg):
"""Returns whether the argument is a qualifier."""
return isinstance(arg, type_qualifiers_t)
def is_unknown_type(arg):
"""Returns whether the argument is an unknown type."""
return isinstance(arg, unknown_t)
def is_member_function_type(arg):
"""Returns whether the argument is a member function type."""
return isinstance(arg, member_function_type_t)
def is_typedef(arg):
"""Returns whether the argument is a typedef."""
return isinstance(arg, typedef_t)
def get_public_default_ctor(cls):
"""Returns the class public default ctor, or None if one doesn't exist."""
return has_trivial_constructor(cls)
def has_public_dtor(cls):
"""Returns whether the class has a public destructor."""
return has_public_destructor(cls)
def is_abstract_class_declaration(arg):
"""Returns whether arg is a class declaration that is not a typedef - for example: typedef abstract_class_decl typedef_decl"""
#return is_class_declaration(decl) and not is_typedef(decl)
return isinstance(arg, class_declaration_t)
def get_full_name(decl, sub_seq=None):
"""Generates a C++ token's name, including namespaces."""
#if is_abstract_class_declaration(decl):
# ns_name = get_full_name(decl.parent)
# if not ns_name.endswith("::"): # True to every namespace except for the global namespace.
# ns_name += "::"
# return ns_name + decl.declaration.name
full_name = pygccxml.declarations.full_name(decl)
if sub_seq is not None:
for old_token, new_token in sub_seq:
full_name = full_name.replace(old_token, new_token)
return full_name
def get_func_decl_str(func):
"""Return a func declaration string."""
args_str = PYGCCXML_FUNC_DECL_ARGS.match(func.create_decl_string()).group(1).strip()
return "%s(%s)" % (get_full_name(func), args_str)
def python_to_camel_case(decl_str):
"""Python to (Upper-)Camel Case naming convention, e.g.: "func_name" -> "FuncName" """
words = decl_str.split("_")
return "".join([word.capitalize() for word in words])
def strip_global_ns(decl_str):
"""Strip the global namespace ot a C++ declaration string."""
return decl_str.lstrip(':')
def get_c_name(decl, is_full_name=True, c_sub_seq=None):
"""Generates a C token from a C++ token."""
if is_full_name:
cpp_name = get_full_name(decl)
else:
cpp_name = decl.name
c_name = strip_global_ns(cpp_name).replace('::', '_').replace('~', "delete_").replace('>', '_').replace('<', '_').replace(' ', '').replace(',', '_').replace('*', "_ptr_").replace('&', "_ref_")
# The first substitution is for namespaces. The second is for dtors. All others are for templates.
if c_sub_seq is not None:
for old_token, new_token in c_sub_seq:
if old_token: # FIXME:
c_name = c_name.replace(old_token, new_token)
return c_name
def get_class_ptr_name(class_c_name):
"""Generates a class pointer token from its C class token."""
return "PTR_%s" % (class_c_name,)
def get_error_arg_str(is_c99):
"""Returns the type-name string of the error arg."""
if is_c99:
c_bool_type_str = "bool"
else:
c_bool_type_str = C_BOOL_TYPE_NAME
return "%s *%s" % (c_bool_type_str, WAS_EXCEPTION_ARG_NAME)
def get_enum_c_name(enum):
"""Generates a C enum token from a C++ one."""
enum_name = get_c_name(enum)
if enum_name == enum.name: # To prevent enum redifinition in the global scope. unlike typedef redifinition - it causes a compilation error.
enum_name += "_C" # TODO: Can (still) cause redifinition.
return enum_name
def get_header_guard_name(generated_base_file_path):
"""Returns the header guard. for a specific header file name."""
generated_header_file_name = os.path.basename(generated_base_file_path+".h")
return generated_header_file_name.upper().replace('.', '_')
def is_public_concrete_func(member_func):
"""Reurns whether a member function\operator is public and concrete."""
return ((member_func.access_type == ACCESS_TYPES.PUBLIC) and (member_func.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL))
def get_class_by_decl(global_ns, class_decl, is_safe=True):
"""Returns the class for a class declaration."""
try:
return global_ns.class_(get_full_name(class_decl))
except pygccxml.declarations.runtime_errors.multiple_declarations_found_t:
#print(global_ns, get_full_name(class_decl))
#pass
return global_ns.classes(get_full_name(class_decl))[1]
except pygccxml.declarations.runtime_errors.declaration_not_found_t:
if is_safe:
raise UnsupportedError("No concrete class for class declaration %s. Possible reason: template instatiation is missing." % (str(class_decl),))
else:
raise
def exception_handling_str(generate_exception_handling_code, output_str, generate_error_arg, is_c99, is_void_ret_type, ret_type_c_str):
"""Generates exception handling wrapper around an implementation output string, with or without an error argument."""
if not generate_exception_handling_code:
return output_str
if is_void_ret_type:
on_exception_return_str = ""
else:
on_exception_return_str = "\treturn (%s) %s;\n" % (ret_type_c_str, RET_VAL_ON_EXCEPTION)
if is_c99:
c_false_str = "false"
c_true_str = "true"
else:
c_false_str = C_FALSE_VAL
c_true_str = C_TRUE_VAL
error_arg_no_exception_str = ""
error_arg_was_exception_str = ""
if generate_error_arg:
error_arg_no_exception_str = "if((void *)%s != NULL) (*%s) = %s;\n" % (WAS_EXCEPTION_ARG_NAME, WAS_EXCEPTION_ARG_NAME, c_false_str)
error_arg_was_exception_str = "if((void *)%s != NULL) (*%s) = %s;\n" % (WAS_EXCEPTION_ARG_NAME, WAS_EXCEPTION_ARG_NAME, c_true_str)
return """ try {
%s%s
}
catch(...) {
%s\t%s
}""" % (error_arg_no_exception_str, output_str, error_arg_was_exception_str, on_exception_return_str)
class MemoryFile(object):
"""A class to implement a file on the memory."""
MARK_TOKEN = "@@@"
def __init__(self, path):
self.path = path
self.lines = [self.MARK_TOKEN]
def close(self):
"""Closes the memory file."""
self.lines.remove(self.MARK_TOKEN)
out_file = open(self.path, 'w')
out_file.write("\n".join(self.lines))
out_file.close()
def write(self, str):
"""Writes a string to the memory file."""
self.lines.append(str)
def write_at_mark(self, str):
"""Writes a string at the mark position of the memory file."""
self.lines.insert(self.lines.index(self.MARK_TOKEN), str)
def set_mark(self):
"""Set the mark posiion in the memory file."""
self.lines.remove(self.MARK_TOKEN)
self.lines.append(self.MARK_TOKEN)
class BasicOutputClass(object):
"""A class to handle the files output."""
def __init__(self, header_file_path, generate_dl):
self.header_file_path = header_file_path
header_file_name = os.path.basename(header_file_path)
generated_base_file_name = header_file_name[:header_file_name.rindex(".h")]+GENERATED_FILE_SUFFIX
self.generated_base_file_path = os.path.join(os.path.dirname(header_file_path), generated_base_file_name)
self.generate_dl = generate_dl
self.cpp_file = MemoryFile(self.generated_base_file_path+".cpp")
self.h_file = MemoryFile(self.generated_base_file_path+".h")
if generate_dl:
self.def_file = MemoryFile(self.generated_base_file_path+".def")
def close(self):
"""Forces the output file creation."""
self.cpp_file.close()
self.h_file.close()
if self.generate_dl:
self.def_file.close()
def write_to_cpp_file(self, output_str):
"""Write a string in the cpp file."""
self.cpp_file.write(output_str+'\n')
if DEBUG:
print "CPP: %s" % (output_str,)
def write_to_h_file(self, output_str):
"""Write a string in the header file."""
self.h_file.write(output_str+'\n')
if DEBUG:
print "H: %s" % (output_str,)
def write_at_h_file_mark(self, output_str):
"""Write a string in the header file's mark."""
self.h_file.write_at_mark(output_str+'\n')
if DEBUG:
print "H (FRONT): %s" % (output_str,)
def write_to_def_file(self, output_str):
"""Write a string in the def file, if this option is enabled."""
if self.generate_dl:
self.def_file.write(output_str+'\n')
if DEBUG:
print "DEF: %s" % (output_str,)
def mark_h_file_front(self):
"""Mark the start of the header file, where the typedefs would be written."""
self.h_file.set_mark()
class CodeOutputClass(BasicOutputClass):
"""A class to handle the code output."""
def __init__(self, header_file_path, generate_exception_handling_code, generate_dl, is_compact_string, generate_operators, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, is_camel_case):
super(CodeOutputClass, self).__init__(header_file_path, generate_dl)
self.generate_exception_handling_code = generate_exception_handling_code
self.is_compact_string = is_compact_string
self.generate_operators = generate_operators
self.is_assume_copy = is_assume_copy
self.is_assume_assign = is_assume_assign
self.generate_error_arg = generate_error_arg
self.is_verbose = is_verbose
self.is_camel_case = is_camel_case
def __del__(self):
super(CodeOutputClass, self).__del__()
def output_class_typedef(self, cls, global_context, alternate_class_c_ptr_name=None):
"""Outputs a C class representation."""
class_c_name, class_c_ptr_name = global_context.add_class(cls, alternate_class_c_ptr_name)
verbose_str = ""
if self.is_verbose:
verbose_str = "\t/* A C wrapper for class %s */" % (get_full_name(cls),)
self.write_at_h_file_mark("typedef struct _%s *%s;%s" % (class_c_name, class_c_ptr_name, verbose_str))
def output_func(self, func, global_context, is_array_version=False, generate_min_args_ver_only=False):
"""Outputs a function C wrapper."""
func_info = FuncInfo(func, global_context, self.generate_error_arg, generate_min_args_ver_only)
c_func_name = func_info.c_func_name
if (func_info.func_type == func_info.DTOR):
# To fix the pygccxml dtor name of ~._<num> for declarated classes.
c_func_name = PYGCCXML_DTOR_TOKEN.sub(get_c_name(func.parent, False), c_func_name)
for used_def_vals_num in range(func_info.optional_args_num+1): # Variations to handle default values.
func_args_decl_list = [arg_c_str for arg_c_str in func_info.gen_func_args_c_strs()]
func_args = func_args_decl_list[:len(func_args_decl_list)-used_def_vals_num]
if is_array_version and (func_info.func_type == func_info.CTOR):
func_args.append("size_t %s" % (ARRAY_SIZE_VAR_NAME,)) # Needed for new[].
func_args_str = ", ".join(func_args)
func_args_impl_list = []
for arg_info in func_info.func_args_info_list[:len(func_info.func_args_info_list)-used_def_vals_num]:
redirection_str = ""
if arg_info.is_redirected:
redirection_str = "*"
cast_str = ""
if arg_info.cast_str:
cast_str = "(%s)" % (arg_info.cast_str,)
arg_name = arg_info.arg_name
func_args_impl_list.append((redirection_str, cast_str, arg_name))
func_args_impl_str = ", ".join(["%s%s%s" % (redirection_str, cast_str, arg_name) for redirection_str, cast_str, arg_name in func_args_impl_list])
if is_array_version:
c_func_name = "%s_array" % (c_func_name,)
unique_c_func_name = global_context.generate_unique_token(c_func_name)
if self.is_camel_case:
unique_c_func_name = python_to_camel_case(unique_c_func_name)
self.write_to_def_file('\t'+unique_c_func_name)
func_prototype = "%s %s(%s)" % (func_info.ret_type_info.arg_type_c_str, unique_c_func_name , func_args_str)
verbose_str = ""
if self.is_verbose:
verbose_str = "\t/* A C wrapper for func %s */" % (get_func_decl_str(func),)
self.write_to_h_file("%s;%s" % (func_prototype, verbose_str))
self.write_to_cpp_file("%s {" % (func_prototype,))
ret_val_c_str = "%s%s(%s)" % (func_info.class_redirection, func_info.full_name, func_args_impl_str)
output_str = "\t\t"
if (func_info.func_type == func_info.CTOR):
if func_info.is_default_ctor():
ctor_args_str = ""
else:
ctor_args_str = "(%s)" % (func_args_impl_str,)
array_str = ""
if is_array_version:
array_str = "[%s]" % (ARRAY_SIZE_VAR_NAME,)
nothrow_str = ""
if not self.generate_exception_handling_code:
nothrow_str = "(std::nothrow) "
ret_val_c_str = "new %s%s%s%s" % (nothrow_str, func_info.ret_type_info.class_name, ctor_args_str, array_str)
elif (func_info.func_type == func_info.DTOR):
array_str = ""
if is_array_version:
array_str = "[]"
cast_str = "(%s*)" % (global_context.get_full_name(func.parent),)
ret_val_c_str = "delete %s(%s%s)" % (array_str, cast_str, THIS_VAR_NAME)
else:
if (func_info.ret_type_info.is_class) and (func_info.ret_type_info.is_redirected):# and not(func_info.ret_type_info.is_ptr):
# Special case: a class should be returned by value. We'll try to return a pointer to a new instance, if possible.
nothrow_str = ""
if not self.generate_exception_handling_code:
nothrow_str = "(std::nothrow) "
if func_info.ret_type_info.can_create_with_copy_constructor or ((func_info.ret_type_info.can_create_with_copy_constructor is None) and self.is_assume_copy):
ret_val_c_str = "new %s%s(%s)" % (nothrow_str, func_info.ret_type_info.class_name, ret_val_c_str)
elif func_info.ret_type_info.can_create_with_default_constructor or ((func_info.ret_type_info.can_create_with_default_constructor is None) and self.is_assume_assign):
output_str += "%s *%s = new %s%s;\n" % (func_info.ret_type_info.class_name, RET_VAL_CLASS_NAME, nothrow_str, func_info.ret_type_info.class_name)
nothrow_null_check_str = ""
if not self.generate_exception_handling_code:
nothrow_null_check_str = "if((void*)%s != NULL) " % (RET_VAL_CLASS_NAME,)
output_str += "%s*%s = %s;\n" % (nothrow_null_check_str, RET_VAL_CLASS_NAME, ret_val_c_str)
ret_val_c_str = RET_VAL_CLASS_NAME
else:
raise UnsupportedError("Cannot handle a class return value without a public copy ctor or public default ctor an assignment operator in %s" % (func_info.full_name, ))
if func_info.ret_type_info.is_void():
return_str = ""
else:
return_str = "return "
cast_str = ""
if func_info.ret_type_info.cast_str:
cast_str = "(%s)" % (func_info.ret_type_info.arg_type_c_str,)
ref_str = ""
if (func_info.ret_type_info.is_ref and not(func_info.ret_type_info.is_class)):
ref_str = "&"
output_str += "%s%s%s%s;" % (return_str, cast_str, ref_str, ret_val_c_str)
output_str = exception_handling_str(self.generate_exception_handling_code, output_str, self.generate_error_arg, global_context.is_c99, func_info.ret_type_info.is_void(), func_info.ret_type_info.arg_type_c_str)
self.write_to_cpp_file("%s" % (output_str,))
self.write_to_cpp_file( "}")
def output_std_string(self, string_typedef, global_context):
"""Outputs the std::(w)string C wrapper."""
is_wstring, string_class, string_c_ptr_name = global_context.add_std_string(string_typedef)
if self.is_compact_string: # Otherwise, it would be outputed like other classes, recursively, as needed.
self.output_class_typedef(string_class, global_context, string_c_ptr_name)
public_default_ctor = get_public_default_ctor(string_class)
self.output_func(public_default_ctor, global_context)
self.output_func(public_default_ctor, global_context, True)
if is_wstring:
char_str = "wchar_t"
else:
char_str = "char"
char_ptr_str = "const %s *" % (char_str,)
for ctor in string_class.constructors():
if (len(ctor.required_args) == 1) and (char_ptr_str == ctor.required_args[0].decl_type.build_decl_string()):
self.output_func(ctor, global_context, False, True) # Outputs the std::(w)string(char*) ctor. We don't generate the allocator<char_str> optional arg.
break
string_dtor = has_destructor(string_class)
self.output_func(string_dtor, global_context)
self.output_func(string_dtor, global_context, True)
c_str_func = string_class.member_function("c_str")
self.output_func(c_str_func, global_context)
def output_enum(self, enum, global_context):
"""Outputs an enum C version."""
enum_name = get_enum_c_name(enum)
verbose_str = ""
if self.is_verbose:
verbose_str = "\t/* A C wrapper for enum %s */" % (get_full_name(enum),)
self.write_at_h_file_mark("enum %s {" % (enum_name,))
self.write_at_h_file_mark("%s" % (",\n".join(["\t%s=%s" % (global_context.generate_unique_token(key, True), val) for key, val in enum.values]),)) # Needed to handle 2 enums with same keys in different namespaces.
self.write_at_h_file_mark("};%s" % (verbose_str,))
global_context.add_enum(enum)
def output_typedef(self, typedef, global_context):
"""Outputs a typedef C version."""
typedef_info=ArgInfo(typedef.decl_type, global_context, get_c_name(typedef))
if typedef_info.is_c_decl: # There is no support for typedefs that aren't C declerations - they'll be stripped to their raw C-type.
verbose_str = ""
if self.is_verbose:
verbose_str = "\t/* A C wrapper for typedef %s */" % (get_full_name(typedef),)
self.write_at_h_file_mark("typedef %s;%s" % (typedef_info.get_type_name_str(), verbose_str))
global_context.add_typedef(typedef)
# TODO: What about a typedef of an enum?
def output_class_code(self, cls, global_context):
"""Output cls class code."""
for ctor in cls.constructors(allow_empty=True):
if (ctor.access_type == ACCESS_TYPES.PUBLIC):
self.output_func(ctor, global_context)
if has_public_dtor(cls):
dtor = has_destructor(cls)
self.output_func(dtor, global_context)
public_default_ctor = get_public_default_ctor(cls)
if public_default_ctor is not None:
self.output_func(public_default_ctor, global_context, True)
self.output_func(dtor, global_context, True)
for member_func in cls.member_functions(allow_empty=True):
if is_public_concrete_func(member_func):
self.output_func(member_func, global_context)
if self.generate_operators:
for member_op in cls.member_operators(allow_empty=True):
if is_public_concrete_func(member_op):
self.output_func(member_op, global_context)
def output_prefix_code(self, is_c99):
"""Output the prefix code (includes, base typedefs, etc.)."""
header_file_name = os.path.basename(self.header_file_path)
generated_header_file_name = os.path.basename(self.generated_base_file_path+".h")
generated_base_file_name = os.path.basename(self.generated_base_file_path)
self.write_to_cpp_file("""#include "%s" """ % (header_file_name,))
self.write_to_cpp_file("""#include "%s" """ % (generated_header_file_name,))
self.write_to_def_file("""LIBRARY "%s"
EXPORTS""" % (generated_base_file_name,))
header_guard = get_header_guard_name(self.generated_base_file_path)
self.write_to_h_file("#ifndef %s" % (header_guard,))
self.write_to_h_file("#define %s" % (header_guard,))
self.write_to_h_file("""#ifdef __cplusplus
extern "C" {
#endif""")
if not is_c99:
self.write_to_h_file("#define %s 0" % (C_FALSE_VAL,))
self.write_to_h_file("#define %s 1" % (C_TRUE_VAL,))
self.write_to_h_file("typedef unsigned char %s;" % (C_BOOL_TYPE_NAME,))
self.mark_h_file_front()
if self.generate_dl:
self.write_to_cpp_file("""#ifdef WIN32
#include <Windows.h>
extern "C" BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
#endif // WIN32""")
def output_suffix_code(self):
"""Output the suffix code (header protectors, etc.)."""
self.write_to_h_file("""#ifdef __cplusplus
}
#endif /* __cplusplus */""")
generated_header_file_name = os.path.basename(self.generated_base_file_path+".h")
self.write_to_h_file("#endif /* %s */" % (get_header_guard_name(self.generated_base_file_path),))
class CodeContext(object):
"""The code context (classes, typdefs, etc.) of the parsed header files."""
CLASS = 0
TYPEDEF = 1
ENUM = 2
def __init__(self, header_file_path, gccxml_file_path, compiler_type, is_c99):
generator_path, generator_name = pygccxml.utils.find_xml_generator()
#config = pygccxml.parser.config_t(gccxml_path=gccxml_file_path, compiler=compiler_type)
config = pygccxml.parser.xml_generator_configuration_t(
gccxml_path=gccxml_file_path, compiler=compiler_type,
xml_generator=generator_name, xml_generator_path=generator_path,
include_paths=["/usr/include", "/usr/include/opencascade"])
#config = pygccxml.parser.xml_generator_configuration_t(
# xml_generator_path=gccxml_file_path,
# xml_generator=compiler_type or "gccxml")
decls = pygccxml.parser.parse([header_file_path], config)
self.global_ns = pygccxml.declarations.get_global_namespace(decls)
self.is_c99 = is_c99
self.class_c_ptrs_map = {}
self.token_freqs = {}
self.typedefs_map = {}
self.std_wstring_c_name = None
self.std_string_c_name = None
self.recursive_classes = []
self.recursive_typedefs = []
self.recursive_enums = []
self.enums_map = {}
def __getattr__(self, attr_name):
""" CodeContext becomes a proxy to the global namespace attributes."""
return getattr(self.global_ns, attr_name)
def generate_unique_token(self, c_func_name, always_add_suffix=False):
"""Generates a unique C token."""
# TODO: Use the args types instead, perhaps.
if c_func_name in self.token_freqs:
self.token_freqs[c_func_name] += 1
return "%s%d" % (c_func_name, self.token_freqs[c_func_name])
else:
self.token_freqs[c_func_name] = 1
if always_add_suffix:
return "%s%d" % (c_func_name, self.token_freqs[c_func_name])
else:
return c_func_name
def add_class(self, cls, alternate_class_c_ptr_name=None):
"""Add cls to the code context."""
class_c_name = self.get_c_name(cls)
if alternate_class_c_ptr_name is None:
class_c_ptr_name = get_class_ptr_name(class_c_name)
else:
class_c_ptr_name = alternate_class_c_ptr_name
self.class_c_ptrs_map[self.get_full_name(cls)] = class_c_ptr_name
return (class_c_name, class_c_ptr_name)
def add_typedef(self, typedef):
"""Add typedef to the code context."""
self.typedefs_map[get_full_name(typedef)] = get_c_name(typedef)
def add_enum(self, enum):
"""Add an enum to the code context."""
self.enums_map[get_full_name(enum)] = get_enum_c_name(enum)
def get_class_data(self, cls):
"""Get the class data for cls from the code context."""
class_name = self.get_full_name(cls)
if class_name not in self.class_c_ptrs_map:
self.add_class(cls)
if is_abstract_class_declaration(cls):
cls = get_class_by_decl(self.global_ns, cls)
if cls is not None:
self.recursive_classes.append(cls)
return (class_name, self.class_c_ptrs_map[class_name])
def get_typedef_data(self, typedef):
"""Get the data for typedef from the code context."""
typedef_name = get_full_name(typedef)
if typedef_name not in self.typedefs_map:
self.add_typedef(typedef)
self.recursive_typedefs.append(typedef)
return (typedef_name, self.typedefs_map[typedef_name])
def get_enum_data(self, enum):
"""Get the data for enum from the code context."""
enum_name = get_full_name(enum)
if enum_name not in self.enums_map:
self.add_enum(enum)
self.recursive_enums.append(enum)
return (enum_name, self.enums_map[enum_name])
def add_std_string(self, string_typedef):
"""Add std::(w)string to the code context."""
string_class = get_class_by_decl(self.global_ns, string_typedef.decl_type.declaration, False)
string_name = string_typedef.name
is_wstring = ("wstring" in string_name)
if is_wstring:
self.wstring_ctor_name = get_public_default_ctor(string_class).name
self.std_wstring_c_name = get_c_name(string_class)
self.std_wstring_typedef_c_name = get_c_name(string_typedef)
self.wstring_name = string_name
self.wstring_full_name = get_full_name(string_class)
self.wstring_full_typedef_name = get_full_name(string_typedef)
string_c_ptr_name=get_class_ptr_name(self.std_wstring_typedef_c_name) # We replace the ptr of the class with that of the typedef - more readable.
else:
self.string_ctor_name = get_public_default_ctor(string_class).name
self.std_string_c_name = get_c_name(string_class)
self.std_string_typedef_c_name = get_c_name(string_typedef)
self.string_name = string_name
self.string_full_name = get_full_name(string_class)
self.string_full_typedef_name = get_full_name(string_typedef)
string_c_ptr_name=get_class_ptr_name(self.std_string_typedef_c_name) # We replace the ptr of the class with that of the typedef - more readable.
self.add_typedef(string_typedef)
return (is_wstring, string_class, string_c_ptr_name)
def gen_recursive_elems(self):
"""Generates the elements gathered recursively that needs to be outputed."""
while self.recursive_classes or self.recursive_typedefs or self.recursive_enums:
# Not a for loop - since classes may get into self.recursive_classes during this loop (e.g.: std::string::allocator inside std::string methods). The same is true for typedefs.
if self.recursive_enums:
yield (self.ENUM, self.recursive_enums.pop(0))
elif self.recursive_typedefs:
yield (self.TYPEDEF, self.recursive_typedefs.pop(0))
elif self.recursive_classes:
yield (self.CLASS, self.recursive_classes.pop(0))
def gen_sub_seq(self):
"""Generates a substitution sequence for C++ tokens."""
if self.std_wstring_c_name is not None:
yield (self.wstring_full_name, self.wstring_full_typedef_name) # Make the std::wstring declerations more readable.
if self.std_string_c_name is not None:
yield (self.string_full_name, self.string_full_typedef_name) # Make the std::wstring declerations more readable.
def gen_c_sub_seq(self):
"""Generates a substitution sequence for C tokens."""
if self.std_wstring_c_name is not None:
yield (self.std_wstring_c_name, self.std_wstring_typedef_c_name) # Make the std::wstring declerations more readable.
yield (self.wstring_ctor_name, self.wstring_name) # Replace basic_string() with wstring().
if self.std_string_c_name is not None:
yield (self.std_string_c_name, self.std_string_typedef_c_name) # Make the std::string declerations more readable.
yield (self.string_ctor_name, self.string_name) # Replace basic_string() with string().
def get_full_name(self, decl):
""" Returns decl full name in the current code context."""
return get_full_name(decl, self.gen_sub_seq())
def get_c_name(self, decl):
""" Returns decl C-name in the current code context."""
return get_c_name(decl, True, self.gen_c_sub_seq())
class ArgInfo(object):
"""A class to parse a func argument."""
def __init__(self, arg_type, global_context, arg_name=""):
self.class_name = None
self.is_const = False
self.is_ref = False
self.is_class = False
self.arg_type_c_str = None
self.is_ptr = False
self.is_enum = False
self.is_typedef = False
self.arg_type = arg_type
self.arg_name = arg_name
self.cast_str = ""
self.is_func_ptr = False
ptrs_list=[]
if "std::_Aux_cont" in str(arg_type):
# Handle special case for MSVSC 2008, for example, when trying to instantiate vector<int>.
# TODO: Handle the special case in a generic way.
raise UnsupportedError("No support for std::_Aux_cont in: %s" % (str(arg_type),))
curr_arg = arg_type
while not(is_fundamental(curr_arg)) or is_typedef(curr_arg) or is_declarated_type(curr_arg) or is_enum(curr_arg):
if is_abstract_class_declaration(curr_arg):
self.is_class = True
cls = get_class_by_decl(global_context.global_ns, curr_arg)
break
elif is_typedef(curr_arg):
self.is_typedef = True
typedef_name, typedef_c_name = global_context.get_typedef_data(curr_arg)
curr_arg = curr_arg.decl_type # Don't use remove_alias() since this deletes ALL the typedefs - and we don't want that.
#TODO: Is this good to classes, either?
elif is_declarated_type(curr_arg):
#curr_arg_decl_str = curr_arg.build_decl_string()
#if pygccxml.declarations.templates.is_instantiation(curr_arg_decl_str) and not(is_std_string(curr_arg) or is_std_wstring(curr_arg)):
# raise UnsupportedError("Currently templates are not supported.")
# TODO: Check STL contains, for example vector.
#self.is_typedef, typedef_name, typedef_c_name = global_context.get_possible_typedef_data(curr_arg)
curr_arg = curr_arg.declaration # And not remove_declarated(curr_arg) - since this would break a typedef completely, etc.
elif is_const(curr_arg):
self.is_const = True
curr_arg = remove_const(curr_arg)
elif is_ellipsis(curr_arg):
raise UnsupportedError("Ellipsis arg types are not handeled.")
elif is_qualifier(curr_arg):
curr_arg = base_type(curr_arg) # TODO: Is this correct?
elif is_unknown_type(curr_arg):
raise UnsupportedError("Unknown arg type: %s" % (str(curr_arg),))
elif is_volatile(curr_arg):
curr_arg = remove_volatile(curr_arg) # Not being dealt.
elif is_calldef_pointer(curr_arg):
curr_arg = curr_arg.base # remove_pointer() doesn't work here.
if is_member_function_type(curr_arg):
raise UnsupportedError("Member function pointers are not supported: %s" % (str(arg_type),))
self.is_func_ptr = True
self.func_ptr_info = FuncPtrInfo(curr_arg, arg_name, global_context)
break
elif is_pointer(curr_arg) or is_array(curr_arg):
ptrs_list.append(self.is_const)
self.is_const = False
curr_arg = remove_pointer(curr_arg)
elif is_reference(curr_arg):
self.is_ref = True # Only the 1st ref is handeled
curr_arg = remove_reference(curr_arg)
elif is_enum(curr_arg):
self.is_enum = True
break
elif is_class(curr_arg):
self.is_class = True
cls = curr_arg
break
self.is_c_bool = is_bool(curr_arg) and not global_context.is_c99 # This is redundent if the compiler is C99 compatible.
self.is_c_decl = not(self.is_class or self.is_ref or self.is_c_bool) #= A simple C decleration.
self.is_redirected = (self.is_class or self.is_ref)
if self.is_c_decl:
self.arg_type_c_str = strip_global_ns(arg_type.build_decl_string())
if self.is_typedef:
stripped_typedef_name = strip_global_ns(typedef_name)
if typedef_c_name != stripped_typedef_name: # There is a namespace
self.cast_str = self.arg_type_c_str
self.arg_type_c_str = self.arg_type_c_str.replace(typedef_name, typedef_c_name)
# The following line is needed to handle the case where arg_type.build_decl_string() is a typedef -> we've stripped the global namespace, and the type won't be replaced with the last line.
self.arg_type_c_str = self.arg_type_c_str.replace(stripped_typedef_name, typedef_c_name)
elif self.is_enum:
self.cast_str = self.arg_type_c_str
enum_name, enum_c_name = global_context.get_enum_data(curr_arg)
if "enum " not in enum_c_name: # C++ style's enum
enum_c_name = "enum %s" % (enum_c_name,)
self.arg_type_c_str = self.arg_type_c_str.replace(strip_global_ns(get_full_name(curr_arg)), enum_c_name)
else:
if self.is_class:
if cls is not None:
self.can_create_with_copy_constructor = has_copy_constructor(cls)
self.can_create_with_default_constructor = (has_public_assign(cls) and has_trivial_constructor(cls))
self.class_name, base_arg_type_c_str = global_context.get_class_data(cls)
else: # For class declaration with no concrete classes.
self.can_create_with_copy_constructor = None
self.can_create_with_default_constructor = None
self.class_name, base_arg_type_c_str = global_context.get_class_data(curr_arg)
if len(ptrs_list) > 0:
if ptrs_list.pop(): # The class ptr covers 1 redirection level...
base_arg_type_c_str = "const " + base_arg_type_c_str #...but we shouldn't forget the const correctness for the ptr we've just removed.
self.is_redirected = False
else:
base_arg_type_c_str = strip_global_ns(curr_arg.build_decl_string())
if self.is_ref: # The (is_class and is_ref) case is dealt in the is_class case.
ptrs_list.append(True) # We add a const indirection. Notice that self.is_const is about the contents - not about the ptr.
curr_ptrs_list = []
for is_ptr_const in reversed(ptrs_list): # reversed - since ptrs are read from right-to-left.
if is_ptr_const:
curr_ptrs_list.append('* const')
else:
curr_ptrs_list.append('*')
ptrs_str = ''.join(curr_ptrs_list)
const_content_str = ""
if self.is_const:
const_content_str = "const "
self.arg_type_c_str = "%s%s%s" % (const_content_str, base_arg_type_c_str, ptrs_str)
if self.is_class:
self.cast_str = self.arg_type_c_str.replace(global_context.get_class_data(curr_arg)[1], self.class_name+'*')
if self.is_c_bool:
self.cast_str = self.arg_type_c_str
self.arg_type_c_str = self.arg_type_c_str.replace("bool", C_BOOL_TYPE_NAME)
if self.is_func_ptr and not(self.is_typedef): # TODO: Is this position covers all bases?
self.arg_type_c_str = self.func_ptr_info.type_str
if len(ptrs_list) > 0:
self.is_ptr = True
def is_void(self):
"""Returns whether the argument is void."""
return is_void(self.arg_type)
def get_type_name_str(self):
"""Returns the type and name argument string."""
if self.is_func_ptr and not(self.is_typedef): # TODO: What about if the typedef is stripped down?
return self.arg_type_c_str.replace("(*)", "(*%s)" % (self.arg_name,))
return "%s %s" % (self.arg_type_c_str, self.arg_name)
class FuncPtrInfo:
"""A class to parse a function pointer."""
def __init__(self, func_type, name, global_context):
self.func_args_info_list = []
self.func_type = func_type
self.name = name
for arg in func_type.arguments_types:
self.func_args_info_list.append(ArgInfo(arg, global_context))
self.ret_type_info = ArgInfo(func_type.return_type, global_context)
func_args_decl_list = [arg_info.arg_type_c_str for arg_info in self.func_args_info_list]
func_args_str = ", ".join(func_args_decl_list)
self.type_str = "%s (*%s)(%s)" % (self.ret_type_info.arg_type_c_str, name, func_args_str)
class FuncInfo:
"""A class to parse a function or a class method."""
FREE_FUNC = 0
FREE_OP = 1
MEMBER_FUNC = 2
MEMBER_OP = 3
CTOR = 4
DTOR = 5
FUNC_TYPE_MAP = {free_function_t: FREE_FUNC,
free_operator_t: FREE_OP,
member_function_t: MEMBER_FUNC,
member_operator_t: MEMBER_OP,
constructor_t: CTOR,
destructor_t: DTOR}
def __init__(self, func, global_context, generate_error_arg, generate_min_args_ver_only=False):
if func.has_ellipsis:
raise UnsupportedError("Ellipsis arg types are not handeled.")
self.func_args_info_list = []
self.func = func
self.full_name = global_context.get_full_name(func)
self.c_func_name = global_context.get_c_name(func)
self.func_type = self.FUNC_TYPE_MAP[type(func)]
if (self.func_type == self.MEMBER_OP) or (self.func_type == self.FREE_OP):
if not("operator_" in self.c_func_name):
# Fix missing space in the func name ("operator+" -> "operator_+").
self.c_func_name = self.c_func_name.replace("operator", "operator_")
for op_name in OPERATORS_LIST_BY_LENGTH:
self.c_func_name = self.c_func_name.replace(op_name, OPERATOR_MAP[op_name])
self.generate_error_arg = generate_error_arg
self.is_c99 = global_context.is_c99
if generate_min_args_ver_only:
self.optional_args_num = 0
else:
self.optional_args_num = len(func.optional_args) # There are always len(func.optional_args) optional arguments, but we don't want to use them when we generate_min_args_ver_only.
if generate_min_args_ver_only:
arguments = func.required_args
else:
arguments = func.arguments
for arg in arguments:
self.func_args_info_list.append(ArgInfo(arg.decl_type, global_context, arg.name))
self.class_redirection = ""
if (self.func_type == self.MEMBER_FUNC) or (self.func_type == self.DTOR) or (self.func_type == self.MEMBER_OP):
self.class_name, class_c_ptr = global_context.get_class_data(func.parent)
self.class_arg_c_str = "%s %s" % (class_c_ptr, THIS_VAR_NAME)
if (self.func_type == self.MEMBER_FUNC) or (self.func_type == self.MEMBER_OP):
self.is_static = func.has_static
if self.is_static:
self.c_func_name += "_static"
self.class_redirection = ""
const_class_redirection_str = ""
if func.has_const:
self.class_arg_c_str = "const " + self.class_arg_c_str
self.c_func_name += "_const"
const_class_redirection_str = "const "
if not self.is_static:
self.class_redirection = "((%s%s*) %s)->" % (const_class_redirection_str, self.class_name, THIS_VAR_NAME,)
if self.func_type == self.CTOR:
self.ret_type_info = ArgInfo(func.parent, global_context)
# TODO: The ctor returns a ptr to the class. Here we put the class_t and not pointer_t(class_t) - since it messes-up the ArgInfo's ctor.
# The reason it works is that handling class and class-ptr is the same - but depending on it is very bad.
elif (self.func_type == self.DTOR):
self.ret_type_info = ArgInfo(void_t(), global_context)
else:
self.ret_type_info = ArgInfo(func.return_type, global_context)
def gen_func_args_c_strs(self):
"""A generator to the func args types and names."""
if self.generate_error_arg:
yield get_error_arg_str(self.is_c99)
if (self.func_type == self.DTOR) or (self.func_type == self.MEMBER_OP) or ((self.func_type == self.MEMBER_FUNC) and not self.is_static):
yield self.class_arg_c_str
for arg_info in self.func_args_info_list:
yield arg_info.get_type_name_str()
def is_default_ctor(self):
"""Returns whether the func is a default ctor."""
if self.func_type == self.CTOR:
return is_trivial_constructor(self.func)
return False
def unsupported_wrapper(func, ignore_unsupported_features=True):
"""A decorator to ignore unsupported features exception, if enabled."""
def decorated(*args, **kws):
try:
func(*args, **kws)
except UnsupportedError, ex:
if ignore_unsupported_features:
print ex.args[0]
else:
raise
return decorated
def generate_c_wrapper(header_file_path, generate_dl=True, generate_exception_handling_code=True, is_compact_string=True, is_assume_copy=False, is_assume_assign=False, generate_error_arg=True, is_verbose=False, generate_operators=True, ignore_unsupported_features=True, is_c99=False, is_camel_case=False, gccxml_file_path = '', compiler_type = None):
"""Outputs a C wrapper for header_file_path."""
if generate_error_arg and not(generate_exception_handling_code):
print "Ignoring error argument generation option, since the exception handling generation option is disabled"
generate_error_arg = False
header_file_path=os.path.abspath(header_file_path)
output_class = CodeOutputClass(header_file_path, generate_exception_handling_code, generate_dl, is_compact_string, generate_operators, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, is_camel_case)
global_context = CodeContext(header_file_path, gccxml_file_path, compiler_type, is_c99)
output_class.output_prefix_code(global_context.is_c99)
output_class.output_typedef=unsupported_wrapper(output_class.output_typedef, ignore_unsupported_features)
output_class.output_func=unsupported_wrapper(output_class.output_func, ignore_unsupported_features)
try:
string_typedef = global_context.typedef(name="::std::string")
output_class.output_std_string(string_typedef, global_context)
string_typedef = global_context.typedef(name="::std::wstring")
output_class.output_std_string(string_typedef, global_context)
except pygccxml.declarations.runtime_errors.declaration_not_found_t:
pass
for cls in global_context.classes(header_file=header_file_path, allow_empty=True):
output_class.output_class_typedef(cls, global_context)
for typedef in global_context.typedefs(header_file=header_file_path, allow_empty=True):
output_class.output_typedef(typedef, global_context)
for enum in global_context.enumerations(header_file=header_file_path, allow_empty=True):
output_class.output_enum(enum, global_context)
for cls in global_context.classes(header_file=header_file_path, allow_empty=True):
output_class.output_class_code(cls, global_context)
for free_func in global_context.free_functions(header_file=header_file_path, allow_empty=True):
output_class.output_func(free_func, global_context)
if output_class.generate_operators:
for free_op in global_context.free_operators(header_file=header_file_path, allow_empty=True):
output_class.output_func(free_op, global_context)
for elem_type, elem in global_context.gen_recursive_elems():
if elem_type == global_context.CLASS:
output_class.output_class_typedef(elem, global_context)
output_class.output_class_code(elem, global_context)
elif elem_type == global_context.TYPEDEF:
output_class.output_typedef(elem, global_context)
elif elem_type == global_context.ENUM:
output_class.output_enum(elem, global_context)
output_class.output_suffix_code()
output_class.close() # Forces the output file creation.
def safe_config_get_wrapper(config_get_func):
"""A decorator to mask ConfigParser methods from option not existing exception, returning a default value instead."""
def decorated(section_name, key_name, def_val=None):
try:
return config_get_func(section_name, key_name)
except ConfigParser.NoOptionError:
return def_val
return decorated
def get_option(options, option, def_val):
"""Returns a default value (other than None) when an optparse var option does not exist."""
ret_val = getattr(options, option)
if ret_val is None:
return def_val
return ret_val
def parse_option(config_get_func, section_name, option_name, options, def_val):
"""Parses one program option. The args parsing order is:
1. Command line args.
2. Config file options.
3. Default values."""
option = def_val
if config_get_func is not None:
option = config_get_func(section_name, option_name, def_val)
return get_option(options, option_name, option)
if __name__ == '__main__':
cmd_line_parser = OptionParser("usage: %prog [options] <header_file_path>")
cmd_line_parser.add_option("-g", "--gccxml", dest='gccxml_file_path', help="The gccxml file path")
cmd_line_parser.add_option("-c", "--config", dest='config_file_path', help="The config file path")
cmd_line_parser.add_option("-t", "--compiler", dest='compiler_type', help="The compiler type")
cmd_line_parser.add_option("-i", "--ignore", action='store_false', dest='ignore_unsupported_features', help="Raise exception if an unsupported feature (like templates) is encountered.")
cmd_line_parser.add_option("-d", "--dl", action='store_false', dest='generate_dl', help="Don't generate a def file (and a DllMain() function under Windows).")
cmd_line_parser.add_option("-e", "--error", action='store_false', dest='generate_error_arg', help="Don't add error output args.")
cmd_line_parser.add_option("-n", "--nothrow", action='store_false', dest='generate_exception_handling_code', help="Don't generate exception handling code.")
cmd_line_parser.add_option("-v", "--verbose", action='store_false', dest='is_verbose', help="Don'e generate verbose output.")
cmd_line_parser.add_option("-9", "--c99", action='store_true', dest='is_c99', help="Compiler with C99 support.")
cmd_line_parser.add_option("-o", "--operator", action='store_false', dest='generate_operators', help="Don't generate operators.")
cmd_line_parser.add_option("-s", "--string", action='store_false', dest='is_compact_string', help="Output std::string in a compact format.")
cmd_line_parser.add_option("--camel", action='store_true', dest='is_camel_case', help="The functions would be outputed in (Upper) Camel Case conventions, not Python conventions (e.g.: FuncName and not func_name).")
cmd_line_parser.add_option("--copy", action='store_true', dest='is_assume_copy', help="Assume public copy constructor for class declarations with no concrete classes.")
cmd_line_parser.add_option("--assign", action='store_true', dest='is_assume_assign', help="Assume public default constructor and assignment operator for class delarations with no concrete classes.")
(options, args) = cmd_line_parser.parse_args()
if len(args) != 1:
cmd_line_parser.error("<header_file_path> is required")
safe_config_get = None
safe_config_get_bool = None
if options.config_file_path is not None:
config = ConfigParser.RawConfigParser()
config.read(options.config_file_path)
safe_config_get = safe_config_get_wrapper(config.get)
safe_config_get_bool = safe_config_get_wrapper(config.getboolean)
generate_dl = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_dl', options, True)
generate_error_arg = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_error_arg', options, True)
ignore_unsupported_features = parse_option(safe_config_get_bool, 'Cpp2C Config', 'ignore_unsupported_features', options, True)
generate_exception_handling_code = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_exception_handling_code', options, True)
gccxml_file_path = parse_option(safe_config_get, 'GccXml Config', 'gccxml_file_path', options, "")
compiler_type = parse_option(safe_config_get, 'GccXml Config', 'compiler_type', options, None)
is_verbose = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_verbose', options, True)
is_c99 = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_c99', options, False)
generate_operators = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_operators', options, True)
is_compact_string = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_compact_string', options, True)
is_camel_case = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_camel_case', options, False)
is_assume_copy = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_assume_copy', options, False)
is_assume_assign = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_assume_assign', options, False)
generate_c_wrapper(args[0], generate_dl, generate_exception_handling_code, is_compact_string, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, generate_operators, ignore_unsupported_features, is_c99, is_camel_case, gccxml_file_path, compiler_type)
print "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment