diff --git a/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx b/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx index a46ce81558..fda72f2ce8 100644 --- a/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx +++ b/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx @@ -5,4 +5,5 @@ #include "interrogate_interface.cxx" #include "interrogate_request.cxx" #include "py_panda.cxx" +#include "py_compat.cxx" #include "py_wrappers.cxx" diff --git a/dtool/src/interrogatedb/py_compat.cxx b/dtool/src/interrogatedb/py_compat.cxx new file mode 100755 index 0000000000..f7f02607c0 --- /dev/null +++ b/dtool/src/interrogatedb/py_compat.cxx @@ -0,0 +1,54 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file py_compat.cxx + * @author rdb + * @date 2017-12-03 + */ + +#include "py_compat.h" + +#ifdef HAVE_PYTHON + +PyTupleObject Dtool_EmptyTuple = {PyVarObject_HEAD_INIT(nullptr, 0)}; + +#if PY_MAJOR_VERSION < 3 +/** + * Given a long or int, returns a size_t, or raises an OverflowError if it is + * out of range. + */ +size_t PyLongOrInt_AsSize_t(PyObject *vv) { + if (PyInt_Check(vv)) { + long value = PyInt_AS_LONG(vv); + if (value < 0) { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to size_t"); + return (size_t)-1; + } + return (size_t)value; + } + + if (!PyLong_Check(vv)) { + Dtool_Raise_TypeError("a long or int was expected"); + return (size_t)-1; + } + + size_t bytes; + int one = 1; + int res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, + SIZEOF_SIZE_T, (int)*(unsigned char*)&one, 0); + + if (res < 0) { + return (size_t)res; + } else { + return bytes; + } +} +#endif + +#endif // HAVE_PYTHON diff --git a/dtool/src/interrogatedb/py_compat.h b/dtool/src/interrogatedb/py_compat.h new file mode 100755 index 0000000000..852ba95a02 --- /dev/null +++ b/dtool/src/interrogatedb/py_compat.h @@ -0,0 +1,169 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file py_compat.h + * @author rdb + * @date 2017-12-02 + */ + +#ifndef PY_COMPAT_H +#define PY_COMPAT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +// The contents of this file were originally part of py_panda.h. It +// specifically contains polyfills that are required to maintain compatibility +// with Python 2 and older versions of Python 3. + +// These compatibility hacks are sorted by Python version that removes the +// need for the respective hack. + +#ifdef _POSIX_C_SOURCE +# undef _POSIX_C_SOURCE +#endif + +#ifdef _XOPEN_SOURCE +# undef _XOPEN_SOURCE +#endif + +// See PEP 353 +#define PY_SSIZE_T_CLEAN 1 + +#include "Python.h" + +/* Python 2.4 */ + +// 2.4 macros which aren't available in 2.3 +#ifndef Py_RETURN_NONE +# define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#ifndef Py_RETURN_TRUE +# define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif + +#ifndef Py_RETURN_FALSE +# define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif + +/* Python 2.5 */ + +// Prior to Python 2.5, we didn't have Py_ssize_t. +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +# define PyInt_FromSsize_t PyInt_FromLong +# define PyInt_AsSsize_t PyInt_AsLong +#endif + +/* Python 2.6 */ + +#ifndef Py_TYPE +# define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif + +/* Python 2.7, 3.1 */ + +#ifndef PyVarObject_HEAD_INIT + #define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, +#endif + +/* Python 2.7, 3.2 */ + +#if PY_VERSION_HEX < 0x03020000 +# define PyErr_NewExceptionWithDoc(name, doc, base, dict) \ + PyErr_NewException(name, base, dict) +#endif + +/* Python 3.0 */ + +// Always on in Python 3 +#ifndef Py_TPFLAGS_CHECKTYPES +# define Py_TPFLAGS_CHECKTYPES 0 +#endif + +// Macros for writing code that will compile in both versions. +#if PY_MAJOR_VERSION >= 3 +# define nb_nonzero nb_bool +# define nb_divide nb_true_divide +# define nb_inplace_divide nb_inplace_true_divide + +# define PyLongOrInt_Check(x) PyLong_Check(x) +# define PyLongOrInt_AS_LONG PyLong_AS_LONG +# define PyInt_Check PyLong_Check +# define PyInt_AsLong PyLong_AsLong +# define PyInt_AS_LONG PyLong_AS_LONG +# define PyLongOrInt_AsSize_t PyLong_AsSize_t +#else +# define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x)) +// PyInt_FromSize_t automatically picks the right type. +# define PyLongOrInt_AS_LONG PyInt_AsLong + +EXPCL_INTERROGATEDB size_t PyLongOrInt_AsSize_t(PyObject *); +#endif + +// Which character to use in PyArg_ParseTuple et al for a byte string. +#if PY_MAJOR_VERSION >= 3 +# define FMTCHAR_BYTES "y" +#else +# define FMTCHAR_BYTES "s" +#endif + +/* Python 3.2 */ + +#if PY_VERSION_HEX < 0x03020000 +typedef long Py_hash_t; +#endif + +/* Python 3.3 */ + +#if PY_MAJOR_VERSION >= 3 +// Python 3 versions before 3.3.3 defined this incorrectly. +# undef _PyErr_OCCURRED +# define _PyErr_OCCURRED() (PyThreadState_GET()->curexc_type) + +// Python versions before 3.3 did not define this. +# if PY_VERSION_HEX < 0x03030000 +# define PyUnicode_AsUTF8 _PyUnicode_AsString +# define PyUnicode_AsUTF8AndSize _PyUnicode_AsStringAndSize +# endif +#endif + +/* Python 3.6 */ + +// Used to implement _PyObject_CallNoArg +extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple; + +#ifndef _PyObject_CallNoArg +# define _PyObject_CallNoArg(func) PyObject_Call((func), (PyObject *)&Dtool_EmptyTuple, nullptr) +#endif + +// Python versions before 3.6 didn't require longlong support to be enabled. +#ifndef HAVE_LONG_LONG +# define PyLong_FromLongLong(x) PyLong_FromLong((long) (x)) +# define PyLong_FromUnsignedLongLong(x) PyLong_FromUnsignedLong((unsigned long) (x)) +# define PyLong_AsLongLong(x) PyLong_AsLong(x) +# define PyLong_AsUnsignedLongLong(x) PyLong_AsUnsignedLong(x) +# define PyLong_AsUnsignedLongLongMask(x) PyLong_AsUnsignedLongMask(x) +# define PyLong_AsLongLongAndOverflow(x) PyLong_AsLongAndOverflow(x) +#endif + +/* Other Python implementations */ + +// _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred. +// Some implementations of the CPython API (e.g. PyPy's cpyext) do not define +// it, so in these cases we just silently fall back to PyErr_Occurred. +#ifndef _PyErr_OCCURRED +# define _PyErr_OCCURRED() PyErr_Occurred() +#endif + +#endif // HAVE_PYTHON + +#endif // PY_COMPAT_H diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 5e453f207c..d218a6c12c 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -17,8 +17,6 @@ #ifdef HAVE_PYTHON -PyTupleObject Dtool_EmptyTuple; - PyMemberDef standard_type_members[] = { {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"}, {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"}, @@ -33,39 +31,6 @@ static RuntimeTypeMap runtime_type_map; static RuntimeTypeSet runtime_type_set; static NamedTypeMap named_type_map; -#if PY_MAJOR_VERSION < 3 -/** - * Given a long or int, returns a size_t, or raises an OverflowError if it is - * out of range. - */ -size_t PyLongOrInt_AsSize_t(PyObject *vv) { - if (PyInt_Check(vv)) { - long value = PyInt_AS_LONG(vv); - if (value < 0) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to size_t"); - return (size_t)-1; - } - return (size_t)value; - } - - if (!PyLong_Check(vv)) { - Dtool_Raise_TypeError("a long or int was expected"); - return (size_t)-1; - } - - size_t bytes; - int one = 1; - int res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, - SIZEOF_SIZE_T, (int)*(unsigned char*)&one, 0); - - if (res < 0) { - return (size_t)res; - } else { - return bytes; - } -} -#endif /** * Given a valid (non-NULL) PyObject, does a simple check to see if it might @@ -646,8 +611,9 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)"); } - // Initialize the "empty tuple". - (void)PyObject_INIT_VAR((PyObject *)&Dtool_EmptyTuple, &PyTuple_Type, 0); +#ifdef Py_TRACE_REFS + _Py_AddToAllObjects((PyObject *)&Dtool_EmptyTuple, 0); +#endif // Initialize the base class of everything. Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(NULL); diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index adcce27b9c..fad7ccedb0 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -20,131 +20,15 @@ #define Py_DEBUG #endif -#ifndef NO_RUNTIME_TYPES - -#include "dtoolbase.h" -#include "typedObject.h" -#include "typeRegistry.h" - -#endif - #include "pnotify.h" #include "vector_uchar.h" #if defined(HAVE_PYTHON) && !defined(CPPPARSER) -#ifdef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE -#endif - -#ifdef _XOPEN_SOURCE -#undef _XOPEN_SOURCE -#endif - -#define PY_SSIZE_T_CLEAN 1 - -#include "Python.h" +// py_compat.h includes Python.h. +#include "py_compat.h" #include "structmember.h" -#ifndef HAVE_LONG_LONG -#define PyLong_FromLongLong(x) PyLong_FromLong((long) (x)) -#define PyLong_FromUnsignedLongLong(x) PyLong_FromUnsignedLong((unsigned long) (x)) -#define PyLong_AsLongLong(x) PyLong_AsLong(x) -#define PyLong_AsUnsignedLongLong(x) PyLong_AsUnsignedLong(x) -#define PyLong_AsUnsignedLongLongMask(x) PyLong_AsUnsignedLongMask(x) -#define PyLong_AsLongLongAndOverflow(x) PyLong_AsLongAndOverflow(x) -#endif - -#if PY_VERSION_HEX < 0x02050000 - -// Prior to Python 2.5, we didn't have Py_ssize_t. -typedef int Py_ssize_t; -#define PyInt_FromSsize_t PyInt_FromLong -#define PyInt_AsSsize_t PyInt_AsLong - -#endif // PY_VERSION_HEX - -// 2.4 macros which aren't available in 2.3 -#ifndef Py_RETURN_NONE -inline PyObject* doPy_RETURN_NONE() -{ Py_INCREF(Py_None); return Py_None; } -#define Py_RETURN_NONE return doPy_RETURN_NONE() -#endif - -#ifndef Py_RETURN_TRUE -inline PyObject* doPy_RETURN_TRUE() -{Py_INCREF(Py_True); return Py_True;} -#define Py_RETURN_TRUE return doPy_RETURN_TRUE() -#endif - -#ifndef Py_RETURN_FALSE -inline PyObject* doPy_RETURN_FALSE() -{Py_INCREF(Py_False); return Py_False;} -#define Py_RETURN_FALSE return doPy_RETURN_FALSE() -#endif - -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(type, size) \ - PyObject_HEAD_INIT(type) size, -#endif - -#ifndef Py_TYPE -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#endif - -#ifndef Py_TPFLAGS_CHECKTYPES -// Always on in Python 3 -#define Py_TPFLAGS_CHECKTYPES 0 -#endif - -#if PY_MAJOR_VERSION >= 3 -// For writing code that will compile in both versions. -#define nb_nonzero nb_bool -#define nb_divide nb_true_divide -#define nb_inplace_divide nb_inplace_true_divide - -#define PyLongOrInt_Check(x) PyLong_Check(x) -#define PyLongOrInt_AS_LONG PyLong_AS_LONG -#define PyInt_Check PyLong_Check -#define PyInt_AsLong PyLong_AsLong -#define PyInt_AS_LONG PyLong_AS_LONG -#define PyLongOrInt_AsSize_t PyLong_AsSize_t -#else -#define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x)) -// PyInt_FromSize_t automatically picks the right type. -#define PyLongOrInt_AS_LONG PyInt_AsLong - -EXPCL_INTERROGATEDB size_t PyLongOrInt_AsSize_t(PyObject *); - -// For more portably defining hash functions. -typedef long Py_hash_t; -#endif - -#if PY_MAJOR_VERSION >= 3 -// Python 3 versions before 3.3.3 defined this incorrectly. -#undef _PyErr_OCCURRED -#define _PyErr_OCCURRED() (PyThreadState_GET()->curexc_type) - -// Python versions before 3.3 did not define this. -#if PY_VERSION_HEX < 0x03030000 -#define PyUnicode_AsUTF8 _PyUnicode_AsString -#define PyUnicode_AsUTF8AndSize _PyUnicode_AsStringAndSize -#endif -#endif - -// Which character to use in PyArg_ParseTuple et al for a byte string. -#if PY_MAJOR_VERSION >= 3 -#define FMTCHAR_BYTES "y" -#else -#define FMTCHAR_BYTES "s" -#endif - -extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple; - -#ifndef _PyObject_CallNoArg -#define _PyObject_CallNoArg(func) PyObject_Call((func), (PyObject *)&Dtool_EmptyTuple, NULL) -#endif - using namespace std; // this is tempory .. untill this is glued better into the panda build system