如何在Python Wheel中处理.pyd扩展与.exe二进制脚本?
问题
我借助PyBind11用C++开发了一个Python二进制扩展,附带一个常规可执行文件(mytool.exe)。目前在制作用于分发的Wheel文件时遇到问题:使用pyproject.toml和setuptools后端能正常打包纯Python包及Python脚本,但不知如何处理包含整个扩展包的.pyd文件。目前能实现的最佳效果是将.pyd安装到python-install-dir/Lib/site-packages/mypackage/mypackage.pyd,此时需通过mypackage.mypackage.mymember访问成员;但手动将.pyd放到python-install-dir/Lib/site-packages/mypackage.pyd时,可通过mypackage.mymember正常访问。请问如何配置pyproject.toml实现该效果?是否在.pyd文件中有遗漏?或者是否需要更换构建后端?另外,如何将mytool.exe包含到Wheel中,使其安装后位于python-install-dir/Scripts目录?
解决方案
一、调整.pyd文件的安装路径,实现直接导入
不需要更换构建后端,setuptools完全可以处理,核心是让.pyd直接安装到site-packages根目录而非子包目录,步骤如下:
确认PyBind11模块命名
在你的C++代码中,确保PyBind11的模块名称为mypackage(即你期望的顶层包名):PYBIND11_MODULE(mypackage, m) { // 模块绑定代码 m.def("mymember", []() { /* 实现逻辑 */ }); }编译后生成的.pyd文件应为
mypackage.pyd,而非嵌套命名的文件。配置pyproject.toml
修改配置,让setuptools将.pyd作为顶层模块安装:[project] name = "mypackage" version = "0.1.0" [tool.setuptools] # 不声明子包,因为要将.pyd作为顶层模块 packages = [] # 指定顶层扩展模块 py-modules = ["mypackage"] # 如果是预编译好的.pyd,指定其本地路径 [tool.setuptools.package-data] "" = ["mypackage.pyd"] # 如果是通过setuptools直接编译C++源文件,替换为以下配置: # [tool.setuptools.ext_modules] # mypackage = { sources = ["src/your_source.cpp"] }打包安装后,.pyd会被放置到
site-packages/mypackage.pyd,即可直接通过import mypackage; mypackage.mymember访问。
二、将mytool.exe打包到Scripts目录
在pyproject.toml中添加data-files配置,指定可执行文件的目标路径为Scripts:
[tool.setuptools.data-files] # 键为安装后的目标目录,值为本地文件的路径 "Scripts" = ["path/to/your/mytool.exe"]
安装Wheel后,mytool.exe会被自动复制到Python安装目录下的Scripts文件夹,该目录通常已加入系统PATH,可直接在终端运行mytool命令。
内容的提问来源于stack exchange,提问作者Orel

