You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为依赖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"
        ]
    }
)

三、配置辅助文件

  1. MANIFEST.in:如果需要把原始.proto文件打包到源码包中(方便后续调试或重新生成),添加以下内容:
include proto/*.proto
  1. .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模板,再修改后构建:

  1. 生成基础spec文件:
python setup.py bdist_rpm --spec-only

生成的spec文件会在dist/目录下,比如user-service-1.0.0.spec

  1. 修改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/"
  1. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:42:27