pypdfium2-team / ctypesgen

Wrapper generator for Python ctypes
BSD 2-Clause "Simplified" License
1 stars 1 forks source link

ctypesgen (pypdfium2-team fork)

ctypesgen is a ctypes wrapper generator for Python.

This is a fork with the objective to better suit the needs of pypdfium2, and address some of the technical debt and (in our opinion) design issues that have accumulated due to highly conservative maintenance.

Here are some notes on our development intents:

System Dependencies

ctypesgen depends on the presence of an external C pre-processor, by default gcc or clang, as available. Alternatively, you may specify a custom pre-processor command using the --cpp option (e.g. --cpp "clang -E" to always use clang).

Tips & Tricks

Notes on symbol inclusion

Binding against the Python API

cat >"overrides.py" <<END
import ctypes

class PyTypeObject (ctypes.Structure): pass
class PyObject (ctypes.Structure): pass

def POINTER(obj):
    if obj is PyObject: return ctypes.py_object
    return ctypes.POINTER(obj)
END

ctypesgen -l python --dllclass pythonapi --system-headers python3.X/Python.h --all-headers -m .overrides --linkage-anchor . -o ctypes_python.py

substituting 3.X with your system's python version.

Small test:

import sys
from ctypes import *
from ctypes_python import *

# Get a string from a Python C API function
v = Py_GetVersion()
v = cast(v, c_char_p).value.decode("utf-8")
print(v)
print(v == sys.version)  # True

# Convert back and forth between Native vs. C view of an object
class Test:
    def __init__(self, a):
        self.a = a

t = Test(a=123)
tc_ptr = cast(id(t), POINTER(PyObject_))
tc = tc_ptr.contents
print(tc.ob_refcnt)  # 1
Py_IncRef(t)
print(tc.ob_refcnt)  # 2 (incremented)
Py_DecRef(t)
print(tc.ob_refcnt)  # 1 (decremented)
t_back = cast(tc_ptr, py_object).value
print(t_back.a)
print(tc.ob_refcnt)  # 2 (new reference from t_back)

It should yield something like

3.11.6 (main, Oct  3 2023, 00:00:00) [GCC 12.3.1 20230508 (Red Hat 12.3.1-1)]
True
1
2
1
123
2

Known Limitations

ctypes

pypdfium2-ctypesgen

ctypesgen

Fork rationale

Trying to get through changes upstream is tedious, with unclear outcome, and often not applicable due to mismatched intents (e.g. regarding backwards compatibility). Also consider that isolating commits in separate branches is not feasible anymore as merge conflicts arise (e.g. due to code cleanups and interfering changes).

Contrast this to a fork, which allows us to keep focused and effect improvements quickly, so as to invest developer time rationally.

However, we would be glad if our work could eventually be merged back upstream once the change set has matured, if upstream can arrange themselves with the radical changes. See https://github.com/ctypesgen/ctypesgen/issues/195 for discussion.

Syncing with upstream

Last time we had to do this, git merge origin/master -Xours did a good job. Changes to files we haven't really modified can usually just be pulled in as-is. Otherwise, you'll have to manually look through the changes and pick what you consider worthwhile on a case by case basis.

Note, it is important to verify the resulting merge commit for correctness - automatic merge strategies might produce mistakes!

Bugs

Oversights or unintentional breakage can happen at times. Feel free to file a bug report if you think a change introduces logical issues. However, please note our response policy below.

Contributions

We may accept contributions, but only if our code quality expectations are met.

Policy: