3.4.4. C extensions
Some C extensions are built as built-in modules, like the sys module. They are built with the Py_BUILD_CORE_BUILTIN macro defined. Built-in modules have no __file__ attribute:
>>> import sys
>>> sys
<module 'sys' (built-in)>
>>> sys.__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute '__file__'
Other C extensions are built as dynamic libraries, like the _asyncio module. They are built with the Py_BUILD_CORE_MODULE macro defined. Example on Linux x86-64:
>>> import _asyncio
>>> _asyncio
<module '_asyncio' from '/usr/lib64/python3.9/lib-dynload/_asyncio.cpython-39-x86_64-linux-gnu.so'>
>>> _asyncio.__file__
'/usr/lib64/python3.9/lib-dynload/_asyncio.cpython-39-x86_64-linux-gnu.so'
Modules/Setup is used to generate Makefile targets to build C extensions. At the beginning of the files, C extensions are built as built-in modules. Extensions defined after the *shared* marker are built as dynamic libraries.
The PyAPI_FUNC(), PyAPI_DATA() and PyMODINIT_FUNC macros of Include/exports.h are defined differently depending if the Py_BUILD_CORE_MODULE macro is defined:
- Use
Py_EXPORTED_SYMBOL if the Py_BUILD_CORE_MODULE is defined - Use
Py_IMPORTED_SYMBOL otherwise.
If the Py_BUILD_CORE_BUILTIN macro is used by mistake on a C extension built as a shared library, its PyInit_xxx() function is not exported, causing an ImportError on import.