| name | build |
| description | Use this skill when you need to compile CPython, run tests, verify your changes work, check if a fix is correct, or debug test failures. Covers building from source with ./configure and make, ccache for faster rebuilds, Argument Clinic regeneration, and the unittest-based test system (NOT pytest). Essential for any task that requires running code or tests. |
Building and Testing CPython
Building CPython
ONLY build in a build/ subdirectory at repo root. Never build in the source tree.
Setup and Configuration
REPO_ROOT=<path-to-cpython-git-repo>
BUILD_DIR=$REPO_ROOT/build
$BUILD_DIR, $BUILT_PY, and $NCPU throughout this skill (and the style and jit skills) are placeholders, not persistent shell state. Each Bash invocation starts a fresh shell, so substitute the concrete values into every command you run — e.g. make -C build patchcheck, not make -C $BUILD_DIR patchcheck in a shell where the variable was never set.
Determine CPU Count
Run nproc (Linux) or sysctl -n hw.ncpu (macOS) to get the number of CPU cores.
Avoid $(nproc) or $(sysctl -n hw.ncpu) command substitution inside other commands — embedded substitutions make commands harder for the user to audit and can trigger extra permission prompts. Read the output once and use the literal number:
NCPU=<number from nproc or sysctl output>
ccache Setup (Recommended)
ccache dramatically speeds up rebuilds by caching compilation results. Check if available:
which ccache
If ccache is not installed:
- macOS (Homebrew): Install directly with
brew install ccache (no sudo required)
- Containerized/root environments: Install directly with
apt-get install -y ccache or dnf install -y ccache
- Otherwise, ask the user for permission to install:
- Debian/Ubuntu:
sudo apt-get install ccache
- Fedora/RHEL:
sudo dnf install ccache
Configure with ccache (if available):
cd $BUILD_DIR && CC="ccache gcc" ../configure --with-pydebug
Configure without ccache (fallback):
cd $BUILD_DIR && ../configure --with-pydebug
Performance/Benchmarking Builds
When doing benchmarking or performance measurement of C code changes, omit --with-pydebug from configure:
cd $BUILD_DIR && CC="ccache gcc" ../configure
Debug builds have significant overhead that distorts performance measurements. However, do not use --enable-optimizations unless explicitly asked—it enables PGO (Profile-Guided Optimization) which is slow to compile. Non-PGO release builds are sufficient for the majority of performance comparison work.
make -C $BUILD_DIR -j $NCPU
Platform notes:
- Linux:
BUILT_PY=$BUILD_DIR/python
- macOS:
BUILT_PY=$BUILD_DIR/python.exe (note .exe extension)
- Windows: Ask user how to build (uses Visual Studio, different process)
Argument Clinic
After editing .c files that change function signatures, docstrings, or argument specs:
make -C $BUILD_DIR clinic
NEVER edit files in **/clinic/** subdirectories - they're auto-generated.
Other Regeneration Targets
Clinic is one of several generated-source families. When you edit a source-of-truth file, rerun its generator rather than hand-editing the output — CI's make regen-all consistency check fails on hand-merged generated files:
make regen-cases — after editing Python/bytecodes.c (interpreter/uop definitions)
make regen-all — regenerates everything; slower, but the safe catch-all
make -C $BUILD_DIR regen-jit — JIT stencils (see the jit skill)
Verify Build
$BUILT_PY --version
$BUILT_PY -c "print('Hello from CPython!')"
Build Troubleshooting
- Missing dependencies: Configure reports missing libraries
- Stale build:
make clean in BUILD_DIR and rebuild
- Clinic files out of sync:
make -C $BUILD_DIR clinic
- Clean build:
rm -rf $BUILD_DIR && mkdir $BUILD_DIR && cd $BUILD_DIR && CC="ccache gcc" ../configure --with-pydebug && make -j $NCPU (omit CC=... if ccache unavailable)
Running CPython Tests
Critical rules:
- NEVER use
python, python3, or any Python from $PATH - always use $BUILT_PY (the locally-built interpreter). The system Python won't have your changes.
- NEVER use
pytest - CPython tests are unittest based
- Use
--match not -k for filtering - takes a glob pattern (this is not pytest!)
Prerequisite: BUILT_PY=build/python or build/python.exe
Running Tests
$BUILT_PY -m test test_zipfile -j $NCPU
$BUILT_PY -m test test_csv test_json -j $NCPU
$BUILT_PY Lib/test/test_csv.py
$BUILT_PY -m test test_zipfile --match "*large*" -j $NCPU
$BUILT_PY -m test test_csv --match "TestDialect*"
$BUILT_PY -m test test_json --match "TestEncode.test_encode_string"
make -C $BUILD_DIR test
Test packages (directories like test_asyncio/) require load_tests() in __init__.py to work with python -m test.
Code Coverage
$BUILT_PY -m test --coverage test_csv test_json --coveragedir .claude/coverage/ -j $NCPU
Debugging
Add breakpoint() in test code, then run the test with -v for verbose output.