pip安装Python包时如何自动编译包内的C/C++代码
Python包pip安装时自动编译C++代码的实现方案
标准实现方案
目前最通用的实现是基于Python官方的打包工具链实现安装时自动编译,分两种场景适配你现有的代码逻辑:
场景1:可调整现有逻辑,替换subprocess调用
推荐直接将C++代码编译为Python原生扩展,不需要额外生成可执行文件,调用性能更高,配置也更简单:
- 首先在项目根目录创建
pyproject.toml声明构建依赖:
[build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta"
- 在
setup.py中定义C++扩展规则,示例如下:
from setuptools import setup, Extension # 定义C++扩展的编译规则 cpp_ext = Extension( name="你的包名.扩展模块名", sources=["C++源码文件路径,比如src/cpp/core.cpp"], language="c++", extra_compile_args=["-std=c++17"], # 按需调整编译参数 extra_link_args=[] # 按需添加链接参数,比如依赖的库 ) setup( name="你的包名", ext_modules=[cpp_ext], # 其他常规配置:版本、作者、依赖、包路径等 )
编译完成后可以直接在Python代码中import 你的包名.扩展模块名调用C++逻辑,不需要再通过subprocess调用外部可执行文件。
场景2:必须保留现有subprocess调用可执行文件的逻辑
可以通过自定义setuptools构建钩子,在安装时触发C++编译,将生成的可执行文件打包为包的资源文件:
from setuptools import setup from setuptools.command.build_py import build_py import subprocess import os class BuildWithCppExe(build_py): def run(self): # 编译C++代码生成可执行文件 src_path = "src/cpp/your_code.cpp" exe_output_dir = os.path.join("你的包名", "bin") os.makedirs(exe_output_dir, exist_ok=True) exe_path = os.path.join(exe_output_dir, "可执行文件名") # 可根据平台判断编译命令,比如Windows下用msvc的编译逻辑 subprocess.run( ["g++", src_path, "-o", exe_path, "-std=c++17"], check=True ) # 将可执行文件加入包数据,会同步安装到用户环境 self.distribution.package_data["你的包名"].append("bin/*") super().run() setup( name="你的包名", packages=["你的包名"], package_data={"你的包名": []}, cmdclass={"build_py": BuildWithCppExe}, # 其他常规配置 )
你现有代码只需要调整可执行文件的读取路径,通过importlib.resources读取包内的可执行文件资源即可,不需要用户手动编译。
补充优化点:如果不想要求用户本地安装C++编译环境,你可以提前为Windows、macOS、Linux不同平台预编译wheel包上传到PyPI,用户pip安装时会优先下载对应平台的预编译包,不需要本地执行编译流程。
替代方案
如果你的C++代码依赖复杂,原生setuptools配置成本较高,可以选择以下方案:
- 用pybind11绑定C代码:对C11及以上版本支持友好,绑定代码编写简单,生成的Python扩展调用和普通Python函数一致,不需要额外学习Python C API。
- 用Cython包装C代码:适合需要在C和Python逻辑间做灵活适配的场景,语法和Python接近,学习成本较低。
- 用scikit-build管理构建流程:基于CMake封装的Python打包工具,适合C++代码依赖多、构建逻辑复杂的场景,跨平台兼容性更好,和PyPI打包流程完全兼容。
内容的提问来源于stack exchange,提问作者gsabat
相关产品推荐
相关产品推荐

