使用Setuptools构建Cython包装C++扩展:如何避免全量编译?
优化Cython封装C++的增量编译流程
这个痛点我太有共鸣了!每次改完.pyx文件还要等一堆没动过的C++代码重新编译,简直是在浪费宝贵的开发时间。下面给你几个亲测有效的优化方案,帮你只编译真正改动的部分:
方案一:将C++代码预编译为静态/动态库
核心思路是把不变的C代码先单独编译成库文件,Cython扩展只负责链接这个库,不再重复编译C源文件:
编译C++目标文件
在Linux/macOS下用g++:g++ -c path/to/your_cpp_files/*.cpp -o path/to/output/your_class.o -fPICWindows下用MSVC的cl命令:
cl /c path/to/your_cpp_files/*.cpp /Fo path/to/output/your_class.obj打包为静态库
Linux/macOS下用ar工具:ar rcs path/to/output/libyourclass.a path/to/output/your_class.oWindows下用lib.exe:
lib.exe /OUT:path/to/output/yourclass.lib path/to/output/your_class.obj修改setup.py配置
原来的setup.py可能会把C++源文件列在sources里,现在只保留.pyx文件,然后添加库链接参数:from setuptools import setup, Extension from Cython.Build import cythonize ext = Extension( "rect", sources=["rect.pyx"], include_dirs=["path/to/cpp_headers"], # Linux/macOS下的链接参数 extra_link_args=["-Lpath/to/output", "-lyourclass"], # Windows下替换成下面这行 # extra_link_args=["path/to/output/yourclass.lib"], language="c++" ) setup( name="rect", ext_modules=cythonize(ext) )这样后续修改
.pyx文件时,只会编译Cython生成的C代码,然后直接链接预编译好的库,完全跳过C源文件的编译步骤。
方案二:确保setuptools的增量编译生效
有时候全量编译是因为setup.py没有正确识别文件依赖,你可以做这些调整:
- 不要在
Extension的sources里包含未改动的C++文件,除非你真的需要重新编译它们 - 使用
cythonize时保持默认的force=False,让Cython只重新编译修改过的.pyx文件 - 检查你的C++头文件是否被
.pyx文件引用,如果头文件没改动,Cython也不会触发不必要的重新编译
方案三:使用Ninja作为构建后端
Ninja比默认的make/MSBuild更擅长增量编译,能更精准地跟踪文件修改状态:
先安装Ninja:
pip install ninja配置setuptools使用Ninja:
可以在项目根目录创建setup.cfg文件,添加以下内容:[build] backend = ninja或者在运行setup.py时设置环境变量:
SETUPTOOLS_USE_DISTUTILS=stdlib python setup.py build_ext --inplace这样Ninja会自动处理增量编译,只重新编译改动过的文件。
注意事项
- 如果修改了C头文件,还是需要重新编译C库的,这是不可避免的
- 不同平台的编译命令和链接参数略有差异,需要根据自己的开发环境调整
内容的提问来源于stack exchange,提问作者HDembinski
相关产品推荐
相关产品推荐

