使用pyproject.toml+scikit-build-core+CMake构建Python库时,如何增量重新编译修改后的C++扩展?
pyproject.toml+scikit-build-core+CMake构建Python库时,如何增量重新编译修改后的C++扩展?
我太懂这种折腾了——之前用setup.py的时候,改个C++文件跑一句python setup.py build_ext --inplace就能快速增量编译,换了scikit-build-core+CMake这套新系统后,每次全量编译属实浪费时间。下面给你几个实用的方案,都是贴合这套工具链特性的增量编译方法:
方案1:直接调用CMake做增量编译(最接近make的原生方式)
scikit-build-core本质是帮你打理CMake的构建流程,所以跳过它直接操作CMake就能实现纯增量编译:
- 先跑一次
pip install --no-deps .或者scikit-build-core build,让scikit-build-core帮你生成完整的CMake构建环境(默认会在_skbuild目录下生成平台相关的子目录,比如Linux下是_skbuild/linux-x86_64-3.10,Windows下是_skbuild/win-amd64-3.10) - 进入到该子目录下的
cmake-build文件夹(这是CMake实际的构建工作目录) - 直接执行
cmake --build .,CMake会自动扫描所有源文件的修改时间,只重新编译有变动的C++文件,速度和原生make一样快 - 如果你想直接在项目根目录测试编译后的扩展,可以把
cmake-build里生成的扩展文件(比如.so/.pyd/.dylib格式)复制到项目根目录,就和之前build_ext --inplace的效果完全一致
方案2:用scikit-build-core自带命令实现增量编译
scikit-build-core本身支持保留构建缓存,不用你手动找CMake目录:
- 增量编译并生成构建产物:运行
scikit-build-core build --no-clean,这个命令不会清空之前的构建缓存,CMake会自动处理增量编译 - 增量编译后直接安装到当前环境:运行
scikit-build-core install --no-deps --no-clean,相比pip install --no-deps .,它不会重新执行完整的配置流程,只编译变动的文件,安装速度快很多
方案3:优化CMake配置让增量编译更省心
在你的CMakeLists.txt里加几个配置,能让整个流程更贴近你之前用setup.py的习惯:
- 不要用
file(GLOB)自动收集源文件(虽然它能检测文件修改,但明确列出源文件能避免CMake漏检新增文件),直接把所有C++源文件写在add_library里 - 固定构建类型(比如
Debug或Release),避免每次构建重新配置:在CMakeLists.txt开头加set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) - 让扩展文件直接输出到项目根目录,省去手动复制的步骤:
之后不管是用set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) # Windows下需要这个cmake --build .还是scikit-build-core build --no-clean,编译好的扩展都会直接出现在项目根目录,你可以立刻用Python导入测试
一些注意事项
- 如果你修改了
CMakeLists.txt或者pyproject.toml,需要重新触发CMake配置(比如运行scikit-build-core configure),这时候会重新生成构建系统文件,可能会全量编译一次,但之后修改C++文件依然是增量的 - 不同平台的
_skbuild子目录命名略有差异,找不到的话可以直接看目录结构,找带Python版本和平台信息的文件夹就行 - 确保在激活虚拟环境的状态下运行命令,避免路径或依赖版本混乱
内容来源于stack exchange




