如何自定义Python包的常规与开发模式安装?解决develop命令未执行问题
问题描述
我正在构建example_package,需要自定义常规模式与开发(editable)模式下的安装流程。项目结构如下:
. ├── cpp │ ├── CMakeLists.txt │ └── helloworld.cpp ├── pyproject.toml ├── setup.py └── src └── example_package └── __init__.py
各文件内容:
- pyproject.toml:
[build-system] requires = ["setuptools>=62.0.0", "wheel", "cmake>=3.20"] build-backend = "setuptools.build_meta" [project] name = "example_package" version = "0.0.1" requires-python = ">=3.8" [tool.setuptools.packages.find] where = ["src"]
- setup.py:
from setuptools import setup from setuptools.command import develop, build_py, install import subprocess class CustomDevelop(develop.develop): def run(self): super(CustomDevelop, self).run() print("Execute CustomDevelop ......") class CustomBuildPy(build_py.build_py): def run(self): super(CustomBuildPy, self).run() print("Execute CustomBuildPy ......") class CustomInstall(install.install): def run(self): super(CustomInstall, self).run() print("Execute CustomInstall ......") setup( cmdclass={ 'develop': CustomDevelop, 'build_py': CustomBuildPy, 'install': CustomInstall } )
安装测试情况:
- 常规模式:执行
python3 -m pip install -vv .后,CustomBuildPy和CustomInstall均正常执行,符合预期。 - 开发模式:执行
python3 -m pip install -vv -e .后,仅CustomBuildPy执行,自定义的CustomDevelop未被调用,不符合预期。
实际需求:将cpp目录下的helloworld.cpp通过CMake编译为可执行文件helloworld,并放入sys.path中。修改CustomBuildPy后,常规模式安装正常,但开发模式下出现复制错误,因为源码目录中未生成build文件夹。
解决方案
1. 修复CustomDevelop未触发问题+统一编译逻辑
新版setuptools中,旧的develop命令已被editable_install替代,直接重载develop.develop不会生效。需要改用EditableInstall命令,同时封装CMake编译逻辑避免重复代码:
修改后的setup.py:
from setuptools import setup from setuptools.command.build_py import build_py from setuptools.command.install import install from setuptools.command.editable_install import EditableInstall import subprocess import os import shutil def build_cpp(): # 创建编译目录 build_dir = os.path.join(os.path.dirname(__file__), "cpp", "build") os.makedirs(build_dir, exist_ok=True) # 执行CMake编译流程 subprocess.run(["cmake", ".."], cwd=build_dir, check=True) subprocess.run(["make"], cwd=build_dir, check=True) # 返回编译后的可执行文件路径 return os.path.join(build_dir, "helloworld") class CustomBuildPy(build_py): def run(self): super().run() # 编译CPP并复制到安装后的包目录 exe_path = build_cpp() package_dir = os.path.join(self.build_lib, "example_package") shutil.copy(exe_path, package_dir) print("CustomBuildPy: CPP编译完成并复制到安装包目录") class CustomInstall(install): def run(self): super().run() print("CustomInstall: 常规安装流程执行完成") class CustomEditableInstall(EditableInstall): def run(self): super().run() # 编译CPP并复制到源码包目录(开发模式下sys.path指向src) exe_path = build_cpp() package_dir = os.path.join(os.path.dirname(__file__), "src", "example_package") shutil.copy(exe_path, package_dir) print("CustomEditableInstall: 开发模式CPP编译完成并复制到源码目录") setup( cmdclass={ 'build_py': CustomBuildPy, 'install': CustomInstall, 'editable_install': CustomEditableInstall } )
2. 确保CMake配置正确
cpp/CMakeLists.txt需正确生成可执行文件,示例:
cmake_minimum_required(VERSION 3.20) project(helloworld) add_executable(helloworld helloworld.cpp)
3. 验证测试
- 常规模式:执行
python3 -m pip install -vv .,CustomBuildPy会编译CPP并复制到安装后的包目录,CustomInstall正常触发。 - 开发模式:执行
python3 -m pip install -vv -e .,CustomEditableInstall会编译CPP并复制到src/example_package,此时sys.path指向源码目录,可执行文件能被正确识别。
关键注意点
- 用
build_cpp函数封装编译逻辑,避免重复代码。 - 开发模式下,editable安装指向
src目录,需将可执行文件复制到src/example_package而非build目录。 - 适配新版setuptools,用
EditableInstall替代旧的develop命令。
内容的提问来源于stack exchange,提问作者Der Fänger im Roggen
相关产品推荐
相关产品推荐

