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
|
||||
- name: Check exported libpython symbols
|
||||
run: make smelly
|
||||
- name: Check limited ABI symbols
|
||||
run: make check-limited-abi
|
||||
|
||||
build_win32:
|
||||
name: 'Windows (x86)'
|
||||
|
|
|
@ -192,6 +192,8 @@ script:
|
|||
- 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"
|
||||
- make smelly
|
||||
# Check that all symbols in the limited abi are present
|
||||
- make check-limited-abi
|
||||
# `-r -w` implicitly provided through `make buildbottest`.
|
||||
- |
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
@ -1900,6 +1907,9 @@ funny:
|
|||
patchcheck: @DEF_MAKE_RULE@
|
||||
$(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
|
||||
|
||||
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