Build cpython from scratch

I am currently working on building a minimal CPython interpreter using Meson to gain better control over static linking and potentially exchange implementation details. One idea is to create something akin to bun/deno but for CPython, where specific native code is implemented and bundled/ or solve the issue pyo3, many options seem interesting once building CPython was much easier.

I’ve shared the issue on the Meson WrapDB repo, and also on the buck2 issue tracker (re hermetic builds) hoping to nerd-snipe someone into this. I’m reaching out to your expertise to seek guidance in understanding the build process better.

Conceptually, building CPython from a few C files or generating some code should not be overly challenging. I’ve managed to put together a basic setup that gets me as far as running the following command:

meson compile -C builddir && ./builddir/Programs/python3

However, I’ve encountered a hurdle with the Python path configuration, resulting in the following error:

$ meson compile -C builddir && ./builddir/Programs/python3                                                                                                                                                         

INFO: autodetecting backend as ninja
INFO: calculating backend command to run: /opt/homebrew/bin/ninja -C /Users/benediktmandelkow/Downloads/cpython/builddir
ninja: Entering directory `/Users/benediktmandelkow/Downloads/cpython/builddir'
ninja: no work to do.
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = './builddir/Programs/python3'
  isolated = 0
  environment = 1
  user site = 1
  safe_path = 0
  import site = 1
  is in build tree = 0
  stdlib dir = '/Users/benediktmandelkow/Downloads/cpython/Lib/python3.13'
  sys.path[0] = (not set)
  sys._base_executable = '/Users/benediktmandelkow/Downloads/cpython/builddir/Programs/python3'
  sys.base_prefix = '/Users/benediktmandelkow/Downloads/cpython/Lib'
  sys.base_exec_prefix = '/Users/benediktmandelkow/Downloads/cpython/Lib'
  sys.platlibdir = '/Users/benediktmandelkow/Downloads/cpython/Lib'
  sys.executable = '/Users/benediktmandelkow/Downloads/cpython/builddir/Programs/python3'
  sys.prefix = '/Users/benediktmandelkow/Downloads/cpython/Lib'
  sys.exec_prefix = '/Users/benediktmandelkow/Downloads/cpython/Lib'
  sys.path = [
    '/Users/benediktmandelkow/Downloads/cpython/Lib/python313.zip',
    '/Users/benediktmandelkow/Downloads/cpython/Lib/python3.13',
    '/Users/benediktmandelkow/Downloads/cpython/Lib/python3.13/lib-dynload',
  ]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

Current thread 0x00000001dd501000 (most recent call first):
  <no Python frame>

If you have experience with the Python build process and could help me create a minimal example, I would greatly appreciate your support. I believe that with your expertise, we can put together a straightforward and understandable build system for a minimal working Python interpreter which is easy to hack on.

(As an aside, every complex build system is there for some reason, I don’t want to say that CPython should adapt meson or sth. like that, just that a minimal example of building CPython would really help adopting it in some areas/ creative ways)

Feel free to check the GitHub repo for the actual code meson_build

Kind regards

Have you tried to build cpython using its build system?

I would assume when that works you have something to compare your meson build against.

Have you tried to build cpython using its build system?

Thats how I got pyconfig.h actually but other than that I’m not sure what to compare/ how to deduce the build steps the best way. For generating code for freezing the modules the comments were quite helpful but now I feel like to get further I’d need a much better understanding of the codebase or ask for help here.

I tried to trace the function calls of some initialisation routines but they were fairly deep so I did not manage to fully understand the procedures yet (not enough to remove/ deactivate them as much as possible).

A MVP would be a python interpreter which could just calculate 3 + 4 or print(“hello”), I’d be fine with excluding as much of the std as possible as I’d probably like to add needed functions using pyo3 and native implementations as one example.

Compiling to wasm-unknown-unknown (no emscripten) should also be trivial then which is currently not really that well documented as far as I can see.