基于Rye+Setuptools构建Pybind11封装.so文件的Python包问题
解决pybind11+Rye+setuptools构建Python包的两个问题
问题分析
- 源码包(tar.gz)不含.so文件:源码包默认只包含源代码(如.cpp),.so是编译产物仅存在于wheel包中,但需确保setuptools正确收集C++源码到源码包内。
- 项目目录或
rye run python下无法调用add():当前导入的是src/minimal_example/__init__.py,但编译出的.so未放入该目录,也未被__init__.py关联导入。
解决方案配置修改
1. 添加src/minimal_example/__init__.py
创建该文件用于导出C++扩展模块的接口:
from ._core import add __all__ = ["add"]
2. 修改setup.py
调整扩展模块命名、包收集规则,移除不必要的环境变量依赖:
from setuptools import setup, find_packages from pybind11.setup_helpers import Pybind11Extension, build_ext # 将扩展模块设为包内的私有子模块 ext_modules = [ Pybind11Extension( "minimal_example._core", ["src/minimal_example/minimal_example.cpp"], extra_compile_args=['-O3', '-Wall', '-std=c++11', '-fPIC'] ) ] setup( packages=find_packages(where="src"), package_dir={"": "src"}, cmdclass={"build_ext": build_ext}, ext_modules=ext_modules, include_package_data=True )
3. 优化pyproject.toml
补充包结构配置,确保setuptools正确识别包路径:
[project] name = "minimal-example" version = "0.1.0" description = "Add your description here" authors = [ { name = "me", email = "me@email.com" } ] dependencies = [ "pybind11>=2.12.0", "setuptools>=70.0.0", ] readme = "README.md" requires-python = ">= 3.8" # 指定包位置与目录映射 packages = ["minimal_example"] package_dir = {"": "src"} [build-system] requires = ["setuptools>=42", "pybind11>=2.6.1"] build-backend = "setuptools.build_meta" [tool.rye] managed = true dev-dependencies = []
4. 构建与验证
执行以下命令重新构建并测试:
# 清理旧构建产物 rm -rf build dist src/minimal_example/*.so # 构建wheel和源码包 rye build
验证效果:
- 源码包(tar.gz)将包含
src/minimal_example/minimal_example.cpp等源代码文件 - 在项目目录下执行
rye run python测试导入:
import minimal_example print(minimal_example.add(1,2)) # 输出3
关键说明
- 扩展模块命名为
minimal_example._core作为包内私有模块,通过__init__.py导出公共接口,符合Python包规范 find_packages(where="src")让setuptools自动收集src目录下的Python包include_package_data=True确保编译后的.so文件被安装到对应包目录中- 源码包本身不会包含.so,这是正常行为——源码包用于从源码编译安装,wheel包才是预编译的可直接使用产物
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

