Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bindings/pyroot/cppjit/cppjit-version.tag
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e0945224e5b84336d570872ea47989457dae9d8e
0f6cc367f2f7f169c6a09ffaa97169230e52b299
3 changes: 2 additions & 1 deletion bindings/pyroot/cppjit/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ This release supports Python 3.12-3.14 and LLVM 21-22.

## Other changes

- ...
- `import cppjit` raises a `RuntimeError` when the C++ standard headers do
not parse, for example on a host without a C++ toolchain.

## Contributors

Expand Down
5 changes: 4 additions & 1 deletion bindings/pyroot/cppjit/python/cppjit/_cpython_cppjit.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ def _preload_backend_library():
libdir = os.path.dirname(os.path.dirname(spec.origin))
lib = ctypes.CDLL(os.path.join(libdir, "libcpyrt.dll"))
if not lib.LoadCppInterOp():
raise RuntimeError("failed to load CppInterOp (LoadCppInterOp returned 0)")
raise RuntimeError(
"cppjit could not initialize its C++ interpreter, see the diagnostic "
"above (LoadCppInterOp failed)"
)
return lib


Expand Down
25 changes: 25 additions & 0 deletions bindings/pyroot/cppjit/python/cppjit/ll.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"free",
"array_new",
"array_delete",
"bind_value",
"signals_as_exception",
"set_signals_as_exception",
"FatalError",
Expand All @@ -46,6 +47,30 @@ def argc():
return len(sys.argv)


def bind_value(type_name, address, dims=None):
"""Read a value of the C++ type `type_name` from `address`.

Hands back the object that cppjit's converters would produce reading the
same memory themselves: a bound proxy for a class type, a Python value
for a builtin. Meant for code that has a type name and an address in hand
but no C++ entity to read them from, such as a framework exposing its own
data description.

`address` is an integer, as returned by `addressof`. If `dims` is given,
it is a non-empty sequence of non-negative integers describing the shape
of an array starting at `address`, and the type name must end in `[]` or
`*` (scalar converters ignore `dims`); a `LowLevelView` of that shape is
returned.

v = ll.bind_value('double', addr) # a float
a = ll.bind_value('double[]', addr, (2, 3)) # a 2x3 view

No lifetime or bounds checking is or can be done: the caller vouches for
the address, the type and the shape.
"""
return cppjit._backend.bind_value(type_name, address, dims)


# import low-level python converters
for _name in ["addressof", "as_cobject", "as_capsule", "as_ctypes", "as_memoryview"]:
try:
Expand Down
4 changes: 2 additions & 2 deletions bindings/pyroot/cppjit/src/cpyrt/API.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ bool cpyrt::Import(const std::string& mod_name) {
Py_INCREF(value);

// collect classes
if (PyClass_Check(value) || PyObject_HasAttr(value, PyStrings::gBases)) {
if (PyType_Check(value) || PyObject_HasAttr(value, PyStrings::gBases)) {
// get full class name (including module)
PyObject* pyClName = PyObject_GetAttr(value, PyStrings::gName);
if (PyErr_Occurred())
Expand All @@ -347,7 +347,7 @@ bool cpyrt::Import(const std::string& mod_name) {
// build full, qualified name
std::string fullname = mod_name;
fullname += ".";
fullname += cpyrt_PyText_AsString(pyClName);
fullname += PyUnicode_AsUTF8(pyClName);

Py_XDECREF(pyClName);
}
Expand Down
5 changes: 2 additions & 3 deletions bindings/pyroot/cppjit/src/cpyrt/CPPClassMethod.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ PyObject* cpyrt::CPPClassMethod::Call(CPPInstance*& self, cpyrt_PyArgs_t args,
//----------------------------------------------------------------------------
PyObject* cpyrt::CPPClassMethod::GetTypeName() {
PyObject* cppname =
cpyrt_PyText_FromString((GetReturnTypeName() + " (*)").c_str());
cpyrt_PyText_AppendAndDel(&cppname,
GetSignature(false /* show_formalargs */));
PyUnicode_FromString((GetReturnTypeName() + " (*)").c_str());
PyUnicode_AppendAndDel(&cppname, GetSignature(false /* show_formalargs */));
return cppname;
}
4 changes: 2 additions & 2 deletions bindings/pyroot/cppjit/src/cpyrt/CPPConstructor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PyObject* cpyrt::CPPConstructor::GetDocString() {
// GetMethod() may return an empty function if this is just a special case
// place holder
const std::string& clName = interop::GetFinalName(this->GetScope());
return cpyrt_PyText_FromFormat(
return PyUnicode_FromFormat(
"%s::%s%s", clName.c_str(), clName.c_str(),
this->GetMethod() ? this->GetSignatureString().c_str() : "()");
}
Expand All @@ -49,7 +49,7 @@ PyObject* cpyrt::CPPConstructor::Reflex(interop::Reflex::RequestId_t request,
format == interop::Reflex::AS_TYPE)
return CreateScopeProxy(this->GetScope());
else if (format == interop::Reflex::AS_STRING)
return cpyrt_PyText_FromString(fn.c_str());
return PyUnicode_FromString(fn.c_str());
}

return PyCallable::Reflex(request, format);
Expand Down
14 changes: 7 additions & 7 deletions bindings/pyroot/cppjit/src/cpyrt/CPPDataMember.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ static PyObject* dm_reflex(CPPDataMember* dm, PyObject* args) {
if (request == interop::Reflex::TYPE) {
if (format == interop::Reflex::OPTIMAL ||
format == interop::Reflex::AS_STRING)
return cpyrt_PyText_FromString(dm->fFullType.c_str());
return PyUnicode_FromString(dm->fFullType.c_str());
} else if (request == interop::Reflex::OFFSET) {
if (format == interop::Reflex::OPTIMAL)
return PyLong_FromLong(dm->fOffset);
Expand Down Expand Up @@ -350,7 +350,7 @@ void cpyrt::CPPDataMember::Set(interop::TCppScope_t scope,
if (fFullType.find("(anonymous)") == std::string::npos &&
fFullType.find("(unnamed)") == std::string::npos) {
// repurpose fDescription for lazy lookup of the enum later
fDescription = cpyrt_PyText_FromString((fFullType + "::" + name).c_str());
fDescription = PyUnicode_FromString((fFullType + "::" + name).c_str());
fFlags |= kIsEnumPrep;
}
type = interop::ResolveType(type);
Expand Down Expand Up @@ -379,14 +379,14 @@ void cpyrt::CPPDataMember::Set(interop::TCppScope_t scope,
fConverter = CreateConverter(type, {(dim_t)dims.size(), dims.data()});

if (!(fFlags & kIsEnumPrep))
fDescription = cpyrt_PyText_FromString(name.c_str());
fDescription = PyUnicode_FromString(name.c_str());
}

//-----------------------------------------------------------------------------
void cpyrt::CPPDataMember::Set(interop::TCppScope_t scope,
const std::string& name, void* address) {
fEnclosingScope = scope;
fDescription = cpyrt_PyText_FromString(name.c_str());
fDescription = PyUnicode_FromString(name.c_str());
fOffset = (intptr_t)address;
fFlags = kIsStaticData | kIsConstData;
fConverter = CreateConverter("internal_enum_type_t");
Expand Down Expand Up @@ -435,16 +435,16 @@ std::string cpyrt::CPPDataMember::GetName() {
if (fFlags & kIsEnumType) {
PyObject* repr = PyObject_Repr(fDescription);
if (repr) {
std::string res = cpyrt_PyText_AsString(repr);
std::string res = PyUnicode_AsUTF8(repr);
Py_DECREF(repr);
return res;
}
PyErr_Clear();
return "<unknown>";
} else if (fFlags & kIsEnumPrep) {
std::string fullName = cpyrt_PyText_AsString(fDescription);
std::string fullName = PyUnicode_AsUTF8(fDescription);
return fullName.substr(fullName.rfind("::") + 2, std::string::npos);
}

return cpyrt_PyText_AsString(fDescription);
return PyUnicode_AsUTF8(fDescription);
}
32 changes: 16 additions & 16 deletions bindings/pyroot/cppjit/src/cpyrt/CPPEnum.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ using namespace cppjit;
//- private helpers ----------------------------------------------------------
static PyObject* pytype_from_enum_type(const std::string& enum_type) {
if (enum_type == "char")
return (PyObject*)&cpyrt_PyText_Type;
return (PyObject*)&PyUnicode_Type;
else if (enum_type == "bool")
return (PyObject*)&PyInt_Type; // can't use PyBool_Type as base
return (PyObject*)&PyLong_Type; // can't use PyBool_Type as base
else if (strstr("long", enum_type.c_str()))
return (PyObject*)&PyLong_Type;
return (PyObject*)&PyInt_Type; // covers most cases
return (PyObject*)&PyLong_Type; // covers most cases
}

//----------------------------------------------------------------------------
Expand All @@ -37,7 +37,7 @@ PyObject* cpyrt::pyval_from_enum(const std::string& enum_type, PyObject* pytype,
char val = (char)llval;
bval = PyUnicode_FromOrdinal((int)val);
} else if (enum_type == "int" || enum_type == "unsigned int")
bval = PyInt_FromLong((long)llval);
bval = PyLong_FromLong((long)llval);
else
bval = PyLong_FromLongLong(llval);

Expand Down Expand Up @@ -82,10 +82,10 @@ static PyObject* enum_repr(PyObject* self) {
if (kls_cppname && obj_cppname && obj_str) {
const std::string resolved =
interop::ResolveEnum(PyLong_AsVoidPtr(kls_scope));
repr = cpyrt_PyText_FromFormat(
"(%s::%s) : (%s) %s", cpyrt_PyText_AsString(kls_cppname),
cpyrt_PyText_AsString(obj_cppname), resolved.c_str(),
cpyrt_PyText_AsString(obj_str));
repr = PyUnicode_FromFormat("(%s::%s) : (%s) %s",
PyUnicode_AsUTF8(kls_cppname),
PyUnicode_AsUTF8(obj_cppname), resolved.c_str(),
PyUnicode_AsUTF8(obj_str));
}
Py_XDECREF(obj_cppname);
Py_XDECREF(kls_cppname);
Expand Down Expand Up @@ -144,7 +144,7 @@ static PyObject* enum_ctype(PyObject* cls, PyObject* args, PyObject* kwds) {
if (!pyres)
PyErr_Clear();

std::string underlying = pyres ? cpyrt_PyText_AsString(pyres) : "int";
std::string underlying = pyres ? PyUnicode_AsUTF8(pyres) : "int";
PyTypeObject* ct = GetCTypesType(underlying);
if (!ct)
return nullptr;
Expand Down Expand Up @@ -185,12 +185,12 @@ cpyrt::CPPEnum* cpyrt::CPPEnum_New(const std::string& name,

// create the __cpp_name__ for templates
PyObject* dct = PyDict_New();
PyObject* pycppname = cpyrt_PyText_FromString(ename.c_str());
PyObject* pycppname = PyUnicode_FromString(ename.c_str());
PyObject* pycppscope = PyLong_FromVoidPtr(etype.data);
PyDict_SetItem(dct, PyStrings::gCppName, pycppname);
PyDict_SetItem(dct, PyStrings::gThisModule, pycppscope);
Py_DECREF(pycppname);
PyObject* pyresolved = cpyrt_PyText_FromString(resolved.c_str());
PyObject* pyresolved = PyUnicode_FromString(resolved.c_str());
PyDict_SetItem(dct, PyStrings::gUnderlying, pyresolved);
Py_DECREF(pyresolved);

Expand All @@ -200,7 +200,7 @@ cpyrt::CPPEnum* cpyrt::CPPEnum_New(const std::string& name,
if (!modname.empty())
modname = "." + modname;
PyObject* pymodname =
cpyrt_PyText_FromString(("cppjit.gbl" + modname).c_str());
PyUnicode_FromString(("cppjit.gbl" + modname).c_str());
PyDict_SetItem(dct, PyStrings::gModule, pymodname);
Py_DECREF(pymodname);

Expand Down Expand Up @@ -228,10 +228,10 @@ cpyrt::CPPEnum* cpyrt::CPPEnum_New(const std::string& name,
break;
}
const std::string& dname = interop::GetFinalName(econstant);
PyObject* pydname = cpyrt_PyText_FromString(dname.c_str());
PyObject* pydname = PyUnicode_FromString(dname.c_str());
PyObject_SetAttr(pyenum, pydname, val);
Py_DECREF(pydname);
PyObject* pydcppname = cpyrt_PyText_FromString(
PyObject* pydcppname = PyUnicode_FromString(
(ename.empty() ? dname : (ename + "::" + dname)).c_str());
PyObject_SetAttr(val, PyStrings::gCppName, pydcppname);
Py_DECREF(pydcppname);
Expand All @@ -255,8 +255,8 @@ cpyrt::CPPEnum* cpyrt::CPPEnum_New(const std::string& name,

} else {
// presumably not a class enum; simply pretend int
Py_INCREF(&PyInt_Type);
pyenum = (PyObject*)&PyInt_Type;
Py_INCREF(&PyLong_Type);
pyenum = (PyObject*)&PyLong_Type;
}

return pyenum;
Expand Down
6 changes: 3 additions & 3 deletions bindings/pyroot/cppjit/src/cpyrt/CPPExcInstance.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static PyObject* ep_new(PyTypeObject* subtype, PyObject* args, PyObject* kwds) {
PyErr_Clear();
if (PyTuple_GET_SIZE(args) == 1) {
PyObject* msg = PyTuple_GET_ITEM(args, 0);
if (cpyrt_PyText_Check(msg)) {
if (PyUnicode_Check(msg)) {
Py_INCREF(msg);
excobj->fTopMessage = msg;
}
Expand Down Expand Up @@ -72,7 +72,7 @@ static PyObject* ep_str(CPPExcInstance* self) {
if (self->fTopMessage) {
Py_INCREF(self->fTopMessage);
PyObject* top = self->fTopMessage;
cpyrt_PyText_Append(&top, what);
PyUnicode_Append(&top, what);
Py_DECREF(what);
what = top;
}
Expand Down Expand Up @@ -218,7 +218,7 @@ PyTypeObject CPPExcInstance_Type = {
(setattrofunc)ep_setattro, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_BASE_EXC_SUBCLASS |
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, // tp_flags
Py_TPFLAGS_HAVE_GC, // tp_flags
(char*)"cppjit exception object proxy (internal)", // tp_doc
(traverseproc)ep_traverse, // tp_traverse
(inquiry)ep_clear, // tp_clear
Expand Down
5 changes: 2 additions & 3 deletions bindings/pyroot/cppjit/src/cpyrt/CPPFunction.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ PyObject* cpyrt::CPPFunction::Call(CPPInstance*& self, cpyrt_PyArgs_t args,
//----------------------------------------------------------------------------
PyObject* cpyrt::CPPFunction::GetTypeName() {
PyObject* cppname =
cpyrt_PyText_FromString((GetReturnTypeName() + " (*)").c_str());
cpyrt_PyText_AppendAndDel(&cppname,
GetSignature(false /* show_formalargs */));
PyUnicode_FromString((GetReturnTypeName() + " (*)").c_str());
PyUnicode_AppendAndDel(&cppname, GetSignature(false /* show_formalargs */));
return cppname;
}

Expand Down
Loading
Loading