Skip to content

Windows: in-process ctypes probe in build_tangency_cpp.py locks the DLL and breaks repeated builds (LNK1104) #123

Description

@t-uda

問題

Windows 環境で poetry install を実行すると、C++ バックエンド (_tangency_cpp_impl.dll) のビルドが 2 回呼び出され、2 回目に LNK1104 エラーで失敗する。

エラーメッセージ

\
LINK : fatal error LNK1104: ファイル '_tangency_cpp_impl.dll' を開くことができません。
subprocess.CalledProcessError: Command '[...\link.exe', ..., '/OUT:..._tangency_cpp_impl.dll']' returned non-zero exit status 1104.
distutils.errors.DistutilsExecError: command '...link.exe' failed with exit code 1104
\\

再現手順

  1. Windows 上で poetry install を実行する(特に .venv を削除後のクリーンな状態)。
  2. 1 回目のビルドは成功し DLL が生成される。
  3. Poetry が build backend を再度呼び出す際(wheel の install フェーズ)に同じ DLL へ上書き書き込みしようとするが、1 回目のビルドスクリプト内で ctypes.CDLL() によりロードされた DLL がプロセスに保持されており、ファイルが排他ロックされている。
  4. リンカが DLL を開けずエラー終了する。

原因の詳細

scripts/build_tangency_cpp.py の build() 関数内で既存 DLL のバージョンを確認するために ctypes.CDLL(str(path)) を呼び出している。Windows では LoadLibrary でロードしたファイルはプロセスが終了するまで排他ロックされるため、同一プロセス内での上書きができない。

Poetry の build backend は「build wheel」と「install wheel」の 2 フェーズで build hook を呼び出すため、同一 Python プロセス内でビルドスクリプトが 2 回実行される。

対応案

_existing_library_version() / _existing_library_linalg_kind() 内で ctypes.CDLL() によるロードを行う前に、プロセスを分離してバージョン文字列を取得する(例: subprocess.check_output で別プロセスを起動)。あるいは DLL を一時ディレクトリへコピーしてからロードすることでロックを回避できる。

暫定ワークアラウンド

pip install -e . --no-build-isolation を使用することでビルドが 1 回に抑えられ問題を回避できる。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions