In this section, we explain how to configure and compile the CPython projectwith a Cextension module. We will not explain how to write a Cextension module and prefer to give you some links where you can read gooddocumentation:
Some modules in the standard library, such asdatetime orpickle,have identical implementations in C and Python; the C implementation, whenavailable, is expected to improve performance (such extension modules arecommonly referred to asaccelerator modules).
Other modules mainly implemented in Python may import a C helper extensionproviding implementation details (for instance, thecsv module usesthe internal_csv module defined inModules/_csv.c).
Extension modules can be classified into two categories:
Abuilt-in extension module is a module built and shipped withthe Python interpreter. A built-in module isstatically linkedinto the interpreter, thereby lacking a__file__ attribute.
See also
sys.builtin_module_names — names of built-in modules.
Built-in modules are built with thePy_BUILD_CORE_BUILTINmacro defined.
Ashared (ordynamic) extension module is built as a shared library(.so or.dll file) and isdynamically linked into the interpreter.
In particular, the module’s__file__ attribute contains the pathto the.so or.dll file.
Shared modules are built with thePy_BUILD_CORE_MODULEmacro defined. Using thePy_BUILD_CORE_BUILTIN macroinstead causes anImportError when importing the module.
Note
Informally, built-in extension modules can be regarded asrequiredwhile shared extension modules areoptional in the sense that theymight be supplied, overridden or disabled externally.
Usually, accelerator modules are built asshared extension modules,especially if they already have a pure Python implementation.
According toPEP 399,new extension modules MUST provide a working andtested pure Python implementation, unless a special dispensation fromtheSteering Council is given.
Assume that the standard library contains a pure Python modulefoowith the followingfoo.greet() function:
defgreet():return"Hello World!"
Instead of using the Python implementation offoo.greet(), we want touse its corresponding C extension implementation exposed in the_foomodule. Ideally, we want to modifyLib/foo.py as follows:
try:# use the C implementation if possiblefrom_fooimportgreetexceptImportError:# fallback to the pure Python implementationdefgreet():return"Hello World!"
Note
Accelerator modules shouldnever be imported directly. The convention isto mark them as private implementation details with the underscore prefix(namely,_foo in this example).
In order to incorporate the accelerator module, we need to determine:
where to update the CPython project tree with the extension module source code,
which files to modify to configure and compile the CPython project, and
whichMakefile rules to invoke at the end.
Usually, accelerator modules are added in theModules directory ofthe CPython project. If more than one file is needed for the extension module,it is more convenient to create a sub-directory inModules.
In the simplest example where the extension module consists of one file, it maybe placed inModules asModules/_foomodule.c. For a non-trivialexample of the extension module_foo, we consider the following workingtree:
Modules/_foo/_foomodule.c — the extension module implementation.
Modules/_foo/helper.h — the extension helpers declarations.
Modules/_foo/helper.c — the extension helpers implementations.
By convention, the source file containing the extension module implementationis called<NAME>module.c, where<NAME> is the name of the module thatwill be later imported (in our case_foo). In addition, the directorycontaining the implementation should also be named similarly.
#ifndef _FOO_HELPER_H#define _FOO_HELPER_H#include"Python.h"typedefstruct{/* ... */}foomodule_state;staticinlinefoomodule_state*get_foomodule_state(PyObject*module){void*state=PyModule_GetState(module);assert(state!=NULL);return(foomodule_state*)state;}/* Helper used in Modules/_foo/_foomodule.c * but implemented in Modules/_foo/helper.c. */externPyObject*_Py_greet_fast(void);#endif// _FOO_HELPER_H
Tip
Functions or data that do not need to be shared across different C sourcefiles should be declaredstatic to avoid exporting their symbols fromlibpython.
If symbols need to be exported, their names must start withPy or_Py. This can be verified bymakesmelly. For more details,please refer to the section onChanging Python’s C API.
#include"_foomodule.h"PyObject*_Py_greet_fast(void){returnPyUnicode_FromString("Hello World!");}
#include"helper.h"#include"clinic/_foomodule.c.h"/* Functions for the extension module's state */staticintfoomodule_exec(PyObject*module){// imports, static attributes, exported classes, etcreturn0;}staticintfoomodule_traverse(PyObject*m,visitprocvisit,void*arg){foomodule_state*st=get_foomodule_state(m);// call Py_VISIT() on the state attributesreturn0;}staticintfoomodule_clear(PyObject*m){foomodule_state*st=get_foomodule_state(m);// call Py_CLEAR() on the state attributesreturn0;}staticvoidfoomodule_free(void*m){(void)foomodule_clear((PyObject*)m);}/* Implementation of publicly exported functions. *//*[clinic input]module foo[clinic start generated code]*//*[clinic end generated code: output=... input=...]*//*[clinic input]foo.greet -> object[clinic start generated code]*/staticPyObject*foo_greet_impl(PyObject*module)/*[clinic end generated code: output=... input=...]*/{return_Py_greet_fast();}/* Exported module's data */staticPyMethodDeffoomodule_methods[]={// macro in 'clinic/_foomodule.c.h' after running 'make clinic'FOO_GREET_METHODDEF{NULL,NULL}};staticstructPyModuleDef_Slotfoomodule_slots[]={// 'foomodule_exec' may be NULL if the state is trivial{Py_mod_exec,foomodule_exec},{Py_mod_multiple_interpreters,Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},{Py_mod_gil,Py_MOD_GIL_NOT_USED},{0,NULL},};staticstructPyModuleDeffoomodule={PyModuleDef_HEAD_INIT,.m_name="_foo",.m_doc="some doc",// or NULL if not needed.m_size=sizeof(foomodule_state),.m_methods=foomodule_methods,.m_slots=foomodule_slots,.m_traverse=foomodule_traverse,// or NULL if the state is trivial.m_clear=foomodule_clear,// or NULL if the state is trivial.m_free=foomodule_free,// or NULL if the state is trivial};PyMODINIT_FUNCPyInit__foo(void){returnPyModuleDef_Init(&foomodule);}
Tip
Recall that thePyInit_<NAME> function must be suffixed by themodule name<NAME> used in import statements (here_foo),and which usually coincides withPyModuleDef.m_name.
Other identifiers such as those used inArgument Clinicinputs do not have such naming requirements.
Now that we have added our extension module to the CPython source tree,we need to update some configuration files in order to compile the CPythonproject on different platforms.
Modules/Setup.{bootstrap,stdlib}.in¶Depending on whether the extension module is required to get a functioninginterpreter or not, we updateModules/Setup.bootstrap.in orModules/Setup.stdlib.in. In the former case, the extensionmodule is necessarily built as a built-in extension module.
Tip
For accelerator modules,Modules/Setup.stdlib.in should bepreferred overModules/Setup.bootstrap.in.
For built-in extension modules, updateModules/Setup.bootstrap.inby adding the following line after the*static* marker:
*static*..._foo _foo/_foomodule.c _foo/helper.c...The syntax is<NAME><SOURCES> where<NAME> is the name of themodule used inimport statements and<SOURCES> is the listof space-separated source files.
For other extension modules, updateModules/Setup.stdlib.inby adding the following line after the*@MODULE_BUILDTYPE@* markerbut before the*shared* marker:
*@MODULE_BUILDTYPE@*...@MODULE__FOO_TRUE@_foo _foo/_foomodule.c _foo/helper.c...*shared*The@MODULE_<NAME_UPPER>_TRUE@<NAME> marker expects<NAME_UPPER> tobe the upper-cased form of<NAME>, where<NAME> has the same meaningas before (in our case,<NAME_UPPER> and<NAME> are_FOO and_foo respectively). The marker is followed by the list of source files.
If the extension module must be built as ashared module, put the@MODULE__FOO_TRUE@_foo line after the*shared* marker:
...*shared*...@MODULE__FOO_TRUE@_foo _foo/_foomodule.c _foo/helper.cLocate theSRCDIRS variable and add the following line:
AC_SUBST([SRCDIRS])SRCDIRS="\...Modules/_foo \..."Note
This step is only needed when adding new source directories tothe CPython project.
Find the section containingPY_STDLIB_MOD andPY_STDLIB_MOD_SIMPLEusages and add the following line:
dnl always enabled extension modules...PY_STDLIB_MOD_SIMPLE([_foo], [-I\$(srcdir)/Modules/_foo], [])...ThePY_STDLIB_MOD_SIMPLE macro takes as arguments:
the module name<NAME> used inimport statements,
the compiler flags (CFLAGS), and
the linker flags (LDFLAGS).
If the extension module may not be enabled or supported depending on thehost configuration, use thePY_STDLIB_MOD macro instead, which takesas arguments:
the module name<NAME> used inimport statements,
a boolean indicating whether the extension isenabled or not,
a boolean indicating whether the extension issupported or not,
the compiler flags (CFLAGS), and
the linker flags (LDFLAGS).
For instance, enabling the_foo extension on Linux platforms, butonly providing support for 32-bit architecture, is achieved as follows:
PY_STDLIB_MOD([_foo], [test "$ac_sys_system" = "Linux"], [test "$ARCH_RUN_32BIT" = "true"], [-I\$(srcdir)/Modules/_foo], [])
More generally, the host’s configuration status of the extension isdetermined as follows:
Enabled | Supported | Status |
|---|---|---|
true | true | yes |
true | false | missing |
false | true or false | disabled |
The extension status isn/a if the extension is marked unavailableby thePY_STDLIB_MOD_SET_NA macro. To mark an extension as unavailable,find the usages ofPY_STDLIB_MOD_SET_NA inconfigure.ac andadd the following line:
dnl Modules that are not available on some platformsAS_CASE([$ac_sys_system], ... [PLATFORM_NAME], [PY_STDLIB_MOD_SET_NA([_foo])], ...)Tip
Consider reading the comments and configurations for existing modulesinconfigure.ac for guidance on adding new external builddependencies for extension modules that need them.
If needed, add the following line to the section for module dependencies:
########################################################################### Module dependencies and platform-specific files...MODULE__FOO_DEPS=$(srcdir)/Modules/_foo/helper.h...TheMODULE_<NAME_UPPER>_DEPS variable follows the same namingrequirements as the@MODULE_<NAME_UPPER>_TRUE@<NAME> marker.
We describe the minimal steps for compiling on Windows using MSVC.
UpdatePC/config.c:
...// add the entry point prototypeexternPyObject*PyInit__foo(void);...// update the entry points tablestruct_inittab_PyImport_Inittab[]={...{"_foo",PyInit__foo},...{0,0}};...
Each item in_PyImport_Inittab consists of the module name to import,here_foo, with the correspondingPyInit_* function correctlysuffixed.
UpdatePCbuild/pythoncore.vcxproj:
<!-- group with header files ..\Modules\<MODULE>.h --><ItemGroup>...<ClIncludeInclude="..\Modules\_foo\helper.h"/>...</ItemGroup><!-- group with source files ..\Modules\<MODULE>.c --><ItemGroup>...<ClCompileInclude="..\Modules\_foo\_foomodule.c"/><ClCompileInclude="..\Modules\_foo\helper.c"/>...</ItemGroup>
UpdatePCbuild/pythoncore.vcxproj.filters:
<!-- group with header files ..\Modules\<MODULE>.h --><ItemGroup>...<ClIncludeInclude="..\Modules\_foo\helper.h"><Filter>Modules\_foo</Filter></ClInclude>...</ItemGroup><!-- group with source files ..\Modules\<MODULE>.c --><ItemGroup>...<ClCompileInclude="..\Modules\_foo\_foomodule.c"><Filter>Modules\_foo</Filter></ClCompile><ClCompileInclude="..\Modules\_foo\helper.c"><Filter>Modules\_foo</Filter></ClCompile>...<ItemGroup>
Tip
Header files use<ClInclude> tags, whereassource files use<ClCompile> tags.
Now that the configuration is in place, it remains to compile the project:
makeregen-configure./configuremakeregen-allmakeregen-stdlib-module-namesmake
Tip
Usemake-jN to speed-up compilation by utilizing as many CPU coresas possible, whereN is as many CPU cores you want to spare (and havememory for). Be careful usingmake-j with no argument, as this putsno limit on the number of jobs, and compilation can sometimes use up alot of memory (like when building with LTO).
makeregen-configure updates theconfigure script.
Theconfigure script must be generated using a specific versionofautoconf. To that end, theTools/build/regen-configure.shscript which theregen-configure rule is based on either requires Dockeror Podman, the latter being assumed by default.
Tip
We recommend installingPodmaninstead of Docker since the former does not require a background serviceand avoids creating files owned by theroot user in some cases.
makeregen-all is responsible for regenerating header files andinvoking other scripts, such asArgument Clinic.Execute this rule if you do not know which files should be updated.
makeregen-stdlib-module-names updates the standard module names, making_foo discoverable and importable viaimport_foo.
The finalmake step is generally not needed since the previousmakeinvocations may completely rebuild the project, but it could be needed insome specific cases.
This section addresses common issues that you may face when followingthis example of adding an extension module.
regen-configure¶This usually happens after runningmakedistclean (which removestheMakefile). The solution is to regenerate theconfigurescript as follows:
./configure# for creating the 'Makefile' filemakeregen-configure# for updating the 'configure' script./configure# for updating the 'Makefile' file
If missing, theconfigure script can be regeneratedby executingTools/build/regen-configure.sh:
./Tools/build/regen-configure.sh# create an up-to-date 'configure'./configure# create an up-to-date 'Makefile'
makeregen-configure and missing permissions with Docker¶If Docker complains about missing permissions, this Stack Overflow postcould be useful in solving the issue:How to fix docker: permission denied. Alternatively, you may tryusingPodman.
Py_BUILD_CORE define when using internal headers¶By default, the CPythonStable ABI is exposed via#include"Python.h". In some cases, this may be insufficientand internal headers fromInclude/internal are needed;in particular, those headers require thePy_BUILD_COREmacro to be defined.
To that end, one should define thePy_BUILD_CORE_BUILTINor thePy_BUILD_CORE_MODULE macro depending on whether theextension module is built-in or shared. Using either of the two macrosimpliesPy_BUILD_CORE and gives access to CPython internals:
Py_BUILD_CORE_BUILTIN¶#ifndef Py_BUILD_CORE_MODULE# define Py_BUILD_CORE_BUILTIN 1#endif
Py_BUILD_CORE_MODULE¶#ifndef Py_BUILD_CORE_BUILTIN# define Py_BUILD_CORE_MODULE 1#endif
In this section, we give some tips for improving the quality ofextension modules meant to be included in the standard library.
In order for non-CPython implementations to benefit from new extension modules,it is recommended to use theLimited API. Instead ofexposing the entire Stable ABI, define thePy_LIMITED_API macrobefore the#include"Python.h" directive:
#include"pyconfig.h" // Py_GIL_DISABLED#ifndef Py_GIL_DISABLED# define Py_LIMITED_API 0x030d0000#endif#include"Python.h"
This makes the extension module non-CPython implementation-friendly byremoving the dependencies to CPython internals.