setuptools编译上级目录C++文件的问题求助
Python扩展模块跨平台编译路径问题解决指南
问题描述
C源文件位于setup.py的上级目录(作为C库的Python绑定,属于层级从属结构),使用相对路径编写的setup.py在Windows编译正常,但Linux下执行python3 -m build --wheel报错:
Fatal error: can't create build/temp.linux-x86_64-cpython-311/../src/pybind11_binding_main.o: No such file or directory
尝试使用绝对路径又触发setuptools的路径校验错误:
error: Error: setup script specifies an absolute path: /absolute/path/to/myproject/src/pybind11_binding_main.cpp setup() arguments must *always* be /-separated paths relative to the setup.py directory, *never* absolute paths. ERROR Backend subprocess exited when trying to invoke build_wheel
额外需求:
- 避免Python用setup.py所在文件夹命名包(根命名空间已有同名用途)
- 不让
python3 -m build在项目根目录生成大量编译目录
解决方案1:调整编译工作目录(推荐)
通过自定义build_ext命令,将编译工作目录切换到项目根目录,同时指定编译产物目录到setup.py所在子文件夹,避免路径混乱。修改后的setup.py:
from setuptools import setup from setuptools.command.build_ext import build_ext from pybind11.setup_helpers import Pybind11Extension import os # 源文件路径(相对于项目根目录) src_files = ["src/functionality.cpp", "src/pybind11_binding_main.cpp"] class CustomBuildExt(build_ext): def run(self): # 切换到项目根目录(setup.py的上级目录) original_cwd = os.getcwd() project_root = os.path.dirname(os.path.abspath(__file__)) + "/.." os.chdir(project_root) try: super().run() finally: # 恢复原工作目录 os.chdir(original_cwd) setup_args = dict( ext_modules=[Pybind11Extension("myext", src_files)], cmdclass={"build_ext": CustomBuildExt}, # 指定编译产物生成在setup.py所在目录的build子文件夹 build_dir=os.path.join(os.path.dirname(__file__), "build"), # 自定义包名称,避免自动使用文件夹名 name="myext" ) setup(**setup_args)
解决方案2:复制源文件到临时目录
编译前自动将上级目录的C++文件复制到setup.py所在目录的临时文件夹,编译完成后清理,绕过路径解析问题:
from setuptools import setup from pybind11.setup_helpers import Pybind11Extension import os import shutil # 上级目录的源文件路径 src_files_original = ["../src/functionality.cpp", "../src/pybind11_binding_main.cpp"] temp_src_dir = os.path.join(os.path.dirname(__file__), "temp_src") # 创建临时目录并复制源文件 os.makedirs(temp_src_dir, exist_ok=True) src_files_temp = [] for src_file in src_files_original: dest_file = os.path.join(temp_src_dir, os.path.basename(src_file)) shutil.copy(src_file, dest_file) src_files_temp.append(dest_file) setup_args = dict( ext_modules=[Pybind11Extension("myext", src_files_temp)], build_dir=os.path.join(os.path.dirname(__file__), "build"), name="myext" ) try: setup(**setup_args) finally: # 清理临时目录 shutil.rmtree(temp_src_dir, ignore_errors=True)
解决方案3:配合pyproject.toml管理项目结构
如果使用pyproject.toml配置项目,可进一步规范编译行为:
- 在setup.py所在目录创建
pyproject.toml:
[build-system] requires = ["setuptools>=61.0", "wheel", "pybind11"] build-backend = "setuptools.build_meta" [project] name = "myext" version = "0.1.0" [tool.setuptools] build-dir = "build" # 指定编译目录在当前子目录
- 结合解决方案1的setup.py代码,即可实现跨平台编译,同时避免根目录被编译文件污染。
内容的提问来源于stack exchange,提问作者geometrian
相关产品推荐
相关产品推荐

