python — задержка загрузки в Windows

Я пытаюсь разобраться в некотором коде (адаптирован прямо из PyCXX). Это многоплатформенная оболочка C ++ Python.

РЕДАКТИРОВАТЬ: оригинальный код Вот.

Похоже, что он обслуживает какое-то конкретное явление, которое существует только в Windows:

#ifdef PY_WIN32_DELAYLOAD_PYTHON_DLL
:
#else
:
#endif

Я приведу полный список файлов ниже, это довольно долго.

Этот токен PY_WIN32_DELAYLOAD_PYTHON_DLL не существует в CPython, он также не определен в PyCXX. Следовательно, я могу только представить, что PyCXX намеревается, что он поставляется как необязательный флаг компилятора.

Что я хотел бы знать, так это: какова его цель? Какую проблему это решает? Почему этот механизм вообще существует?

Может быть, кто-то, кто знаком с программированием Windows, может понять это из кода?

Я хотел бы знать, присутствует ли проблема, которую она решает, в современной Windows, так как коду> 15 лет.

Ключевой вопрос: Могу ли я удалить его или заменить чем-нибудь более чистым?

Я бы очень хотел вырезать это; но все еще служит какой-то полезной цели в современной среде Windows?

Код:

#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

1

Решение

На Win32 задержка загрузки является механизмом, позволяющим PE file для ссылки на другой PE-файл, который не находится там, где загрузчик ожидает его во время запуска файла, или изящно откатится, если его вообще нет. Мне кажется, что это обслуживает программу Windows, которая встраивает сам Python, но не хочет, чтобы DLL, содержащая Python, находилась в PATH.

Кроме того, некоторые поиски в Google предполагают, что это связано с предотвращением цикличности между python и модулем, созданным для загрузки python.

4

Другие решения

Макросы могут быть определены аргументами препроцессора, поэтому вы их нигде не видите. С Microsoft компилятор с аргументом / D.

/ D имеет тот же эффект, что и директива #define в начале файла исходного кода, за исключением того, что / D удаляет кавычки в командной строке и #define сохраняет их.

http://msdn.microsoft.com/en-us/library/hhzbb5c8.aspx

С gcc с -D проверьте эту ссылку:

https://www.daniweb.com/software-development/c/threads/348802/passing-string-as-d-compiler-option

Отложенная загрузка — это механизм загрузки библиотеки только тогда, когда она используется вместо того, чтобы ОС делала это до запуска приложения. Это может сэкономить драгоценную память и время загрузки, поскольку (в зависимости от потока кода) DLL может не загружаться вообще.

Этот код пытается реализовать отложенную нагрузку самостоятельно если макрос определен иначе, просто идите нормальным путем. Microsoft linker может выполнить эту работу автоматически (т.е. вам не нужно ничего программировать). Имейте в виду, что это не функция платформы, а функция компоновщика.

Проверьте эту ссылку:
http://en.wikipedia.org/wiki/Dynamic-link_library#Delayed_loading

Вы можете отказаться от кода и дать указание компоновщику Microsoft добавить код для вас, если хотите.

Вы можете сделать это с аргументом / DELAYLOAD, как описано в этой статье:

http://msdn.microsoft.com/en-us/library/yx9zd12s.aspx

Просто убедитесь, что вы перехватываете правильные исключения и хуки, если dll не найден.

2

По вопросам рекламы [email protected]