add support for freeing C/C++ objects used purely within wrappers
This commit is contained in:
1 parent
adeb7ce557
commit
1ce9a95173
6 files changed
+39
-8
No files matched your search
@@ -640,6 +640,17 @@ case too::
|
||||
Which instructs PyBindGen that DoSomething is not to be trusted and that it should
|
||||
acquire ownership of the returned pointer if it needs to keep track of it.
|
||||
|
||||
A Copied Object or String
|
||||
-------------------------
|
||||
|
||||
Some C/C++ functions, and in particular those generated as bindings to other
|
||||
languages allocate storage in the C/C++ heap purely for transferring data
|
||||
to the python C bindings (consider python calling golang via C wrappers for
|
||||
example). In these cases, there is no language level mechanism to track and free
|
||||
this storage. The 'free_on_copy' parameter can be used to request that the
|
||||
python generated bindings free this storage after Py_BuildValue has been
|
||||
used to take a copy of it. This is most often needed for C strings (char *)
|
||||
but is also available for C++ classes using 'delete' rather than 'free'.
|
||||
|
||||
A STL container
|
||||
---------------
|
||||
|
||||
@@ -3676,11 +3676,14 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
|
||||
|
||||
def __init__(self, ctype, caller_owns_return=None, custodian=None,
|
||||
is_const=False, reference_existing_object=None,
|
||||
return_internal_reference=None, caller_manages_return=True):
|
||||
return_internal_reference=None, caller_manages_return=True, free_after_copy=False):
|
||||
"""
|
||||
:param ctype: C type, normally 'MyClass*'
|
||||
:param caller_owns_return: if true, ownership of the object pointer
|
||||
is transferred to the caller
|
||||
:param free_after_copy: if true, the python wrapper must call free on
|
||||
the returned pointer once it has taken a (shallow)
|
||||
copy of it.
|
||||
|
||||
:param custodian: bind the life cycle of the python wrapper
|
||||
for the return value object (ward) to that
|
||||
@@ -3727,6 +3730,7 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
|
||||
|
||||
self.caller_owns_return = caller_owns_return
|
||||
self.caller_manages_return = caller_manages_return
|
||||
self.free_after_copy = free_after_copy
|
||||
self.reference_existing_object = reference_existing_object
|
||||
self.return_internal_reference = return_internal_reference
|
||||
if self.return_internal_reference:
|
||||
@@ -3769,7 +3773,8 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
|
||||
|
||||
# return the value
|
||||
wrapper.build_params.add_parameter("N", [py_name], prepend=True)
|
||||
|
||||
if self.free_after_copy:
|
||||
wrapper.after_call.add_cleanup_code("delete retval;")
|
||||
|
||||
def convert_python_to_c(self, wrapper):
|
||||
"""See ReturnValue.convert_python_to_c"""
|
||||
|
||||
@@ -1155,6 +1155,7 @@ class _ReturnValue(TypeHandler):
|
||||
args[0] = type_traits
|
||||
args = tuple(args)
|
||||
try:
|
||||
print(type_handler_class)
|
||||
return type_handler_class(*args, **kwargs)
|
||||
except TypeError:
|
||||
ex = sys.exc_info()[1]
|
||||
@@ -1212,9 +1213,10 @@ ReturnValue.CTYPES = NotImplemented
|
||||
class PointerReturnValue(ReturnValue):
|
||||
"""Base class for all pointer-to-something handlers"""
|
||||
CTYPES = []
|
||||
def __init__(self, ctype, is_const=False, caller_owns_return=None):
|
||||
def __init__(self, ctype, is_const=False, caller_owns_return=None, free_after_copy=False):
|
||||
super(PointerReturnValue, self).__init__(ctype, is_const)
|
||||
self.call_owns_return = caller_owns_return
|
||||
self.free_after_copy = free_after_copy
|
||||
|
||||
PointerReturnValue.CTYPES = NotImplemented
|
||||
|
||||
|
||||
@@ -218,6 +218,8 @@ class CStringReturn(PointerReturnValue):
|
||||
|
||||
def convert_c_to_python(self, wrapper):
|
||||
wrapper.build_params.add_parameter("s", [self.value])
|
||||
if self.free_after_copy:
|
||||
wrapper.after_call.add_cleanup_code("free(retval);")
|
||||
|
||||
|
||||
class StdStringReturn(ReturnValue):
|
||||
|
||||
@@ -22,6 +22,7 @@ import os, sys
|
||||
from waflib import Utils, Options, Errors, Logs
|
||||
from waflib.TaskGen import extension, before_method, after_method, feature
|
||||
from waflib.Configure import conf
|
||||
import waflib
|
||||
|
||||
FRAG = '''
|
||||
#include <Python.h>
|
||||
@@ -318,7 +319,7 @@ def check_python_headers(conf):
|
||||
|
||||
includes = []
|
||||
if conf.env.PYTHON_CONFIG:
|
||||
for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG, '--includes']).strip().split():
|
||||
for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG[0], '--includes']).strip().split():
|
||||
# strip the -I or /I
|
||||
if (incstr.startswith('-I') or incstr.startswith('/I')):
|
||||
incstr = incstr[2:]
|
||||
@@ -334,6 +335,7 @@ def check_python_headers(conf):
|
||||
env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
|
||||
env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
|
||||
|
||||
|
||||
# Code using the Python API needs to be compiled with -fno-strict-aliasing
|
||||
if env['CC_NAME'] == 'gcc':
|
||||
env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
|
||||
|
||||
@@ -13,6 +13,8 @@ from waflib import Configure
|
||||
|
||||
from waflib import Logs
|
||||
|
||||
from waflib.Tools import c_config
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
@@ -58,7 +60,7 @@ def zipper(dir, zip_file, archive_main_folder=None):
|
||||
|
||||
def options(opt):
|
||||
opt.load('python_patched', tooldir="waf-tools")
|
||||
opt.load('compiler_cc')
|
||||
opt.load('compiler_c')
|
||||
opt.load('compiler_cxx')
|
||||
opt.load('cflags', tooldir="waf-tools")
|
||||
opt.recurse('examples')
|
||||
@@ -120,12 +122,19 @@ def _check_compilation_flag(conf, flag, mode='cxx', linkflags=None):
|
||||
env.append_value("LINKFLAGS", linkflags)
|
||||
|
||||
try:
|
||||
retval = conf.run_c_code(code='#include <stdio.h>\nint main() { return 0; }\n',
|
||||
env=env, compile_filename=fname,
|
||||
print("HERE")
|
||||
retval = conf.run_build(code='#include <stdio.h>\nint main() { return 0; }\n',
|
||||
env=env, compile_filename=fname,
|
||||
build_fun=c_config.build_fun,
|
||||
features=[mode, mode+'program'], execute=False)
|
||||
print("WRF... ",retval)
|
||||
except conf.errors.ConfigurationError:
|
||||
ok = False
|
||||
except:
|
||||
print(":FAILED")
|
||||
raise
|
||||
else:
|
||||
print(":WORKED")
|
||||
ok = (retval == 0)
|
||||
conf.end_msg(ok)
|
||||
return ok
|
||||
@@ -151,7 +160,7 @@ def configure(conf):
|
||||
conf.check_python_version((2,3))
|
||||
|
||||
try:
|
||||
conf.load('compiler_cc')
|
||||
conf.load('compiler_c')
|
||||
conf.load('compiler_cxx')
|
||||
except conf.errors.ConfigurationError:
|
||||
Logs.warn("C/C++ compiler not detected. Unit tests and examples will not be compiled.")
|
||||
|
||||
Reference in new issue
Block a user