Skip to content

Commit

Permalink
Merge pull request #321 from mattip/cpp
Browse files Browse the repository at this point in the history
Add CPlusPlus support
  • Loading branch information
Omer Katz authored May 17, 2022
2 parents f941e8f + c64b6e8 commit 02a4f7e
Show file tree
Hide file tree
Showing 16 changed files with 89 additions and 57 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@ on: [pull_request]

jobs:
main_tests:
name: Main tests
name: Main tests ${{ matrix.os }} ${{ matrix.python-version }} ${{ matrix.compiler }}
runs-on: ${{ matrix.os }}
continue-on-error: true
strategy:
# Duplicate changes to this matrix to 'poc_tests'
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.9', '3.10']
# Possible values: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10.0-rc.2']
# Possible values: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10.0-rc.2', 'pypy-3.8']
compiler: [""]
include:
- os: ubuntu-latest
python-version: '3.6'
- os: ubuntu-latest
python-version: '3.7'
- os: ubuntu-latest
python-version: '3.8'
- os: ubuntu-latest
python-version: '3.9'
compiler: 'g++'
## Expected failure
# - os: ubuntu-latest
# python-version: '3.10.0-rc.2'
Expand All @@ -46,6 +50,10 @@ jobs:
- name: Build
run: python -m pip install .

- if: ${{ matrix.compiler }}
# Only set the compiler for the tests, not for the build
run: echo "CC=${{ matrix.compiler }}" >> $GITHUB_ENV

- name: Run tests
run: |
python -m pip install pytest pytest-xdist
Expand Down
2 changes: 1 addition & 1 deletion c_test/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CC = gcc
CC ?= gcc
INCLUDE=-I.. -I../hpy/devel/include -I../hpy/debug/src/include
CFLAGS = -O0 -UNDEBUG -g -Wall -Werror -Wfatal-errors $(INCLUDE) -DHPY_UNIVERSAL_ABI

Expand Down
5 changes: 4 additions & 1 deletion hpy/debug/src/include/hpy_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ void hpy_debug_close_handle(HPyContext *dctx, HPy dh);
// CPython does for its own built-in modules. But we must use the same
// signature as HPy_MODINIT

// Copied from Python's exports.h
// Copied from Python's exports.h, pyport.h
#ifndef Py_EXPORTED_SYMBOL
#if defined(_WIN32) || defined(__CYGWIN__)
#define Py_EXPORTED_SYMBOL __declspec(dllexport)
#else
#define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default")))
#endif
#endif
#ifdef ___cplusplus
extern "C"
#endif
Py_EXPORTED_SYMBOL
HPy HPyInit__debug(HPyContext *uctx);

Expand Down
9 changes: 7 additions & 2 deletions hpy/devel/include/hpy/hpymodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,20 @@ typedef struct {
} HPyModuleDef;


#if defined(__cplusplus)
# define HPyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL HPy
#else /* __cplusplus */
# define HPyMODINIT_FUNC Py_EXPORTED_SYMBOL HPy
#endif /* __cplusplus */

#ifdef HPY_UNIVERSAL_ABI

// module initialization in the universal case
#define HPy_MODINIT(modname) \
_HPy_HIDDEN HPyContext *_ctx_for_trampolines; \
static HPy init_##modname##_impl(HPyContext *ctx); \
Py_EXPORTED_SYMBOL \
HPy HPyInit_##modname(HPyContext *ctx) \
HPyMODINIT_FUNC \
HPyInit_##modname(HPyContext *ctx) \
{ \
_ctx_for_trampolines = ctx; \
return init_##modname##_impl(ctx); \
Expand Down
24 changes: 24 additions & 0 deletions hpy/devel/include/hpy/inline_helpers.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#ifndef HPY_INLINE_HELPERS_H
#define HPY_INLINE_HELPERS_H

#if defined(_MSC_VER)
# include <malloc.h> /* for alloca() */
#endif

HPyAPI_FUNC HPy HPyErr_SetFromErrno(HPyContext *ctx, HPy h_type)
{
return HPyErr_SetFromErrnoWithFilenameObjects(ctx, h_type, HPy_NULL, HPy_NULL);
Expand All @@ -11,4 +15,24 @@ HPyAPI_FUNC HPy HPyErr_SetFromErrnoWithFilenameObject(HPyContext *ctx, HPy h_typ
return HPyErr_SetFromErrnoWithFilenameObjects(ctx, h_type, filename, HPy_NULL);
}

HPyAPI_FUNC HPy HPyTuple_Pack(HPyContext *ctx, HPy_ssize_t n, ...) {
va_list vargs;
HPy_ssize_t i;

if (n == 0) {
return HPyTuple_FromArray(ctx, (HPy*)NULL, n);
}
HPy *array = (HPy *)alloca(n * sizeof(HPy));
va_start(vargs, n);
if (array == NULL) {
va_end(vargs);
return HPy_NULL;
}
for (i = 0; i < n; i++) {
array[i] = va_arg(vargs, HPy);
}
va_end(vargs);
return HPyTuple_FromArray(ctx, array, n);
}

#endif //HPY_INLINE_HELPERS_H
9 changes: 0 additions & 9 deletions hpy/devel/include/hpy/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
((void**)data) \
))


/* ~~~ HPyTuple_Pack ~~~
this is just syntactic sugar around HPyTuple_FromArray, to help porting the
exising code which uses PyTuple_Pack
*/

#define HPyTuple_Pack(ctx, n, ...) (HPyTuple_FromArray(ctx, (HPy[]){ __VA_ARGS__ }, n))

/* Rich comparison opcodes */
typedef enum {
HPy_LT = 0,
Expand Down
2 changes: 1 addition & 1 deletion hpy/devel/src/runtime/ctx_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ctx_Module_Create(HPyContext *ctx, HPyModuleDef *hpydef)
// we can't free this memory because it is stitched into moduleobject. We
// just make it immortal for now, eventually we should think whether or
// not to free it if/when we unload the module
PyModuleDef *def = PyMem_Malloc(sizeof(PyModuleDef));
PyModuleDef *def = (PyModuleDef*)PyMem_Malloc(sizeof(PyModuleDef));
if (def == NULL) {
PyErr_NoMemory();
return HPy_NULL;
Expand Down
6 changes: 3 additions & 3 deletions hpy/devel/src/runtime/ctx_tracker.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ ctx_Tracker_New(HPyContext *ctx, HPy_ssize_t capacity)
}
capacity++; // always reserve space for an extra handle, see the docs

hp = malloc(sizeof(_HPyTracker_s));
hp = (_HPyTracker_s*)malloc(sizeof(_HPyTracker_s));
if (hp == NULL) {
HPyErr_NoMemory(ctx);
return _hp2ht(0);
}
hp->handles = calloc(capacity, sizeof(HPy));
hp->handles = (HPy*)calloc(capacity, sizeof(HPy));
if (hp->handles == NULL) {
free(hp);
HPyErr_NoMemory(ctx);
Expand Down Expand Up @@ -118,7 +118,7 @@ tracker_resize(HPyContext *ctx, _HPyTracker_s *hp, HPy_ssize_t capacity)
HPyErr_SetString(ctx, ctx->h_ValueError, "HPyTracker resize would lose handles");
return -1;
}
new_handles = realloc(hp->handles, capacity * sizeof(HPy));
new_handles = (HPy*)realloc(hp->handles, capacity * sizeof(HPy));
if (new_handles == NULL) {
HPyErr_NoMemory(ctx);
return -1;
Expand Down
24 changes: 12 additions & 12 deletions hpy/devel/src/runtime/ctx_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static HPyType_Extra_t *_HPyType_Extra_Alloc(const char *name, bool is_pure)
{
size_t name_size = strlen(name) + 1;
size_t size = offsetof(HPyType_Extra_t, name) + name_size;
HPyType_Extra_t *result = PyMem_Calloc(1, size);
HPyType_Extra_t *result = (HPyType_Extra_t*)PyMem_Calloc(1, size);
if (result == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -248,7 +248,7 @@ create_method_defs(HPyDef *hpydefs[], PyMethodDef *legacy_methods)
HPy_ssize_t total_count = hpymeth_count + legacy_count;

// allocate&fill the result
PyMethodDef *result = PyMem_Calloc(total_count+1, sizeof(PyMethodDef));
PyMethodDef *result = (PyMethodDef*)PyMem_Calloc(total_count+1, sizeof(PyMethodDef));
if (result == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -295,7 +295,7 @@ create_member_defs(HPyDef *hpydefs[], PyMemberDef *legacy_members, HPy_ssize_t b
HPy_ssize_t total_count = hpymember_count + legacy_count;

// allocate&fill the result
PyMemberDef *result = PyMem_Calloc(total_count+1, sizeof(PyMemberDef));
PyMemberDef *result = (PyMemberDef*)PyMem_Calloc(total_count+1, sizeof(PyMemberDef));
if (result == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -342,7 +342,7 @@ create_getset_defs(HPyDef *hpydefs[], PyGetSetDef *legacy_getsets)
HPy_ssize_t total_count = hpygetset_count + legacy_count;

// allocate&fill the result
PyGetSetDef *result = PyMem_Calloc(total_count+1, sizeof(PyGetSetDef));
PyGetSetDef *result = (PyGetSetDef*)PyMem_Calloc(total_count+1, sizeof(PyGetSetDef));
if (result == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -383,7 +383,7 @@ create_slot_defs(HPyType_Spec *hpyspec, HPy_ssize_t base_member_offset,
PyMethodDef *legacy_method_defs = NULL;
PyMemberDef *legacy_member_defs = NULL;
PyGetSetDef *legacy_getset_defs = NULL;
legacy_slots_count(hpyspec->legacy_slots, &legacy_slot_count,
legacy_slots_count((PyType_Slot*)hpyspec->legacy_slots, &legacy_slot_count,
&legacy_method_defs, &legacy_member_defs,
&legacy_getset_defs);
bool needs_dealloc = needs_hpytype_dealloc(hpyspec);
Expand All @@ -400,7 +400,7 @@ create_slot_defs(HPyType_Spec *hpyspec, HPy_ssize_t base_member_offset,

// allocate the result PyType_Slot array
HPy_ssize_t total_slot_count = hpyslot_count + legacy_slot_count;
PyType_Slot *result = PyMem_Calloc(total_slot_count+1, sizeof(PyType_Slot));
PyType_Slot *result = (PyType_Slot*)PyMem_Calloc(total_slot_count+1, sizeof(PyType_Slot));
if (result == NULL) {
PyErr_NoMemory();
return NULL;
Expand All @@ -423,7 +423,7 @@ create_slot_defs(HPyType_Spec *hpyspec, HPy_ssize_t base_member_offset,
}
PyType_Slot *dst = &result[dst_idx++];
dst->slot = hpy_slot_to_cpy_slot(src->slot.slot);
dst->pfunc = src->slot.cpy_trampoline;
dst->pfunc = (void*)src->slot.cpy_trampoline;
}
}

Expand Down Expand Up @@ -474,12 +474,12 @@ create_slot_defs(HPyType_Spec *hpyspec, HPy_ssize_t base_member_offset,

// add a dealloc function, if needed
if (needs_dealloc) {
result[dst_idx++] = (PyType_Slot){Py_tp_dealloc, hpytype_dealloc};
result[dst_idx++] = (PyType_Slot){Py_tp_dealloc, (void*)hpytype_dealloc};
}

// add a tp_clear, if the user provided a tp_traverse
if (has_tp_traverse(hpyspec)) {
result[dst_idx++] = (PyType_Slot){Py_tp_clear, hpytype_clear};
result[dst_idx++] = (PyType_Slot){Py_tp_clear, (void*)hpytype_clear};
}

// add the NULL sentinel at the end
Expand All @@ -505,7 +505,7 @@ create_buffer_procs(HPyType_Spec *hpyspec)
switch (src->slot.slot) {
case HPy_bf_getbuffer:
if (buffer_procs == NULL) {
buffer_procs = PyMem_Calloc(1, sizeof(PyBufferProcs));
buffer_procs = (PyBufferProcs*)PyMem_Calloc(1, sizeof(PyBufferProcs));
if (buffer_procs == NULL) {
PyErr_NoMemory();
return NULL;
Expand All @@ -515,7 +515,7 @@ create_buffer_procs(HPyType_Spec *hpyspec)
break;
case HPy_bf_releasebuffer:
if (buffer_procs == NULL) {
buffer_procs = PyMem_Calloc(1, sizeof(PyBufferProcs));
buffer_procs = (PyBufferProcs*)PyMem_Calloc(1, sizeof(PyBufferProcs));
if (buffer_procs == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -706,7 +706,7 @@ ctx_Type_FromSpec(HPyContext *ctx, HPyType_Spec *hpyspec,
return HPy_NULL;
}

PyType_Spec *spec = PyMem_Calloc(1, sizeof(PyType_Spec));
PyType_Spec *spec = (PyType_Spec*)PyMem_Calloc(1, sizeof(PyType_Spec));
if (spec == NULL) {
PyErr_NoMemory();
return HPy_NULL;
Expand Down
2 changes: 1 addition & 1 deletion test/test_00_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def test_unsupported_signature(self):
.kind = HPyDef_Kind_Meth,
.meth = {
.name = "f",
.signature = 1234,
.signature = (HPyFunc_Signature)1234,
}
};
@EXPORT(f)
Expand Down
3 changes: 2 additions & 1 deletion test/test_cpy_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ def test_many_handles(self):
static HPy f_impl(HPyContext *ctx, HPy self)
{
PyObject *o = PyList_New(0);
Py_ssize_t final_refcount;
Py_ssize_t result = -42;
HPy handles[NUM_HANDLES];
Expand All @@ -185,7 +186,7 @@ def test_many_handles(self):
goto error;
for (i = 0; i < NUM_HANDLES; i++)
HPy_Close(ctx, handles[i]);
Py_ssize_t final_refcount = o->ob_refcnt;
final_refcount = o->ob_refcnt;
result = final_refcount - initial_refcount;
error:
Expand Down
2 changes: 1 addition & 1 deletion test/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_with_spec_and_params(self):
{
HPyType_SpecParam param[] = {
{ HPyType_SpecParam_Base, ctx->h_LongType },
{ 0 }
{ (HPyType_SpecParam_Kind)0 }
};
if (!HPyHelpers_AddType(ctx, self, "Dummy", &dummy_spec, param))
{
Expand Down
10 changes: 5 additions & 5 deletions test/test_hpytype.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ def test_doc_string(self):
mod = self.make_module("""
static HPyType_Spec Dummy_spec = {
.name = "mytest.Dummy",
.doc = "A succinct description.",
.itemsize = 0,
.flags = HPy_TPFLAGS_DEFAULT | HPy_TPFLAGS_BASETYPE,
@IS_LEGACY
.doc = "A succinct description.",
};
@EXPORT_TYPE("Dummy", Dummy_spec)
Expand Down Expand Up @@ -154,8 +154,8 @@ def test_HPyDef_SLOT(self):
};
static HPyType_Spec Dummy_spec = {
.name = "mytest.Dummy",
.defines = Dummy_defines,
@IS_LEGACY
.defines = Dummy_defines,
};
@EXPORT_TYPE("Dummy", Dummy_spec)
Expand Down Expand Up @@ -195,8 +195,8 @@ def test_HPyDef_METH(self):
static HPyType_Spec dummy_type_spec = {
.name = "mytest.Dummy",
.defines = dummy_type_defines,
@IS_LEGACY
.defines = dummy_type_defines,
};
@EXPORT_TYPE("Dummy", dummy_type_spec)
Expand Down Expand Up @@ -734,7 +734,7 @@ def test_specparam_base(self):
{
HPyType_SpecParam param[] = {
{ HPyType_SpecParam_Base, ctx->h_LongType },
{ 0 }
{ (HPyType_SpecParam_Kind)0 }
};
HPy h_Dummy = HPyType_FromSpec(ctx, &Dummy_spec, param);
if (HPy_IsNull(h_Dummy))
Expand Down Expand Up @@ -773,7 +773,7 @@ def test_specparam_basestuple(self):
return;
HPyType_SpecParam param[] = {
{ HPyType_SpecParam_BasesTuple, h_bases },
{ 0 }
{ (HPyType_SpecParam_Kind)0 }
};
HPy h_Dummy = HPyType_FromSpec(ctx, &Dummy_spec, param);
HPy_Close(ctx, h_bases);
Expand Down
Loading

0 comments on commit 02a4f7e

Please sign in to comment.