问题描述

之前有一个rust的gRPC项目,使用的是tonic 0.13.1版本,最近尝试将tonic升级到0.14.2版本,结果在编译时遇到了如下错误:

error[E0412]: cannot find type `i64` in module `super`
   --> src/proto-gen/category.rs:132:72
    |
132 |             request: impl tonic::IntoStreamingRequest<Message = super::i64>,
    |                                                                        ^^^ not found in `super`
    |
help: consider importing this builtin type
    |
 39 +     use std::primitive::i64;
    |
help: if you import `i64`, refer to it directly
    |
132 -             request: impl tonic::IntoStreamingRequest<Message = super::i64>,
132 +             request: impl tonic::IntoStreamingRequest<Message = i64>,
    |

For more information about this error, try `rustc --explain E0412`.
error: could not compile `couxie-web-axum` (lib) due to 4 previous errors

解决方案

Cargo.toml中将tonic的依赖更新:

-prost = "0.13.5" # Protobuf 编码/解码库
-prost-types = "0.13.5"
+prost = "0.14.1" # Protobuf 编码/解码库
+prost-types = "0.14.1"

-tonic = { version = "0.13.1", default-features = false, features = [
+tonic = { version = "0.14.2", default-features = false, features = [
     "transport",
-    "prost",
     "codegen",
 ] }
+tonic-prost = "0.14.2"
 [build-dependencies]
-tonic-build = "0.13.1"
+tonic-prost-build = "0.14.2"

然后在build.rs中将tonic-build替换为tonic-prost-build:

use std::path::Path;
use tonic_prost_build::configure;
-    tonic_build::configure()
+    configure()

同时修改build.rs中生成代码的相关逻辑处理protobuf的编译:

        .compile_protos(&protos, &["proto"])?; // Compile the proto file(s)

    // 修复super::i64和super::u64的问题
    for entry in fs::read_dir(OUT_DIR)? {
        let entry = entry?;
        let path = entry.path();
        if path.extension().map(|e| e == "rs").unwrap_or(false) {
            fix_proto_file(&path)?;
        }
    }

    Ok(())
}

fn fix_proto_file(path: &Path) -> Result<()> {
    let content = fs::read_to_string(path)?;
    let content = content
        .replace("super::i64", "i64")
        .replace("super::u64", "u64");
    fs::write(path, content)?;
    Ok(())
}

主要原因:

proto文件中使用了google.protobuf.Int64Valuegoogle.protobuf.UInt64Value这两个包装类型,但tonic在生成代码时将其映射为了super::i64super::u64,而不是直接使用Rust的内置类型i64u64,不知道什么时候tonic不再使用super::i64super::u64这种写法了,导致编译错误。