如何为依赖protoc生成模块(protobuf、grpc)的Python脚本创建RPM包
打包含Protobuf/GRPC生成代码的Python项目为RPM的完整方案
我来分享一个实际项目中验证过的可行方案,既能把Protobuf代码生成整合到Python包构建流程,又能顺利生成符合需求的RPM包,兼顾setup.py的便捷性和RPM定制化需求。
一、先梳理项目结构
先给一个标准的项目结构参考,方便后续步骤对齐:
my_grpc_project/ ├── proto/ # 存放原始.proto文件 │ └── user_service.proto ├── user_service/ # 你的Python包目录 │ ├── __init__.py │ ├── core/ # 自定义业务代码 │ │ └── handlers.py │ └── generated/ # 存放构建时生成的Protobuf/GRPC代码(无需提交到版本控制) ├── setup.py # 核心构建脚本 ├── MANIFEST.in # 控制源码包包含的文件 └── .gitignore # 忽略临时文件/生成代码
二、在setup.py中整合Protobuf代码生成
关键思路是扩展setuptools的build_py命令,让Python包构建前自动执行protoc生成代码。这样生成的代码会被自动打包到最终的Python包中。
下面是完整的setup.py示例:
import os from setuptools import setup, find_packages from setuptools.command.build_py import build_py from grpc_tools import protoc # 用grpcio-tools自带的protoc,避免依赖系统版本 class ProtobufBuildPy(build_py): def run(self): # 1. 定义路径变量 proto_root = os.path.join(os.path.dirname(__file__), "proto") output_dir = os.path.join(os.path.dirname(__file__), "user_service", "generated") # 确保输出目录存在 os.makedirs(output_dir, exist_ok=True) # 2. 执行protoc生成Python和GRPC代码 # 这里用grpc_tools.protoc代替系统protoc,版本更可控 protoc.main([ "protoc", f"--proto_path={proto_root}", # 指定proto文件根目录 f"--python_out={output_dir}", # 生成普通Protobuf代码 f"--grpc_python_out={output_dir}", # 生成GRPC服务端/客户端代码 os.path.join(proto_root, "user_service.proto") # 目标proto文件 ]) # 3. 执行原生的build_py步骤,打包生成的代码和业务代码 super().run() # 核心setup配置 setup( name="user-service", version="1.0.0", packages=find_packages(), # 替换默认的build_py命令为我们自定义的版本 cmdclass={"build_py": ProtobufBuildPy}, # 运行时依赖 install_requires=[ "protobuf>=4.23.0", "grpcio>=1.56.0" ], # 构建时依赖(确保构建环境有grpcio-tools来生成代码) setup_requires=[ "grpcio-tools>=1.56.0" ], # 可选:如果你的项目有命令行工具,可以在这里声明 entry_points={ "console_scripts": [ "user-service=user_service.core.handlers:main" ] } )
三、配置辅助文件
- MANIFEST.in:如果需要把原始.proto文件打包到源码包中(方便后续调试或重新生成),添加以下内容:
include proto/*.proto
- .gitignore:避免把生成的代码提交到版本控制,添加:
user_service/generated/ dist/ build/ *.egg-info/
四、生成RPM包的两种方式
方式1:直接用bdist_rpm快速生成
在项目根目录执行命令:
python setup.py bdist_rpm
这会自动完成:
- 生成Protobuf/GRPC代码
- 构建Python包
- 生成RPM包(默认输出到
dist/目录)
方式2:自定义spec文件实现高级需求
如果需要添加post/postun脚本、自定义RPM依赖或其他定制化配置,可以先生成spec模板,再修改后构建:
- 生成基础spec文件:
python setup.py bdist_rpm --spec-only
生成的spec文件会在dist/目录下,比如user-service-1.0.0.spec
- 修改spec文件,添加自定义逻辑,比如:
# 构建依赖(确保构建环境有必要工具) BuildRequires: python3-devel BuildRequires: python3-grpcio-tools # 安装后脚本 %post echo "User Service已安装,启动服务请执行: systemctl start user-service" # 卸载后脚本 %postun echo "User Service已卸载,清理配置请执行: rm -rf /etc/user-service/"
- 用rpmbuild构建最终RPM:
rpmbuild -bb dist/user-service-1.0.0.spec
生成的RPM会在rpmbuild的输出目录(默认~/rpmbuild/RPMS/)
五、关键注意事项
- 构建环境依赖:如果用方式1,要确保构建机器上安装了Python3和pip;如果用方式2,还要确保安装了
rpm-build工具。 - 版本一致性:用
grpcio-tools自带的protoc可以避免系统protoc版本和Python依赖的protobuf版本不兼容的问题,强烈推荐这种方式。 - RPM依赖自动处理:
bdist_rpm会自动把install_requires中的依赖转化为RPM的Requires字段,无需手动添加。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

