일부 코드 (PyCXX에서 곧바로 적용됨) 주위에 머리를 쓰려고합니다. 다중 플랫폼 C++ 파이썬 랩퍼입니다.Windows에서 지연로드
편집 : 원본 코드 here.
그것은 단지 윈도우에 존재하는 어떤 특별한 현상을 음식을 장만 할 나타납니다
#ifdef PY_WIN32_DELAYLOAD_PYTHON_DLL
:
#else
:
#endif
내가 아래 목록 전체 파일을 줄 것이다, 꽤 깁니다.
이 PY_WIN32_DELAYLOAD_PYTHON_DLL 토큰은 CPython 내에 존재하지 않으며 PyCXX에도 정의되어 있지 않습니다. 따라서 PyCXX는 선택적 컴파일러 플래그로 제공 될 것이라고 생각할 수 있습니다.
내가 알고 싶은 것은 : 그 목적은 무엇인가? 어떤 문제가 해결됩니까? 이 메커니즘은 왜 존재합니까?
아마도 Windows 프로그래밍에 익숙한 사람이 코드에서 알아낼 수 있습니까?
코드가 15 세 이상이므로 해결해야 할 문제가 여전히 최신 Windows에 있는지 여부를 알고 싶습니다.
키 질문은 다음과 같습니다. 이를 제거 할 수 있습니까? 아니면 청소기로 교체 할 수 있습니까?
나는 그것을 아주 잘랐다. 하지만 여전히 현대 Windows 환경에서 유용한 목적을 수행합니까?
코드 :
는 Win32에#include "Base.hxx" //"IndirectPythonInterface.hxx"
namespace Py
{
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
#ifdef PY_WIN32_DELAYLOAD_PYTHON_DLL
# ifndef MS_WINDOWS
# error "Can only delay load under Win32"
# endif
# include <windows.h> // !!! Is it possible we ever want Windows.h but no delay load? If so, this is wrong...
static HMODULE python_dll;
# define DECLARE_ERROR(THE_ERROR) \
static PyObject* ptr__Exc_##THE_ERROR = nullptr;
ALL_ERRORS(DECLARE_ERROR)
static PyObject* ptr__PyNone = nullptr;
static PyObject* ptr__PyFalse = nullptr;
static PyObject* ptr__PyTrue = nullptr;
# define DECLARE_TYPE(T) \
static PyTypeObject* ptr__##T##_Type = nullptr;
ALL_TYPES(DECLARE_TYPE)
static int* ptr_Py_DebugFlag = nullptr;
static int* ptr_Py_InteractiveFlag = nullptr;
static int* ptr_Py_OptimizeFlag = nullptr;
static int* ptr_Py_NoSiteFlag = nullptr;
static int* ptr_Py_VerboseFlag = nullptr;
static char** ptr__Py_PackageContext = nullptr;
# ifdef Py_REF_DEBUG
int* ptr_Py_RefTotal; // !!! Why not static?
# endif
//--------------------------------------------------------------------------------
class GetAddressException
{
public:
GetAddressException(const char* _name)
: name(_name)
{ }
virtual ~GetAddressException() { }
const char* name;
};
//--------------------------------------------------------------------------------
# define GET_PTR(FUNC, RETURN_TYPE) \
static FUNC(const char *name) \
{ \
FARPROC addr = GetProcAddress(python_dll, name); \
if(addr == nullptr) \
throw GetAddressException(name); \
\
return RETURN_TYPE addr; \
}
GET_PTR(PyObject * GetPyObjectPointer_As_PyObjectPointer , *(PyObject **) )
GET_PTR(PyObject * GetPyObject_As_PyObjectPointer , (PyObject *) )
GET_PTR(PyTypeObject * GetPyTypeObjectPointer_As_PyTypeObjectPointer , *(PyTypeObject**) )
GET_PTR(PyTypeObject * GetPyTypeObject_As_PyTypeObjectPointer , (PyTypeObject*) )
GET_PTR(int * GetInt_as_IntPointer , (int*) )
GET_PTR(char ** GetCharPointer_as_CharPointerPointer , (char**) )
# ifdef _DEBUG
static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL";
# else
static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL";
# endif
//--------------------------------------------------------------------------------
bool InitialisePythonIndirectInterface()
{
char python_dll_name[sizeof(python_dll_name_format)];
_snprintf(python_dll_name, sizeof(python_dll_name_format)/sizeof(char) - 1, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION);
python_dll = LoadLibraryA(python_dll_name);
if(python_dll == nullptr)
return false;
try
{
# ifdef Py_REF_DEBUG
ptr_Py_RefTotal = GetInt_as_IntPointer("_Py_RefTotal");
# endif
ptr_Py_DebugFlag = GetInt_as_IntPointer("Py_DebugFlag");
ptr_Py_InteractiveFlag = GetInt_as_IntPointer("Py_InteractiveFlag");
ptr_Py_OptimizeFlag = GetInt_as_IntPointer("Py_OptimizeFlag");
ptr_Py_NoSiteFlag = GetInt_as_IntPointer("Py_NoSiteFlag");
ptr_Py_VerboseFlag = GetInt_as_IntPointer("Py_VerboseFlag");
ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer("_Py_PackageContext");
# define ASSIGN_PTR(E) \
ptr__Exc_##E = GetPyObjectPointer_As_PyObjectPointer("PyExc_" #E);
ALL_ERRORS(ASSIGN_PTR)
ptr__PyNone = GetPyObject_As_PyObjectPointer("_Py_NoneStruct");
ptr__PyFalse = GetPyObject_As_PyObjectPointer("_Py_ZeroStruct");
ptr__PyTrue = GetPyObject_As_PyObjectPointer("_Py_TrueStruct");
# define MAKE_PTR(TYPENAME) \
ptr__##TYPENAME##_Type = GetPyTypeObject_As_PyTypeObjectPointer("Py" #TYPENAME "_Type");
ALL_TYPES(MAKE_PTR)
}
catch(GetAddressException &e)
{
OutputDebugStringA(python_dll_name);
OutputDebugStringA(" does not contain symbol ");
OutputDebugStringA(e.name);
OutputDebugStringA("\n");
return false;
}
return true;
}
//#if 0
//#define Py_INCREF(op) ( \
// _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
// ((PyObject*)(op))->ob_refcnt++)
//
//#define Py_DECREF(op) \
// if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
// --((PyObject*)(op))->ob_refcnt != 0) \
// _Py_CHECK_REFCNT(op) \
// else \
// _Py_Dealloc((PyObject *)(op))
//#endif
void _XINCREF(PyObject* op)
{
// This function must match the contents of Py_XINCREF(op)
if(op == nullptr)
return;
# ifdef Py_REF_DEBUG
(*ptr_Py_RefTotal)++;
# endif
(op)->ob_refcnt++;
}
void _XDECREF(PyObject* op)
{
// This function must match the contents of Py_XDECREF(op);
if(op == nullptr)
return;
# ifdef Py_REF_DEBUG
(*ptr_Py_RefTotal)--;
# endif
if (--(op)->ob_refcnt == 0)
_Py_Dealloc((PyObject *)(op));
}
#else // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// Needed to keep the abstactions for delayload interface
//
// !!! π Py_XDECREF has been deprecated in favour of Py_CLEAR
void _XINCREF(PyObject* op)
{
Py_XINCREF(op);
}
void _XDECREF(PyObject* op)
{
Py_XDECREF(op);
}
#endif // PY_WIN32_DELAYLOAD_PYTHON_DLL
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
//
// Wrap Python-types, type checks, errors, flags, etc as function calls
//
#ifdef PY_WIN32_DELAYLOAD_PYTHON_DLL
# define IF_DELAYLOAD_ELSE(A, B) A
#else
# define IF_DELAYLOAD_ELSE(A, B) B
#endif
#define _Foo_Check(TYPENAME) \
bool _##TYPENAME##_Check(PyObject *pyob) \
{ \
return pyob->ob_type == _##TYPENAME##_Type(); \
}
ALL_TYPES(_Foo_Check)
#define _Foo_Type(TYPENAME) \
PyTypeObject* _##TYPENAME##_Type() \
{ \
return IF_DELAYLOAD_ELSE(ptr__##TYPENAME##_Type, & Py##TYPENAME##_Type); \
}
ALL_TYPES(_Foo_Type)
#define _Exc_Foo(E) \
PyObject* _Exc_##E() \
{ \
return IF_DELAYLOAD_ELSE(ptr__Exc_##E, ::PyExc_##E); \
}
ALL_ERRORS(_Exc_Foo)
int& _Py_DebugFlag() { return IF_DELAYLOAD_ELSE(*ptr_Py_DebugFlag , Py_DebugFlag); }
int& _Py_InteractiveFlag() { return IF_DELAYLOAD_ELSE(*ptr_Py_InteractiveFlag , Py_InteractiveFlag); }
int& _Py_OptimizeFlag() { return IF_DELAYLOAD_ELSE(*ptr_Py_OptimizeFlag , Py_OptimizeFlag); }
int& _Py_NoSiteFlag() { return IF_DELAYLOAD_ELSE(*ptr_Py_NoSiteFlag , Py_NoSiteFlag); }
int& _Py_VerboseFlag() { return IF_DELAYLOAD_ELSE(*ptr_Py_VerboseFlag , Py_VerboseFlag); }
char* __Py_PackageContext() { return IF_DELAYLOAD_ELSE(*ptr__Py_PackageContext , _Py_PackageContext); }
PyObject* _None() { return IF_DELAYLOAD_ELSE(ptr__PyNone , &::_Py_NoneStruct); }
PyObject* _False() { return IF_DELAYLOAD_ELSE(ptr__PyFalse , Py_False); }
PyObject* _True() { return IF_DELAYLOAD_ELSE(ptr__PyTrue , Py_True); }
} // namespace Py
Windows 로더가 Linux ld.so와 매우 다르게 작동하기 때문에. @Waldo의 대답에 따라 현대 Windows에서이 모든 것을 삭제하고/delayload를 사용할 수 있습니다. 왜 해보지 그래? – bmargulies