bpo-42545: Check that all symbols in the limited ABI are exported (GH-23616)
This commit is contained in:
parent
2e0760bb2e
commit
85f1dedb8d
|
@ -75,6 +75,8 @@ jobs:
|
||||||
fi
|
fi
|
||||||
- name: Check exported libpython symbols
|
- name: Check exported libpython symbols
|
||||||
run: make smelly
|
run: make smelly
|
||||||
|
- name: Check limited ABI symbols
|
||||||
|
run: make check-limited-abi
|
||||||
|
|
||||||
build_win32:
|
build_win32:
|
||||||
name: 'Windows (x86)'
|
name: 'Windows (x86)'
|
||||||
|
|
|
@ -192,6 +192,8 @@ script:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./python Tools/scripts/patchcheck.py --travis $TRAVIS_PULL_REQUEST; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./python Tools/scripts/patchcheck.py --travis $TRAVIS_PULL_REQUEST; fi
|
||||||
# Check that all symbols exported by libpython start with "Py" or "_Py"
|
# Check that all symbols exported by libpython start with "Py" or "_Py"
|
||||||
- make smelly
|
- make smelly
|
||||||
|
# Check that all symbols in the limited abi are present
|
||||||
|
- make check-limited-abi
|
||||||
# `-r -w` implicitly provided through `make buildbottest`.
|
# `-r -w` implicitly provided through `make buildbottest`.
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
|
|
|
@ -0,0 +1,779 @@
|
||||||
|
# File generated by 'make regen-limited-abi'
|
||||||
|
# This is NOT an authoritative list of stable ABI symbols
|
||||||
|
PyArg_Parse
|
||||||
|
PyArg_ParseTuple
|
||||||
|
PyArg_ParseTupleAndKeywords
|
||||||
|
PyArg_UnpackTuple
|
||||||
|
PyArg_VaParse
|
||||||
|
PyArg_VaParseTupleAndKeywords
|
||||||
|
PyArg_ValidateKeywordArguments
|
||||||
|
PyBaseObject_Type
|
||||||
|
PyBool_FromLong
|
||||||
|
PyBool_Type
|
||||||
|
PyByteArrayIter_Type
|
||||||
|
PyByteArray_AsString
|
||||||
|
PyByteArray_Concat
|
||||||
|
PyByteArray_FromObject
|
||||||
|
PyByteArray_FromStringAndSize
|
||||||
|
PyByteArray_Resize
|
||||||
|
PyByteArray_Size
|
||||||
|
PyByteArray_Type
|
||||||
|
PyBytesIter_Type
|
||||||
|
PyBytes_AsString
|
||||||
|
PyBytes_AsStringAndSize
|
||||||
|
PyBytes_Concat
|
||||||
|
PyBytes_ConcatAndDel
|
||||||
|
PyBytes_DecodeEscape
|
||||||
|
PyBytes_FromFormat
|
||||||
|
PyBytes_FromFormatV
|
||||||
|
PyBytes_FromObject
|
||||||
|
PyBytes_FromString
|
||||||
|
PyBytes_FromStringAndSize
|
||||||
|
PyBytes_Repr
|
||||||
|
PyBytes_Size
|
||||||
|
PyBytes_Type
|
||||||
|
PyCFunction_Call
|
||||||
|
PyCFunction_GetFlags
|
||||||
|
PyCFunction_GetFunction
|
||||||
|
PyCFunction_GetSelf
|
||||||
|
PyCFunction_NewEx
|
||||||
|
PyCFunction_Type
|
||||||
|
PyCMethod_New
|
||||||
|
PyCallIter_New
|
||||||
|
PyCallIter_Type
|
||||||
|
PyCallable_Check
|
||||||
|
PyCapsule_GetContext
|
||||||
|
PyCapsule_GetDestructor
|
||||||
|
PyCapsule_GetName
|
||||||
|
PyCapsule_GetPointer
|
||||||
|
PyCapsule_Import
|
||||||
|
PyCapsule_IsValid
|
||||||
|
PyCapsule_New
|
||||||
|
PyCapsule_SetContext
|
||||||
|
PyCapsule_SetDestructor
|
||||||
|
PyCapsule_SetName
|
||||||
|
PyCapsule_SetPointer
|
||||||
|
PyCapsule_Type
|
||||||
|
PyClassMethodDescr_Type
|
||||||
|
PyCodec_BackslashReplaceErrors
|
||||||
|
PyCodec_Decode
|
||||||
|
PyCodec_Decoder
|
||||||
|
PyCodec_Encode
|
||||||
|
PyCodec_Encoder
|
||||||
|
PyCodec_IgnoreErrors
|
||||||
|
PyCodec_IncrementalDecoder
|
||||||
|
PyCodec_IncrementalEncoder
|
||||||
|
PyCodec_KnownEncoding
|
||||||
|
PyCodec_LookupError
|
||||||
|
PyCodec_NameReplaceErrors
|
||||||
|
PyCodec_Register
|
||||||
|
PyCodec_RegisterError
|
||||||
|
PyCodec_ReplaceErrors
|
||||||
|
PyCodec_StreamReader
|
||||||
|
PyCodec_StreamWriter
|
||||||
|
PyCodec_StrictErrors
|
||||||
|
PyCodec_Unregister
|
||||||
|
PyCodec_XMLCharRefReplaceErrors
|
||||||
|
PyComplex_FromDoubles
|
||||||
|
PyComplex_ImagAsDouble
|
||||||
|
PyComplex_RealAsDouble
|
||||||
|
PyComplex_Type
|
||||||
|
PyDescr_NewClassMethod
|
||||||
|
PyDescr_NewGetSet
|
||||||
|
PyDescr_NewMember
|
||||||
|
PyDescr_NewMethod
|
||||||
|
PyDictItems_Type
|
||||||
|
PyDictIterItem_Type
|
||||||
|
PyDictIterKey_Type
|
||||||
|
PyDictIterValue_Type
|
||||||
|
PyDictKeys_Type
|
||||||
|
PyDictProxy_New
|
||||||
|
PyDictProxy_Type
|
||||||
|
PyDictRevIterItem_Type
|
||||||
|
PyDictRevIterKey_Type
|
||||||
|
PyDictRevIterValue_Type
|
||||||
|
PyDictValues_Type
|
||||||
|
PyDict_Clear
|
||||||
|
PyDict_Contains
|
||||||
|
PyDict_Copy
|
||||||
|
PyDict_DelItem
|
||||||
|
PyDict_DelItemString
|
||||||
|
PyDict_GetItem
|
||||||
|
PyDict_GetItemString
|
||||||
|
PyDict_GetItemWithError
|
||||||
|
PyDict_Items
|
||||||
|
PyDict_Keys
|
||||||
|
PyDict_Merge
|
||||||
|
PyDict_MergeFromSeq2
|
||||||
|
PyDict_New
|
||||||
|
PyDict_Next
|
||||||
|
PyDict_SetItem
|
||||||
|
PyDict_SetItemString
|
||||||
|
PyDict_Size
|
||||||
|
PyDict_Type
|
||||||
|
PyDict_Update
|
||||||
|
PyDict_Values
|
||||||
|
PyEllipsis_Type
|
||||||
|
PyEnum_Type
|
||||||
|
PyErr_BadArgument
|
||||||
|
PyErr_BadInternalCall
|
||||||
|
PyErr_CheckSignals
|
||||||
|
PyErr_Clear
|
||||||
|
PyErr_Display
|
||||||
|
PyErr_ExceptionMatches
|
||||||
|
PyErr_Fetch
|
||||||
|
PyErr_Format
|
||||||
|
PyErr_FormatV
|
||||||
|
PyErr_GetExcInfo
|
||||||
|
PyErr_GivenExceptionMatches
|
||||||
|
PyErr_NewException
|
||||||
|
PyErr_NewExceptionWithDoc
|
||||||
|
PyErr_NoMemory
|
||||||
|
PyErr_NormalizeException
|
||||||
|
PyErr_Occurred
|
||||||
|
PyErr_Print
|
||||||
|
PyErr_PrintEx
|
||||||
|
PyErr_ProgramText
|
||||||
|
PyErr_ResourceWarning
|
||||||
|
PyErr_Restore
|
||||||
|
PyErr_SetExcInfo
|
||||||
|
PyErr_SetFromErrno
|
||||||
|
PyErr_SetFromErrnoWithFilename
|
||||||
|
PyErr_SetFromErrnoWithFilenameObject
|
||||||
|
PyErr_SetFromErrnoWithFilenameObjects
|
||||||
|
PyErr_SetImportError
|
||||||
|
PyErr_SetImportErrorSubclass
|
||||||
|
PyErr_SetInterrupt
|
||||||
|
PyErr_SetNone
|
||||||
|
PyErr_SetObject
|
||||||
|
PyErr_SetString
|
||||||
|
PyErr_SyntaxLocation
|
||||||
|
PyErr_SyntaxLocationEx
|
||||||
|
PyErr_WarnEx
|
||||||
|
PyErr_WarnExplicit
|
||||||
|
PyErr_WarnFormat
|
||||||
|
PyErr_WriteUnraisable
|
||||||
|
PyEval_AcquireLock
|
||||||
|
PyEval_AcquireThread
|
||||||
|
PyEval_CallFunction
|
||||||
|
PyEval_CallMethod
|
||||||
|
PyEval_CallObjectWithKeywords
|
||||||
|
PyEval_EvalCode
|
||||||
|
PyEval_EvalCodeEx
|
||||||
|
PyEval_EvalFrame
|
||||||
|
PyEval_EvalFrameEx
|
||||||
|
PyEval_GetBuiltins
|
||||||
|
PyEval_GetFrame
|
||||||
|
PyEval_GetFuncDesc
|
||||||
|
PyEval_GetFuncName
|
||||||
|
PyEval_GetGlobals
|
||||||
|
PyEval_GetLocals
|
||||||
|
PyEval_InitThreads
|
||||||
|
PyEval_ReleaseLock
|
||||||
|
PyEval_ReleaseThread
|
||||||
|
PyEval_RestoreThread
|
||||||
|
PyEval_SaveThread
|
||||||
|
PyEval_ThreadsInitialized
|
||||||
|
PyExc_ArithmeticError
|
||||||
|
PyExc_AssertionError
|
||||||
|
PyExc_AttributeError
|
||||||
|
PyExc_BaseException
|
||||||
|
PyExc_BlockingIOError
|
||||||
|
PyExc_BrokenPipeError
|
||||||
|
PyExc_BufferError
|
||||||
|
PyExc_BytesWarning
|
||||||
|
PyExc_ChildProcessError
|
||||||
|
PyExc_ConnectionAbortedError
|
||||||
|
PyExc_ConnectionError
|
||||||
|
PyExc_ConnectionRefusedError
|
||||||
|
PyExc_ConnectionResetError
|
||||||
|
PyExc_DeprecationWarning
|
||||||
|
PyExc_EOFError
|
||||||
|
PyExc_EnvironmentError
|
||||||
|
PyExc_Exception
|
||||||
|
PyExc_FileExistsError
|
||||||
|
PyExc_FileNotFoundError
|
||||||
|
PyExc_FloatingPointError
|
||||||
|
PyExc_FutureWarning
|
||||||
|
PyExc_GeneratorExit
|
||||||
|
PyExc_IOError
|
||||||
|
PyExc_ImportError
|
||||||
|
PyExc_ImportWarning
|
||||||
|
PyExc_IndentationError
|
||||||
|
PyExc_IndexError
|
||||||
|
PyExc_InterruptedError
|
||||||
|
PyExc_IsADirectoryError
|
||||||
|
PyExc_KeyError
|
||||||
|
PyExc_KeyboardInterrupt
|
||||||
|
PyExc_LookupError
|
||||||
|
PyExc_MemoryError
|
||||||
|
PyExc_ModuleNotFoundError
|
||||||
|
PyExc_NameError
|
||||||
|
PyExc_NotADirectoryError
|
||||||
|
PyExc_NotImplementedError
|
||||||
|
PyExc_OSError
|
||||||
|
PyExc_OverflowError
|
||||||
|
PyExc_PendingDeprecationWarning
|
||||||
|
PyExc_PermissionError
|
||||||
|
PyExc_ProcessLookupError
|
||||||
|
PyExc_RecursionError
|
||||||
|
PyExc_ReferenceError
|
||||||
|
PyExc_ResourceWarning
|
||||||
|
PyExc_RuntimeError
|
||||||
|
PyExc_RuntimeWarning
|
||||||
|
PyExc_StopAsyncIteration
|
||||||
|
PyExc_StopIteration
|
||||||
|
PyExc_SyntaxError
|
||||||
|
PyExc_SyntaxWarning
|
||||||
|
PyExc_SystemError
|
||||||
|
PyExc_SystemExit
|
||||||
|
PyExc_TabError
|
||||||
|
PyExc_TimeoutError
|
||||||
|
PyExc_TypeError
|
||||||
|
PyExc_UnboundLocalError
|
||||||
|
PyExc_UnicodeDecodeError
|
||||||
|
PyExc_UnicodeEncodeError
|
||||||
|
PyExc_UnicodeError
|
||||||
|
PyExc_UnicodeTranslateError
|
||||||
|
PyExc_UnicodeWarning
|
||||||
|
PyExc_UserWarning
|
||||||
|
PyExc_ValueError
|
||||||
|
PyExc_Warning
|
||||||
|
PyExc_ZeroDivisionError
|
||||||
|
PyExceptionClass_Name
|
||||||
|
PyException_GetCause
|
||||||
|
PyException_GetContext
|
||||||
|
PyException_GetTraceback
|
||||||
|
PyException_SetCause
|
||||||
|
PyException_SetContext
|
||||||
|
PyException_SetTraceback
|
||||||
|
PyFile_FromFd
|
||||||
|
PyFile_GetLine
|
||||||
|
PyFile_WriteObject
|
||||||
|
PyFile_WriteString
|
||||||
|
PyFilter_Type
|
||||||
|
PyFloat_AsDouble
|
||||||
|
PyFloat_FromDouble
|
||||||
|
PyFloat_FromString
|
||||||
|
PyFloat_GetInfo
|
||||||
|
PyFloat_GetMax
|
||||||
|
PyFloat_GetMin
|
||||||
|
PyFloat_Type
|
||||||
|
PyFrame_GetCode
|
||||||
|
PyFrame_GetLineNumber
|
||||||
|
PyFrozenSet_New
|
||||||
|
PyFrozenSet_Type
|
||||||
|
PyGC_Collect
|
||||||
|
PyGILState_Ensure
|
||||||
|
PyGILState_GetThisThreadState
|
||||||
|
PyGILState_Release
|
||||||
|
PyGetSetDescr_Type
|
||||||
|
PyImport_AddModule
|
||||||
|
PyImport_AddModuleObject
|
||||||
|
PyImport_AppendInittab
|
||||||
|
PyImport_ExecCodeModule
|
||||||
|
PyImport_ExecCodeModuleEx
|
||||||
|
PyImport_ExecCodeModuleObject
|
||||||
|
PyImport_ExecCodeModuleWithPathnames
|
||||||
|
PyImport_GetImporter
|
||||||
|
PyImport_GetMagicNumber
|
||||||
|
PyImport_GetMagicTag
|
||||||
|
PyImport_GetModule
|
||||||
|
PyImport_GetModuleDict
|
||||||
|
PyImport_Import
|
||||||
|
PyImport_ImportFrozenModule
|
||||||
|
PyImport_ImportFrozenModuleObject
|
||||||
|
PyImport_ImportModule
|
||||||
|
PyImport_ImportModuleLevel
|
||||||
|
PyImport_ImportModuleLevelObject
|
||||||
|
PyImport_ImportModuleNoBlock
|
||||||
|
PyImport_ReloadModule
|
||||||
|
PyIndex_Check
|
||||||
|
PyInterpreterState_Clear
|
||||||
|
PyInterpreterState_Delete
|
||||||
|
PyInterpreterState_Get
|
||||||
|
PyInterpreterState_GetDict
|
||||||
|
PyInterpreterState_GetID
|
||||||
|
PyInterpreterState_New
|
||||||
|
PyIter_Check
|
||||||
|
PyIter_Next
|
||||||
|
PyIter_Send
|
||||||
|
PyListIter_Type
|
||||||
|
PyListRevIter_Type
|
||||||
|
PyList_Append
|
||||||
|
PyList_AsTuple
|
||||||
|
PyList_GetItem
|
||||||
|
PyList_GetSlice
|
||||||
|
PyList_Insert
|
||||||
|
PyList_New
|
||||||
|
PyList_Reverse
|
||||||
|
PyList_SetItem
|
||||||
|
PyList_SetSlice
|
||||||
|
PyList_Size
|
||||||
|
PyList_Sort
|
||||||
|
PyList_Type
|
||||||
|
PyLongRangeIter_Type
|
||||||
|
PyLong_AsDouble
|
||||||
|
PyLong_AsLong
|
||||||
|
PyLong_AsLongAndOverflow
|
||||||
|
PyLong_AsLongLong
|
||||||
|
PyLong_AsLongLongAndOverflow
|
||||||
|
PyLong_AsSize_t
|
||||||
|
PyLong_AsSsize_t
|
||||||
|
PyLong_AsUnsignedLong
|
||||||
|
PyLong_AsUnsignedLongLong
|
||||||
|
PyLong_AsUnsignedLongLongMask
|
||||||
|
PyLong_AsUnsignedLongMask
|
||||||
|
PyLong_AsVoidPtr
|
||||||
|
PyLong_FromDouble
|
||||||
|
PyLong_FromLong
|
||||||
|
PyLong_FromLongLong
|
||||||
|
PyLong_FromSize_t
|
||||||
|
PyLong_FromSsize_t
|
||||||
|
PyLong_FromString
|
||||||
|
PyLong_FromUnsignedLong
|
||||||
|
PyLong_FromUnsignedLongLong
|
||||||
|
PyLong_FromVoidPtr
|
||||||
|
PyLong_GetInfo
|
||||||
|
PyLong_Type
|
||||||
|
PyMap_Type
|
||||||
|
PyMapping_Check
|
||||||
|
PyMapping_GetItemString
|
||||||
|
PyMapping_HasKey
|
||||||
|
PyMapping_HasKeyString
|
||||||
|
PyMapping_Items
|
||||||
|
PyMapping_Keys
|
||||||
|
PyMapping_Length
|
||||||
|
PyMapping_SetItemString
|
||||||
|
PyMapping_Size
|
||||||
|
PyMapping_Values
|
||||||
|
PyMarshal_ReadObjectFromString
|
||||||
|
PyMarshal_WriteLongToFile
|
||||||
|
PyMarshal_WriteObjectToFile
|
||||||
|
PyMarshal_WriteObjectToString
|
||||||
|
PyMem_Free
|
||||||
|
PyMem_Malloc
|
||||||
|
PyMem_Realloc
|
||||||
|
PyMemberDescr_Type
|
||||||
|
PyMember_GetOne
|
||||||
|
PyMember_SetOne
|
||||||
|
PyMemoryView_FromMemory
|
||||||
|
PyMemoryView_FromObject
|
||||||
|
PyMemoryView_GetContiguous
|
||||||
|
PyMemoryView_Type
|
||||||
|
PyMethodDescr_Type
|
||||||
|
PyModuleDef_Init
|
||||||
|
PyModuleDef_Type
|
||||||
|
PyModule_AddFunctions
|
||||||
|
PyModule_AddIntConstant
|
||||||
|
PyModule_AddObject
|
||||||
|
PyModule_AddObjectRef
|
||||||
|
PyModule_AddStringConstant
|
||||||
|
PyModule_AddType
|
||||||
|
PyModule_Create2
|
||||||
|
PyModule_ExecDef
|
||||||
|
PyModule_FromDefAndSpec2
|
||||||
|
PyModule_GetDef
|
||||||
|
PyModule_GetDict
|
||||||
|
PyModule_GetFilename
|
||||||
|
PyModule_GetFilenameObject
|
||||||
|
PyModule_GetName
|
||||||
|
PyModule_GetNameObject
|
||||||
|
PyModule_GetState
|
||||||
|
PyModule_New
|
||||||
|
PyModule_NewObject
|
||||||
|
PyModule_SetDocString
|
||||||
|
PyModule_Type
|
||||||
|
PyNumber_Absolute
|
||||||
|
PyNumber_Add
|
||||||
|
PyNumber_And
|
||||||
|
PyNumber_AsSsize_t
|
||||||
|
PyNumber_Check
|
||||||
|
PyNumber_Divmod
|
||||||
|
PyNumber_Float
|
||||||
|
PyNumber_FloorDivide
|
||||||
|
PyNumber_InPlaceAdd
|
||||||
|
PyNumber_InPlaceAnd
|
||||||
|
PyNumber_InPlaceFloorDivide
|
||||||
|
PyNumber_InPlaceLshift
|
||||||
|
PyNumber_InPlaceMatrixMultiply
|
||||||
|
PyNumber_InPlaceMultiply
|
||||||
|
PyNumber_InPlaceOr
|
||||||
|
PyNumber_InPlacePower
|
||||||
|
PyNumber_InPlaceRemainder
|
||||||
|
PyNumber_InPlaceRshift
|
||||||
|
PyNumber_InPlaceSubtract
|
||||||
|
PyNumber_InPlaceTrueDivide
|
||||||
|
PyNumber_InPlaceXor
|
||||||
|
PyNumber_Index
|
||||||
|
PyNumber_Invert
|
||||||
|
PyNumber_Long
|
||||||
|
PyNumber_Lshift
|
||||||
|
PyNumber_MatrixMultiply
|
||||||
|
PyNumber_Multiply
|
||||||
|
PyNumber_Negative
|
||||||
|
PyNumber_Or
|
||||||
|
PyNumber_Positive
|
||||||
|
PyNumber_Power
|
||||||
|
PyNumber_Remainder
|
||||||
|
PyNumber_Rshift
|
||||||
|
PyNumber_Subtract
|
||||||
|
PyNumber_ToBase
|
||||||
|
PyNumber_TrueDivide
|
||||||
|
PyNumber_Xor
|
||||||
|
PyOS_AfterFork
|
||||||
|
PyOS_AfterFork_Child
|
||||||
|
PyOS_AfterFork_Parent
|
||||||
|
PyOS_BeforeFork
|
||||||
|
PyOS_FSPath
|
||||||
|
PyOS_InterruptOccurred
|
||||||
|
PyOS_double_to_string
|
||||||
|
PyOS_getsig
|
||||||
|
PyOS_mystricmp
|
||||||
|
PyOS_mystrnicmp
|
||||||
|
PyOS_setsig
|
||||||
|
PyOS_snprintf
|
||||||
|
PyOS_string_to_double
|
||||||
|
PyOS_strtol
|
||||||
|
PyOS_strtoul
|
||||||
|
PyOS_vsnprintf
|
||||||
|
PyObject_ASCII
|
||||||
|
PyObject_AsFileDescriptor
|
||||||
|
PyObject_Bytes
|
||||||
|
PyObject_Call
|
||||||
|
PyObject_CallFunction
|
||||||
|
PyObject_CallFunctionObjArgs
|
||||||
|
PyObject_CallMethod
|
||||||
|
PyObject_CallMethodObjArgs
|
||||||
|
PyObject_CallNoArgs
|
||||||
|
PyObject_CallObject
|
||||||
|
PyObject_Calloc
|
||||||
|
PyObject_ClearWeakRefs
|
||||||
|
PyObject_DelItem
|
||||||
|
PyObject_DelItemString
|
||||||
|
PyObject_Dir
|
||||||
|
PyObject_Format
|
||||||
|
PyObject_Free
|
||||||
|
PyObject_GC_Del
|
||||||
|
PyObject_GC_IsFinalized
|
||||||
|
PyObject_GC_IsTracked
|
||||||
|
PyObject_GC_Track
|
||||||
|
PyObject_GC_UnTrack
|
||||||
|
PyObject_GenericGetAttr
|
||||||
|
PyObject_GenericGetDict
|
||||||
|
PyObject_GenericSetAttr
|
||||||
|
PyObject_GenericSetDict
|
||||||
|
PyObject_GetAttr
|
||||||
|
PyObject_GetAttrString
|
||||||
|
PyObject_GetItem
|
||||||
|
PyObject_GetIter
|
||||||
|
PyObject_HasAttr
|
||||||
|
PyObject_HasAttrString
|
||||||
|
PyObject_Hash
|
||||||
|
PyObject_HashNotImplemented
|
||||||
|
PyObject_Init
|
||||||
|
PyObject_InitVar
|
||||||
|
PyObject_IsInstance
|
||||||
|
PyObject_IsSubclass
|
||||||
|
PyObject_IsTrue
|
||||||
|
PyObject_Length
|
||||||
|
PyObject_Malloc
|
||||||
|
PyObject_Not
|
||||||
|
PyObject_Realloc
|
||||||
|
PyObject_Repr
|
||||||
|
PyObject_RichCompare
|
||||||
|
PyObject_RichCompareBool
|
||||||
|
PyObject_SelfIter
|
||||||
|
PyObject_SetAttr
|
||||||
|
PyObject_SetAttrString
|
||||||
|
PyObject_SetItem
|
||||||
|
PyObject_Size
|
||||||
|
PyObject_Str
|
||||||
|
PyObject_Type
|
||||||
|
PyProperty_Type
|
||||||
|
PyRangeIter_Type
|
||||||
|
PyRange_Type
|
||||||
|
PyReversed_Type
|
||||||
|
PySeqIter_New
|
||||||
|
PySeqIter_Type
|
||||||
|
PySequence_Check
|
||||||
|
PySequence_Concat
|
||||||
|
PySequence_Contains
|
||||||
|
PySequence_Count
|
||||||
|
PySequence_DelItem
|
||||||
|
PySequence_DelSlice
|
||||||
|
PySequence_Fast
|
||||||
|
PySequence_GetItem
|
||||||
|
PySequence_GetSlice
|
||||||
|
PySequence_In
|
||||||
|
PySequence_InPlaceConcat
|
||||||
|
PySequence_InPlaceRepeat
|
||||||
|
PySequence_Index
|
||||||
|
PySequence_Length
|
||||||
|
PySequence_List
|
||||||
|
PySequence_Repeat
|
||||||
|
PySequence_SetItem
|
||||||
|
PySequence_SetSlice
|
||||||
|
PySequence_Size
|
||||||
|
PySequence_Tuple
|
||||||
|
PySetIter_Type
|
||||||
|
PySet_Add
|
||||||
|
PySet_Clear
|
||||||
|
PySet_Contains
|
||||||
|
PySet_Discard
|
||||||
|
PySet_New
|
||||||
|
PySet_Pop
|
||||||
|
PySet_Size
|
||||||
|
PySet_Type
|
||||||
|
PySlice_AdjustIndices
|
||||||
|
PySlice_GetIndices
|
||||||
|
PySlice_GetIndicesEx
|
||||||
|
PySlice_New
|
||||||
|
PySlice_Type
|
||||||
|
PySlice_Unpack
|
||||||
|
PyState_AddModule
|
||||||
|
PyState_FindModule
|
||||||
|
PyState_RemoveModule
|
||||||
|
PyStructSequence_GetItem
|
||||||
|
PyStructSequence_New
|
||||||
|
PyStructSequence_NewType
|
||||||
|
PyStructSequence_SetItem
|
||||||
|
PySuper_Type
|
||||||
|
PySys_AddWarnOption
|
||||||
|
PySys_AddWarnOptionUnicode
|
||||||
|
PySys_AddXOption
|
||||||
|
PySys_FormatStderr
|
||||||
|
PySys_FormatStdout
|
||||||
|
PySys_GetObject
|
||||||
|
PySys_GetXOptions
|
||||||
|
PySys_HasWarnOptions
|
||||||
|
PySys_ResetWarnOptions
|
||||||
|
PySys_SetArgv
|
||||||
|
PySys_SetArgvEx
|
||||||
|
PySys_SetObject
|
||||||
|
PySys_SetPath
|
||||||
|
PySys_WriteStderr
|
||||||
|
PySys_WriteStdout
|
||||||
|
PyThreadState_Clear
|
||||||
|
PyThreadState_Delete
|
||||||
|
PyThreadState_Get
|
||||||
|
PyThreadState_GetDict
|
||||||
|
PyThreadState_GetFrame
|
||||||
|
PyThreadState_GetID
|
||||||
|
PyThreadState_GetInterpreter
|
||||||
|
PyThreadState_New
|
||||||
|
PyThreadState_SetAsyncExc
|
||||||
|
PyThreadState_Swap
|
||||||
|
PyThread_GetInfo
|
||||||
|
PyThread_ReInitTLS
|
||||||
|
PyThread_acquire_lock
|
||||||
|
PyThread_acquire_lock_timed
|
||||||
|
PyThread_allocate_lock
|
||||||
|
PyThread_create_key
|
||||||
|
PyThread_delete_key
|
||||||
|
PyThread_delete_key_value
|
||||||
|
PyThread_exit_thread
|
||||||
|
PyThread_free_lock
|
||||||
|
PyThread_get_key_value
|
||||||
|
PyThread_get_stacksize
|
||||||
|
PyThread_get_thread_ident
|
||||||
|
PyThread_get_thread_native_id
|
||||||
|
PyThread_init_thread
|
||||||
|
PyThread_release_lock
|
||||||
|
PyThread_set_key_value
|
||||||
|
PyThread_set_stacksize
|
||||||
|
PyThread_start_new_thread
|
||||||
|
PyThread_tss_alloc
|
||||||
|
PyThread_tss_create
|
||||||
|
PyThread_tss_delete
|
||||||
|
PyThread_tss_free
|
||||||
|
PyThread_tss_get
|
||||||
|
PyThread_tss_is_created
|
||||||
|
PyThread_tss_set
|
||||||
|
PyTraceBack_Here
|
||||||
|
PyTraceBack_Print
|
||||||
|
PyTraceBack_Type
|
||||||
|
PyTupleIter_Type
|
||||||
|
PyTuple_GetItem
|
||||||
|
PyTuple_GetSlice
|
||||||
|
PyTuple_New
|
||||||
|
PyTuple_Pack
|
||||||
|
PyTuple_SetItem
|
||||||
|
PyTuple_Size
|
||||||
|
PyTuple_Type
|
||||||
|
PyType_ClearCache
|
||||||
|
PyType_FromModuleAndSpec
|
||||||
|
PyType_FromSpec
|
||||||
|
PyType_FromSpecWithBases
|
||||||
|
PyType_GenericAlloc
|
||||||
|
PyType_GenericNew
|
||||||
|
PyType_GetFlags
|
||||||
|
PyType_GetModule
|
||||||
|
PyType_GetModuleState
|
||||||
|
PyType_GetSlot
|
||||||
|
PyType_IsSubtype
|
||||||
|
PyType_Modified
|
||||||
|
PyType_Ready
|
||||||
|
PyType_Type
|
||||||
|
PyUnicodeDecodeError_Create
|
||||||
|
PyUnicodeDecodeError_GetEncoding
|
||||||
|
PyUnicodeDecodeError_GetEnd
|
||||||
|
PyUnicodeDecodeError_GetObject
|
||||||
|
PyUnicodeDecodeError_GetReason
|
||||||
|
PyUnicodeDecodeError_GetStart
|
||||||
|
PyUnicodeDecodeError_SetEnd
|
||||||
|
PyUnicodeDecodeError_SetReason
|
||||||
|
PyUnicodeDecodeError_SetStart
|
||||||
|
PyUnicodeEncodeError_GetEncoding
|
||||||
|
PyUnicodeEncodeError_GetEnd
|
||||||
|
PyUnicodeEncodeError_GetObject
|
||||||
|
PyUnicodeEncodeError_GetReason
|
||||||
|
PyUnicodeEncodeError_GetStart
|
||||||
|
PyUnicodeEncodeError_SetEnd
|
||||||
|
PyUnicodeEncodeError_SetReason
|
||||||
|
PyUnicodeEncodeError_SetStart
|
||||||
|
PyUnicodeIter_Type
|
||||||
|
PyUnicodeTranslateError_GetEnd
|
||||||
|
PyUnicodeTranslateError_GetObject
|
||||||
|
PyUnicodeTranslateError_GetReason
|
||||||
|
PyUnicodeTranslateError_GetStart
|
||||||
|
PyUnicodeTranslateError_SetEnd
|
||||||
|
PyUnicodeTranslateError_SetReason
|
||||||
|
PyUnicodeTranslateError_SetStart
|
||||||
|
PyUnicode_Append
|
||||||
|
PyUnicode_AppendAndDel
|
||||||
|
PyUnicode_AsASCIIString
|
||||||
|
PyUnicode_AsCharmapString
|
||||||
|
PyUnicode_AsDecodedObject
|
||||||
|
PyUnicode_AsDecodedUnicode
|
||||||
|
PyUnicode_AsEncodedObject
|
||||||
|
PyUnicode_AsEncodedString
|
||||||
|
PyUnicode_AsEncodedUnicode
|
||||||
|
PyUnicode_AsLatin1String
|
||||||
|
PyUnicode_AsRawUnicodeEscapeString
|
||||||
|
PyUnicode_AsUCS4
|
||||||
|
PyUnicode_AsUCS4Copy
|
||||||
|
PyUnicode_AsUTF16String
|
||||||
|
PyUnicode_AsUTF32String
|
||||||
|
PyUnicode_AsUTF8AndSize
|
||||||
|
PyUnicode_AsUTF8String
|
||||||
|
PyUnicode_AsUnicodeEscapeString
|
||||||
|
PyUnicode_AsWideChar
|
||||||
|
PyUnicode_AsWideCharString
|
||||||
|
PyUnicode_BuildEncodingMap
|
||||||
|
PyUnicode_Compare
|
||||||
|
PyUnicode_CompareWithASCIIString
|
||||||
|
PyUnicode_Concat
|
||||||
|
PyUnicode_Contains
|
||||||
|
PyUnicode_Count
|
||||||
|
PyUnicode_Decode
|
||||||
|
PyUnicode_DecodeASCII
|
||||||
|
PyUnicode_DecodeCharmap
|
||||||
|
PyUnicode_DecodeFSDefault
|
||||||
|
PyUnicode_DecodeFSDefaultAndSize
|
||||||
|
PyUnicode_DecodeLatin1
|
||||||
|
PyUnicode_DecodeLocale
|
||||||
|
PyUnicode_DecodeLocaleAndSize
|
||||||
|
PyUnicode_DecodeRawUnicodeEscape
|
||||||
|
PyUnicode_DecodeUTF16
|
||||||
|
PyUnicode_DecodeUTF16Stateful
|
||||||
|
PyUnicode_DecodeUTF32
|
||||||
|
PyUnicode_DecodeUTF32Stateful
|
||||||
|
PyUnicode_DecodeUTF7
|
||||||
|
PyUnicode_DecodeUTF7Stateful
|
||||||
|
PyUnicode_DecodeUTF8
|
||||||
|
PyUnicode_DecodeUTF8Stateful
|
||||||
|
PyUnicode_DecodeUnicodeEscape
|
||||||
|
PyUnicode_EncodeFSDefault
|
||||||
|
PyUnicode_EncodeLocale
|
||||||
|
PyUnicode_FSConverter
|
||||||
|
PyUnicode_FSDecoder
|
||||||
|
PyUnicode_Find
|
||||||
|
PyUnicode_FindChar
|
||||||
|
PyUnicode_Format
|
||||||
|
PyUnicode_FromEncodedObject
|
||||||
|
PyUnicode_FromFormat
|
||||||
|
PyUnicode_FromFormatV
|
||||||
|
PyUnicode_FromObject
|
||||||
|
PyUnicode_FromOrdinal
|
||||||
|
PyUnicode_FromString
|
||||||
|
PyUnicode_FromStringAndSize
|
||||||
|
PyUnicode_FromWideChar
|
||||||
|
PyUnicode_GetDefaultEncoding
|
||||||
|
PyUnicode_GetLength
|
||||||
|
PyUnicode_GetSize
|
||||||
|
PyUnicode_InternFromString
|
||||||
|
PyUnicode_InternImmortal
|
||||||
|
PyUnicode_InternInPlace
|
||||||
|
PyUnicode_IsIdentifier
|
||||||
|
PyUnicode_Join
|
||||||
|
PyUnicode_Partition
|
||||||
|
PyUnicode_RPartition
|
||||||
|
PyUnicode_RSplit
|
||||||
|
PyUnicode_ReadChar
|
||||||
|
PyUnicode_Replace
|
||||||
|
PyUnicode_Resize
|
||||||
|
PyUnicode_RichCompare
|
||||||
|
PyUnicode_Split
|
||||||
|
PyUnicode_Splitlines
|
||||||
|
PyUnicode_Substring
|
||||||
|
PyUnicode_Tailmatch
|
||||||
|
PyUnicode_Translate
|
||||||
|
PyUnicode_Type
|
||||||
|
PyUnicode_WriteChar
|
||||||
|
PyWeakref_GetObject
|
||||||
|
PyWeakref_NewProxy
|
||||||
|
PyWeakref_NewRef
|
||||||
|
PyWrapperDescr_Type
|
||||||
|
PyWrapper_New
|
||||||
|
PyZip_Type
|
||||||
|
Py_AddPendingCall
|
||||||
|
Py_AtExit
|
||||||
|
Py_BuildValue
|
||||||
|
Py_BytesMain
|
||||||
|
Py_CompileString
|
||||||
|
Py_DecRef
|
||||||
|
Py_DecodeLocale
|
||||||
|
Py_EncodeLocale
|
||||||
|
Py_EndInterpreter
|
||||||
|
Py_EnterRecursiveCall
|
||||||
|
Py_Exit
|
||||||
|
Py_FatalError
|
||||||
|
Py_FileSystemDefaultEncodeErrors
|
||||||
|
Py_FileSystemDefaultEncoding
|
||||||
|
Py_Finalize
|
||||||
|
Py_FinalizeEx
|
||||||
|
Py_GenericAlias
|
||||||
|
Py_GenericAliasType
|
||||||
|
Py_GetBuildInfo
|
||||||
|
Py_GetCompiler
|
||||||
|
Py_GetCopyright
|
||||||
|
Py_GetExecPrefix
|
||||||
|
Py_GetPath
|
||||||
|
Py_GetPlatform
|
||||||
|
Py_GetPrefix
|
||||||
|
Py_GetProgramFullPath
|
||||||
|
Py_GetProgramName
|
||||||
|
Py_GetPythonHome
|
||||||
|
Py_GetRecursionLimit
|
||||||
|
Py_GetVersion
|
||||||
|
Py_HasFileSystemDefaultEncoding
|
||||||
|
Py_IncRef
|
||||||
|
Py_Initialize
|
||||||
|
Py_InitializeEx
|
||||||
|
Py_IsInitialized
|
||||||
|
Py_LeaveRecursiveCall
|
||||||
|
Py_Main
|
||||||
|
Py_MakePendingCalls
|
||||||
|
Py_NewInterpreter
|
||||||
|
Py_NewRef
|
||||||
|
Py_ReprEnter
|
||||||
|
Py_ReprLeave
|
||||||
|
Py_SetPath
|
||||||
|
Py_SetProgramName
|
||||||
|
Py_SetPythonHome
|
||||||
|
Py_SetRecursionLimit
|
||||||
|
Py_SymtableString
|
||||||
|
Py_UTF8Mode
|
||||||
|
Py_VaBuildValue
|
||||||
|
Py_XNewRef
|
|
@ -744,6 +744,13 @@ regen-importlib: Programs/_freeze_importlib
|
||||||
$(UPDATE_FILE) $(srcdir)/Python/importlib_zipimport.h $(srcdir)/Python/importlib_zipimport.h.new
|
$(UPDATE_FILE) $(srcdir)/Python/importlib_zipimport.h $(srcdir)/Python/importlib_zipimport.h.new
|
||||||
|
|
||||||
|
|
||||||
|
regen-limited-abi: all
|
||||||
|
@$(MKDIR_P) $(srcdir)/Doc/data/
|
||||||
|
$(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/stable_abi.py generate $(srcdir)/Doc/data/stable_abi.dat.new
|
||||||
|
$(UPDATE_FILE) $(srcdir)/Doc/data/stable_abi.dat \
|
||||||
|
$(srcdir)/Doc/data/stable_abi.dat.new
|
||||||
|
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
# Regenerate all generated files
|
# Regenerate all generated files
|
||||||
|
|
||||||
|
@ -1900,6 +1907,9 @@ funny:
|
||||||
patchcheck: @DEF_MAKE_RULE@
|
patchcheck: @DEF_MAKE_RULE@
|
||||||
$(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/patchcheck.py
|
$(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/patchcheck.py
|
||||||
|
|
||||||
|
check-limited-abi: all
|
||||||
|
$(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/stable_abi.py check $(srcdir)/Doc/data/stable_abi.dat
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h
|
Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import pathlib
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
|
EXCLUDED_HEADERS = {
|
||||||
|
"bytes_methods.h",
|
||||||
|
"cellobject.h",
|
||||||
|
"classobject.h",
|
||||||
|
"code.h",
|
||||||
|
"compile.h",
|
||||||
|
"datetime.h",
|
||||||
|
"dtoa.h",
|
||||||
|
"frameobject.h",
|
||||||
|
"funcobject.h",
|
||||||
|
"genobject.h",
|
||||||
|
"longintrepr.h",
|
||||||
|
"parsetok.h",
|
||||||
|
"pyarena.h",
|
||||||
|
"pyatomic.h",
|
||||||
|
"pyctype.h",
|
||||||
|
"pydebug.h",
|
||||||
|
"pytime.h",
|
||||||
|
"symtable.h",
|
||||||
|
"token.h",
|
||||||
|
"ucnhash.h",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_exported_symbols(library, dynamic=False):
|
||||||
|
# Only look at dynamic symbols
|
||||||
|
args = ["nm", "--no-sort"]
|
||||||
|
if dynamic:
|
||||||
|
args.append("--dynamic")
|
||||||
|
args.append(library)
|
||||||
|
proc = subprocess.run(args, stdout=subprocess.PIPE, universal_newlines=True)
|
||||||
|
if proc.returncode:
|
||||||
|
sys.stdout.write(proc.stdout)
|
||||||
|
sys.exit(proc.returncode)
|
||||||
|
|
||||||
|
stdout = proc.stdout.rstrip()
|
||||||
|
if not stdout:
|
||||||
|
raise Exception("command output is empty")
|
||||||
|
|
||||||
|
for line in stdout.splitlines():
|
||||||
|
# Split line '0000000000001b80 D PyTextIOWrapper_Type'
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
parts = line.split(maxsplit=2)
|
||||||
|
if len(parts) < 3:
|
||||||
|
continue
|
||||||
|
|
||||||
|
symbol = parts[-1]
|
||||||
|
yield symbol
|
||||||
|
|
||||||
|
|
||||||
|
def check_library(library, abi_funcs, dynamic=False):
|
||||||
|
available_symbols = set(get_exported_symbols(library, dynamic))
|
||||||
|
missing_symbols = abi_funcs - available_symbols
|
||||||
|
if missing_symbols:
|
||||||
|
print(
|
||||||
|
f"Some symbols from the stable ABI are missing: {', '.join(missing_symbols)}"
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def generate_limited_api_symbols(args):
|
||||||
|
if hasattr(sys, "gettotalrefcount"):
|
||||||
|
print(
|
||||||
|
"Stable ABI symbols cannot be generated from a debug build", file=sys.stderr
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
library = sysconfig.get_config_var("LIBRARY")
|
||||||
|
ldlibrary = sysconfig.get_config_var("LDLIBRARY")
|
||||||
|
if ldlibrary != library:
|
||||||
|
raise Exception("Limited ABI symbols can only be generated from a static build")
|
||||||
|
available_symbols = {
|
||||||
|
symbol for symbol in get_exported_symbols(library) if symbol.startswith("Py")
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = [
|
||||||
|
file
|
||||||
|
for file in pathlib.Path("Include").glob("*.h")
|
||||||
|
if file.name not in EXCLUDED_HEADERS
|
||||||
|
]
|
||||||
|
stable_data, stable_exported_data, stable_functions = get_limited_api_definitions(
|
||||||
|
headers
|
||||||
|
)
|
||||||
|
macros = get_limited_api_macros(headers)
|
||||||
|
|
||||||
|
stable_symbols = {
|
||||||
|
symbol
|
||||||
|
for symbol in (stable_functions | stable_exported_data | stable_data | macros)
|
||||||
|
if symbol.startswith("Py") and symbol in available_symbols
|
||||||
|
}
|
||||||
|
with open(args.output_file, "w") as output_file:
|
||||||
|
output_file.write(f"# File generated by 'make regen-limited-abi'\n")
|
||||||
|
output_file.write(
|
||||||
|
f"# This is NOT an authoritative list of stable ABI symbols\n"
|
||||||
|
)
|
||||||
|
for symbol in sorted(stable_symbols):
|
||||||
|
output_file.write(f"{symbol}\n")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def get_limited_api_macros(headers):
|
||||||
|
"""Run the preprocesor over all the header files in "Include" setting
|
||||||
|
"-DPy_LIMITED_API" to the correct value for the running version of the interpreter
|
||||||
|
and extracting all macro definitions (via adding -dM to the compiler arguments).
|
||||||
|
"""
|
||||||
|
|
||||||
|
preprocesor_output_with_macros = subprocess.check_output(
|
||||||
|
sysconfig.get_config_var("CC").split()
|
||||||
|
+ [
|
||||||
|
# Prevent the expansion of the exported macros so we can capture them later
|
||||||
|
"-DSIZEOF_WCHAR_T=4", # The actual value is not important
|
||||||
|
f"-DPy_LIMITED_API={sys.version_info.major << 24 | sys.version_info.minor << 16}",
|
||||||
|
"-I.",
|
||||||
|
"-I./Include",
|
||||||
|
"-dM",
|
||||||
|
"-E",
|
||||||
|
]
|
||||||
|
+ [str(file) for file in headers],
|
||||||
|
text=True,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
target
|
||||||
|
for _, target in re.findall(
|
||||||
|
r"#define (\w+)\s*(?:\(.*?\))?\s+(\w+)", preprocesor_output_with_macros
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_limited_api_definitions(headers):
|
||||||
|
"""Run the preprocesor over all the header files in "Include" setting
|
||||||
|
"-DPy_LIMITED_API" to the correct value for the running version of the interpreter.
|
||||||
|
|
||||||
|
The limited API symbols will be extracted from the output of this command as it includes
|
||||||
|
the prototypes and definitions of all the exported symbols that are in the limited api.
|
||||||
|
|
||||||
|
This function does *NOT* extract the macros defined on the limited API
|
||||||
|
"""
|
||||||
|
preprocesor_output = subprocess.check_output(
|
||||||
|
sysconfig.get_config_var("CC").split()
|
||||||
|
+ [
|
||||||
|
# Prevent the expansion of the exported macros so we can capture them later
|
||||||
|
"-DPyAPI_FUNC=__PyAPI_FUNC",
|
||||||
|
"-DPyAPI_DATA=__PyAPI_DATA",
|
||||||
|
"-DEXPORT_DATA=__EXPORT_DATA",
|
||||||
|
"-D_Py_NO_RETURN=",
|
||||||
|
"-DSIZEOF_WCHAR_T=4", # The actual value is not important
|
||||||
|
f"-DPy_LIMITED_API={sys.version_info.major << 24 | sys.version_info.minor << 16}",
|
||||||
|
"-I.",
|
||||||
|
"-I./Include",
|
||||||
|
"-E",
|
||||||
|
]
|
||||||
|
+ [str(file) for file in headers],
|
||||||
|
text=True,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
stable_functions = set(
|
||||||
|
re.findall(r"__PyAPI_FUNC\(.*?\)\s*(.*?)\s*\(", preprocesor_output)
|
||||||
|
)
|
||||||
|
stable_exported_data = set(
|
||||||
|
re.findall(r"__EXPORT_DATA\((.*?)\)", preprocesor_output)
|
||||||
|
)
|
||||||
|
stable_data = set(
|
||||||
|
re.findall(r"__PyAPI_DATA\(.*?\)\s*\(?(.*?)\)?\s*;", preprocesor_output)
|
||||||
|
)
|
||||||
|
return stable_data, stable_exported_data, stable_functions
|
||||||
|
|
||||||
|
|
||||||
|
def check_symbols(parser_args):
|
||||||
|
with open(parser_args.stable_abi_file, "r") as filename:
|
||||||
|
abi_funcs = {
|
||||||
|
symbol
|
||||||
|
for symbol in filename.read().splitlines()
|
||||||
|
if symbol and not symbol.startswith("#")
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0
|
||||||
|
# static library
|
||||||
|
LIBRARY = sysconfig.get_config_var("LIBRARY")
|
||||||
|
if not LIBRARY:
|
||||||
|
raise Exception("failed to get LIBRARY variable from sysconfig")
|
||||||
|
ret = check_library(LIBRARY, abi_funcs)
|
||||||
|
|
||||||
|
# dynamic library
|
||||||
|
LDLIBRARY = sysconfig.get_config_var("LDLIBRARY")
|
||||||
|
if not LDLIBRARY:
|
||||||
|
raise Exception("failed to get LDLIBRARY variable from sysconfig")
|
||||||
|
if LDLIBRARY != LIBRARY:
|
||||||
|
ret |= check_library(LDLIBRARY, abi_funcs, dynamic=True)
|
||||||
|
|
||||||
|
sys.exit(ret)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Process some integers.")
|
||||||
|
subparsers = parser.add_subparsers()
|
||||||
|
check_parser = subparsers.add_parser(
|
||||||
|
"check", help="Check the exported symbols against a given ABI file"
|
||||||
|
)
|
||||||
|
check_parser.add_argument(
|
||||||
|
"stable_abi_file", type=str, help="File with the stable abi functions"
|
||||||
|
)
|
||||||
|
check_parser.set_defaults(func=check_symbols)
|
||||||
|
generate_parser = subparsers.add_parser(
|
||||||
|
"generate",
|
||||||
|
help="Generate symbols from the header files and the exported symbols",
|
||||||
|
)
|
||||||
|
generate_parser.add_argument(
|
||||||
|
"output_file", type=str, help="File to dump the symbols to"
|
||||||
|
)
|
||||||
|
generate_parser.set_defaults(func=generate_limited_api_symbols)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if "func" not in args:
|
||||||
|
parser.error("Either 'check' or 'generate' must be used")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
args.func(args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue