Mercurial > pub > dyncall > bindings
view python/pydc/README.txt @ 66:7a61dd082341 default tip
pydc:
- fix double free triggered by capsule destructor, when freeing pydc and callback objects, manually
author | Tassilo Philipp |
---|---|
date | Fri, 24 May 2024 18:16:29 +0200 |
parents | c5a69c454963 |
children |
line wrap: on
line source
dyncall python bindings Copyright 2007-2016 Daniel Adler 2018-2023 Tassilo Philipp Dec 4, 2007: initial Mar 22, 2016: update to dyncall 0.9, includes breaking sig char changes Apr 19, 2018: update to dyncall 1.0 Apr 7, 2020: update to dyncall 1.1, Python 3 support, using the Capsule API, as well as support for python unicode strings Apr 11, 2020: support for getting loaded library path Apr 12, 2020: breaking change: restrict 'Z' conversions to immutable types and 'p' to mutable types (and handles) Apr 13, 2020: added signature char support to specify calling conventions Oct 27, 2020: allowing 'None' for 'p' params, always passing NULL Nov 13, 2020: removed pydc.py wrapper overhead (which only called pydcext.so functions; implies renaming pydcext.* to pydc.*), added type stub as package_data Jan 23, 2021: update to dyncall 1.2 (only version bump) Feb 2, 2021: added callback support (comes with some bigger refactoring); allow CPython's Py{CObject,Capsule} to be used as 'p'ointers Aug 3, 2022: added p2Z() helper function (e.g. helpful when working with string 'p'ointers that eventually need to be free()'d, as no implicit 'Z' conversion is taking place) Apr 3, 2023: allowing 'None' for 'Z' params BUILD/INSTALLATION ================== 1) make sure dyncall is built and libraries/headers are in include paths or CFLAGS points to them, etc. 2) Build and install this extension with: python setup.py install Building a wheel package isn't supported, currently. API === In a nutshell for all calls: libhandle = load(libpath) # if path == None => handle to running process libpath = get_path(libhandle) # if handle == None => path to executable funcptr = find(libhandle, symbolname) # lookup symbol by name call(funcptr, signature, ...) # call C func w/ signature and corresponding args free(libhandle) # free library For callback objects to be passed as 'p'ointer args: cbhandle = new_callback(signature, pyfunc) # signature reflecting C func ptr free_callback(cbhandle) # release callback object Notes: - a pydc.pyi stub file with the precise interface description is available - there are no functions to set the calling convention mode, however, it can be set using the signature - not specifying any calling convention in the signature string will use the platform's default one SIGNATURE FORMAT ================ ignoring calling convention mode switching for simplicity, the signature is a string with the following format (using * as regex-like repetition): "x*)y" where x is positional parameter-type charcode (per argument), y is result-type charcode SIG | FROM PYTHON 2 | FROM PYTHON 3 | C/C++ | TO PYTHON 2 | TO PYTHON 3 ----+---------------------------------+---------------------------------+---------------------------------+--------------------------------------+--------------------------------------- 'v' | | | void | None (Py_None) (e.g. ret of "...)v") | None (Py_None) (e.g. ret of "...)v") 'B' | bool (PyBool) | bool (PyBool) # | int/bool | bool (PyBool) | bool (PyBool) @ 'c' | int (PyInt) % | int (PyLong) % | char | int (PyInt) | int (PyLong) | str (with only a single char) % | str (with only a single char) % | char | int (PyInt) | int (PyLong) 'C' | int (PyInt) % | int (PyLong) % | unsigned char | int (PyInt) | int (PyLong) | str (with only a single char) % | str (with only a single char) % | unsigned char | int (PyInt) | int (PyLong) 's' | int (PyInt) % | int (PyLong) % | short | int (PyInt) | int (PyLong) 'S' | int (PyInt) % | int (PyLong) % | unsigned short | int (PyInt) | int (PyLong) 'i' | int (PyInt) | int (PyLong) | int | int (PyInt) | int (PyLong) 'I' | int (PyInt) | int (PyLong) | unsigned int | int (PyInt) | int (PyLong) 'j' | int (PyInt) | int (PyLong) | long | int (PyInt) | int (PyLong) 'J' | int (PyInt) | int (PyLong) | unsigned long | int (PyInt) | int (PyLong) 'l' | int (PyInt) | int (PyLongLong) | long long | long (PyLong) | int (PyLong) | long (PyLong) | - | long long | long (PyLong) | int (PyLong) 'L' | int (PyInt) | int (PyLongLong) | unsigned long long | long (PyLong) | int (PyLong) | long (PyLong) | - | unsigned long long | long (PyLong) | int (PyLong) 'f' | float (PyFloat) $ | float (PyFloat) $ | float | float (PyFloat) ^ | float (PyFloat) ^ 'd' | float (PyFloat) | float (PyFloat) | double | float (PyFloat) | float (PyFloat) 'p' | bytearray (PyByteArray) & | bytearray (PyByteArray) & | void* | int,long (Py_ssize_t) | int (Py_ssize_t) | int (PyInt) | int (PyLong) | void* | int,long (Py_ssize_t) | int (Py_ssize_t) | long (PyLong) | - | void* | int,long (Py_ssize_t) | int (Py_ssize_t) | None (Py_None) | None (Py_None) | void* (always NULL) | int,long (Py_ssize_t) | int (Py_ssize_t) | (PyCObject,PyCapsule) | (PyCObject,PyCapsule) | void* | int,long (Py_ssize_t) | int (Py_ssize_t) @@@ test 'Z' | str (PyString) ! | str (PyUnicode) ! | const char* (UTF-8 for unicode) | str (PyString) | str (PyUnicode) | unicode (PyUnicode) ! | - | const char* (UTF-8 for unicode) | str (PyString) | str (PyUnicode) | - | bytes (PyBytes) ! | const char* (UTF-8 for unicode) | str (PyString) | str (PyUnicode) | bytearray (PyByteArray) ! | bytearray (PyByteArray) ! | const char* (UTF-8 for unicode) | str (PyString) | str (PyUnicode) | None (Py_None) | None (Py_None) | const char* (always NULL) | None (Py_None) | None (Py_None) Annotations: # converted to 1 if True and 0 otherwise @ converted to False if 0 and True otherwise % range/length checked $ cast to single precision ^ cast to double precision & mutable buffer when passed to C ! immutable buffer when passed to C, as strings (in any form) are considered objects, not buffers; also, not allowed as return type in callback signatures Also supported are specifying calling convention switches using '_'-prefixed signature characters: SIG | DESCRIPTION ----+----------------------------------------------------------------------------------------------------------- '_' | prefix indicating that next signature character specifies calling convention; char is one of the following ':' | platform's default calling convention '*' | platform's default thiscall (C++ methods) calling convention, first argument of a call is the this pointer 'e' | vararg function '.' | vararg function's variadic/ellipsis part (...), to be specified before first vararg 'c' | only on x86: cdecl 's' | only on x86: stdcall 'F' | only on x86: fastcall (MS) 'f' | only on x86: fastcall (GNU) '+' | only on x86: thiscall (MS) '#' | only on x86: thiscall (GNU) 'A' | only on ARM: ARM mode 'a' | only on ARM: THUMB mode '$' | syscall TODO ==== - calling convention mode handling for callbacks (not sure if ever needed?) - pydoc "man page" - stub location: the pydc-stubs folder isn't picked up by mypy, so I question why this is the suggested way - get into freebsd ports - releasing GIL when calling into C code (*only* when none of the arguments is a mutable buffer, though) - support for new dyncall aggregate-by-value interface BUGS ==== - when using Python 2, the dyncall call vm object is never dcFree'd, as there is no way to call a "freefunc" as introduced with Python 3 module definitions (see PEP 3121 for details)