Windows で Python C 拡張をビルドする 2026:MSVC、Windows SDK、pyproject.toml、Wheel

メンテナンス層(2026-09-01 確認)。 このガイドは、現在サポートされている CPython、PyPA、setuptools、Microsoft ツールチェーンの手順に沿っています。末尾には 2019 年のエクスポート全文を原文のまま保存しました。当時 Visual C++ 2017 の導入で問題が解消したという結果は過去の環境に関するものであり、提示された Windows 10 SDK による修正は著者自身が未検証だったことを明記しています。

Windows の CPython C 拡張は通常 .pyd ファイルにコンパイルされます。ビルドを成功させるには、Python インタープリター、そのアーキテクチャと ABI、適切な MSVC ツールチェーン、Windows SDK/UCRT のヘッダーとライブラリという四つの要素が一致しなければなりません。現代のプロジェクトでは PEP 517 ビルドバックエンドを pyproject.toml で宣言し、python -m build または python -m pip install . を使います。python setup.py をコマンドラインのビルドツールとして直接実行する方法は非推奨です。

何をビルドするのか確認する

Python C API は CPython 固有です。既存の C ライブラリを呼び出したいだけなら、まず ctypes またはバインディング生成器のほうが適切ではないか検討してください。CPython API への直接アクセス、独自 Python 型、非常に密接な統合が必要な場合には、手書きの拡張が適しています。

この記事では、Windows 向け公式 CPython リリースでサポートされる Microsoft コンパイラの経路を扱います。CPython インタープリター自体のコンパイル、Linux からのクロスコンパイル、MinGW で作ったオブジェクトと MSVC ベースの Python ランタイムの混在は対象外です。

ツールを入れる前にターゲットを決める

ビルド前に、正確なインタープリターとターゲットアーキテクチャを記録します。

where.exe python
python -c "import platform, struct, sys; print(sys.executable); print(sys.version); print(platform.machine()); print(8 * struct.calcsize('P'), 'bit')"
python -m pip --version

ビルドとテストには同じインタープリターコマンドを使います。64 ビット x64 Python には x64 をターゲットにするツールチェーンが必要です。Windows ARM64 と 32 ビット Python はそれぞれ別のターゲットです。通常の CPython 拡張 Wheel は Python/ABI タグにも結び付いています。ただし、プロジェクトが Limited API と Stable ABI を意図的かつ正しく採用している場合を除きます。

OS だけを見て互換性を推測しないでください。where.exe python には、Microsoft Store のエイリアス、Conda 環境、仮想環境、または PATH 上で先に見つかる別のインストールが表示されることがあります。

MSVC と Windows SDK をインストールする

Visual Studio Installer または Microsoft C++ Build Tools を使い、次を選択します。

  • C++ によるデスクトップ開発
  • 現在サポートされている MSVC C++ x64/x86 ビルドツールのコンポーネント
  • Universal CRT のヘッダーとライブラリを提供する、現在の Windows SDK

ツールセットと SDK の正確なコンポーネント番号は時間とともに変わります。古いビルドログの番号をそのままコピーせず、インストーラーが現在提示するサポート対象コンポーネントを選んでください。

インストール後は Developer PowerShell for Visual Studio、またはインタープリターのアーキテクチャをターゲットにするネイティブ/クロスツール用コマンドプロンプトを開きます。MSVC では PATHINCLUDELIBLIBPATH を整合させる必要があるため、Microsoft はこれらの準備済み shell を推奨しています。環境変数を手作業で恒久設定しないでください。

一貫した一つのビルド Shell を検証する

開発者 shell でプロジェクトディレクトリへ移動し、有効なツールを調べます。

where.exe python
where.exe cl
where.exe link
cl /Bv
python -c "import sys, sysconfig; print('base:', sys.base_prefix); print('include:', sysconfig.get_paths()['include']); print('EXT_SUFFIX:', sysconfig.get_config_var('EXT_SUFFIX'))"
$env:INCLUDE -split ';'

cl /Bv はコンパイラの詳細を表示します。Python の include ディレクトリは、where.exe python が示す同じインタープリターに属している必要があります。開発者 shell の INCLUDE には、MSVC と Windows SDK のパス、およびバージョン付き UCRT ディレクトリが含まれているはずです。

Setuptools は Visual Studio を自動検出できることが多いものの、開発者 shell を使うとアーキテクチャや SDK 不足の問題を診断しやすくなります。Conda を使う場合は、同じ shell で対象環境を有効化し、すべての確認をやり直してください。

最小プロジェクトを作る

新しいディレクトリに次の構成を作ります。

hello-extension/
├── pyproject.toml
└── src/
    └── hello.c

ディストリビューション名は hello-extension-example、import 可能な拡張モジュール名は hello です。この二つは異なっても構いませんが、Extension 名、C の初期化シンボル、Python の import 名は互いに一致しなければなりません。

C 拡張を書く

src/hello.c を作成します。

#define PY_SSIZE_T_CLEAN
#include <Python.h>

static PyObject *
hello_add(PyObject *self, PyObject *args)
{
    PyObject *left;
    PyObject *right;

    (void)self;

    if (!PyArg_ParseTuple(args, "OO:add", &left, &right)) {
        return NULL;
    }

    return PyNumber_Add(left, right);
}

static PyMethodDef hello_methods[] = {
    {"add", hello_add, METH_VARARGS, PyDoc_STR("Return left + right.")},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef hello_module = {
    PyModuleDef_HEAD_INIT,
    "hello",
    "Minimal CPython extension example.",
    -1,
    hello_methods
};

PyMODINIT_FUNC
PyInit_hello(void)
{
    return PyModule_Create(&hello_module);
}

Python.h は、CPython の定義による影響を受け得るシステムヘッダーより先に include する必要があります。PyMODINIT_FUNC は必要なエクスポート/リンケージ宣言を提供し、関数名 PyInit_hello は import 名 hello と一致します。

この例では二つの Python オブジェクトを PyNumber_Add に渡すので、エラーは通常の Python 例外として伝播します。意図的に小さな例にしています。実運用の拡張では、所有権、エラー処理、モジュール状態、サブインタープリター方針、自由スレッドビルド方針も明確にする必要があります。

pyproject.toml でビルドを宣言する

pyproject.toml を作成します。

[build-system]
requires = ["setuptools>=74.1"]
build-backend = "setuptools.build_meta"

[project]
name = "hello-extension-example"
version = "0.1.0"
description = "Minimal CPython C extension example"
requires-python = ">=3.9"

[tool.setuptools]
ext-modules = [
  {name = "hello", sources = ["src/hello.c"]}
]

この下限は、setuptools が pyproject.toml 内での拡張モジュール宣言をサポートするために必要です。ビルド分離では宣言されたバックエンドが一時環境へインストールされますが、システムツールである MSVC や Windows SDK はインストールされません。

setup.py を setuptools の設定ファイルとして使うこと自体は引き続きサポートされていますが、python setup.py buildinstallbdist_wheel を直接実行する方法は非推奨です。ビルドフロントエンドを優先してください。

ビルド、インストール、テスト

プロジェクトルートの Developer PowerShell で実行します。

python -m venv .venv
..venvScriptsActivate.ps1
python -m pip install --upgrade pip build
python -m build
Get-ChildItem .dist*.whl
$wheel = Get-ChildItem .dist*.whl | Sort-Object LastWriteTime | Select-Object -Last 1
python -m pip install --force-reinstall $wheel.FullName
python -c "import hello; print(hello.add(2, 3)); print(hello.__file__)"

計算結果として 5 が表示され、続いてインストールされた .pyd のパスが表示されるのが期待値です。デフォルトの python -m build は sdist を作成し、その sdist から Wheel をビルドします。そのため、C ソースがソース配布物に含まれているかも確認できます。

ローカルソースをすばやくインストールするだけなら、次も有効です。

python -m pip install .

リリース成果物を検証するときは、新しい仮想環境とクリーンなチェックアウトを使い、ログに出る Python、pip、ビルドバックエンド、コンパイラ、SDK のバージョンを記録します。

Wheel と ABI の適用範囲を理解する

Wheel のファイル名には Python、ABI、プラットフォームの互換性タグが含まれます。通常の Windows 拡張ビルドでは cp314-cp314-win_amd64.whl のような末尾になる場合があります。正確なタグはインタープリターとターゲットに依存します。

インストールを通すために Wheel タグを改名したり、Python の異なるバージョン間で .pyd をコピーしたりしないでください。サポートするターゲットごとにビルドとテストを行うか、CPython Limited API を意図的に採用して abi3 Wheel を設定します。Limited API のソース設定と Wheel のタグ付けは別々の判断であり、両方を正しく行う必要があります。

自由スレッド版 CPython も明示的に別のターゲットです。拡張側の変更と個別にタグ付けされた Wheel が必要であり、通常ビルドが成功しただけで自由スレッド対応を宣言してはいけません。

複数の Python バージョンと Windows アーキテクチャにまたがるリリースマトリクスには、分離された CI ランナー(一般には PyPA の cibuildwheel)を使い、ソースツリーから直接 import するのではなく、インストール後の Wheel をテストします。

Unable to find vcvarsall.bat を直す

このメッセージは、多くの場合、古い distutils 時代の検出処理または不完全なコンパイラのインストールに関連します。現在の対応手順は次のとおりです。

  1. プロジェクトが使用中の Python バージョンをサポートしているか確認する。
  2. プロジェクトのサポート範囲内でビルドフロントエンド/バックエンドを更新する。
  3. 現在の Microsoft C++ Build Tools をインストールまたは変更し、C++ ワークロードと Windows SDK を追加する。
  4. 正しい Developer PowerShell またはネイティブツール用プロンプトを開く。
  5. where.exe clcl /Bv、インタープリター、アーキテクチャをもう一度確認する。

出所の不明な vcvarsall.bat をダウンロードしたり、別の Visual Studio リリースからコピーしたり、推測したコンパイラパスをグローバル環境へ恒久的に追加したりしないでください。メンテナンスされていないパッケージが古いコンパイラをハードコードしている場合は、現行リリースを使う、ビルド設定を修正する、または意図的に分離したレガシー環境でビルドしてください。現在のマシンの整合性を崩すべきではありません。

Visual C++ 2017 のインストールでこのエラーが消えたという 2019 年の観察は、当時の環境に関する事実としてアーカイブに残します。2026 年のツールチェーン指定ではありません。

見つからない io.h または Python.h を直す

io.h は Windows SDK が提供する Universal CRT ヘッダーに含まれます。Developer PowerShell で環境とインストール済みヘッダーを確認します。

$env:INCLUDE -split ';'
Get-ChildItem "${env:ProgramFiles(x86)}Windows Kits10Include" -Filter io.h -Recurse | Select-Object -First 5 FullName
python -c "import sysconfig; print(sysconfig.get_paths()['include'])"

io.h が存在しない場合は、Visual Studio/Build Tools のインストールを変更し、サポート対象の Windows SDK を追加します。存在するのにコンパイラから見えない場合は、適切な開発者 shell を使って INCLUDE を確認してください。ヘッダーを Python ディレクトリへコピーしてはいけません。

Python.h が見つからない場合は、まず正確なインタープリターと、その sysconfig include ディレクトリを確認します。一つの Python インストールのヘッダーと別のインストールのライブラリを混ぜないでください。対象 Python ディストリビューションの開発ファイルが不完全なら、再インストールまたは修復します。

リンクと Import の失敗を診断する

  • LNK1112 またはマシンタイプの競合: Python、コンパイル済みオブジェクト、リンカーが異なるアーキテクチャをターゲットにしています。正しいネイティブ/クロスツール shell を開き直し、すべて再ビルドしてください。
  • *python3XY.lib がない、または Py シンボルが未解決:** 誤った Python ライブラリディレクトリ、アーキテクチャ、デバッグ/リリースの組み合わせが使われています。sysconfig、インタープリターの出所、古い成果物を再確認します。
  • ImportError: dynamic module does not define module export function (PyInit_...) setuptools の拡張名と PyInit_name シンボルが一致していません。
  • ImportError: DLL load failed 依存 DLL がないか、互換性がありません。インストールされた .pyd の場所を特定し、開発者 shell から dumpbin /dependents pathtohello.pyd で調べます。
  • Wheel が非対応として拒否される: Python、ABI、プラットフォームのタグがインストーラーの対応タグと一致しません。そのターゲット向けにビルドし、ファイル名を変えてはいけません。

失敗を報告するときは、最後の「command failed」行だけでなく、コンパイラまたはリンカーの最初の完全なエラーを含めてください。上記のインタープリター、コンパイラ、アーキテクチャ、ビルドバックエンドの確認結果も添えます。公開する場合は、あらかじめ私的なパスを取り除いてください。

リリース前チェックリスト

Wheel を配布する前に、次を確認します。

  • クリーンなチェックアウトから分離環境でビルドする。
  • sdist と Wheel をビルドし、生成された Wheel を新しい環境へインストールする。
  • インストール済み成果物に対して import テストと機能テストを実行する。
  • 対応を表明するすべての Python、ABI、Windows アーキテクチャのターゲットをテストする。
  • sdist に必要な C ソース、ヘッダー、ライセンス、生成ファイルがすべて入っていることを確認する。
  • 外部 DLL の依存関係と再配布条件を調べる。
  • ローカルの絶対パス、認証情報、ビルドマシン情報を埋め込まない。
  • CI から最小権限の認証情報で公開し、信頼できないビルド工程から分離する。

ローカルで成功しても、確認できるのは現在のインタープリター/ツールチェーンの組み合わせだけです。一つの Wheel が別の Python バージョン、自由スレッドビルド、win32、x64、ARM64 に対応することの証明にはなりません。

一次公式ドキュメント

---

2019 年オリジナルエクスポート(原文のまま)

以下はメタデータと本文を含むオリジナルエクスポートの全文です。2019-04-23 に公開され、2 秒後に最終更新されました。著者は Visual C++ 2017 の導入で最初のエラーが消えたと報告する一方、提示した Windows 10 SDK による修正は試していないと明記しています。このアーカイブ内では表現も句読点も修正していません。

---
id: 1900
title: 'Compile C Extension of Python on Windows'
slug: 'compile-c-extension-of-python-on-windows'
date: '2019-04-23T12:51:39'
modified: '2019-04-23T12:51:41'
status: 'publish'
link: 'https://blog.lazying.art/en/html/computer_internet/python/1900/compile-c-extension-of-python-on-windows.html'
author: 'Lachlan Chen'
categories:
  - 'Python'
---

Unable to find vcvarsall.bat

I installed Visual C++ 2017 and the error get eliminated

c:miniconda3includepyconfig.h(59): fatal error C1083: Cannot open include file: ‘io.h’: No such file or directory

Installing Windows 10 SDK can solve this problem. But I have’t tried.

Leave a Reply