You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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配置项目,可进一步规范编译行为:

  1. 在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. 结合解决方案1的setup.py代码,即可实现跨平台编译,同时避免根目录被编译文件污染。

内容的提问来源于stack exchange,提问作者geometrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:32:48