【问题标题】:What is the relationship between proto package and actual directory structureproto包和实际目录结构有什么关系
【发布时间】:2021-10-12 05:22:58
【问题描述】:

我已经在线阅读了关于protobuf的官方文档和教程,但我仍然不太了解proto定义中的包名和导入路径与实际目录结构之间的关系。

为了让我的问题更清楚,假设这是我的项目结构:

root
├── project
│   └── protos
│       ├── common
│       │   └── common.proto
│       └── custom
│           ├── app.proto
│           └── util
│               └── util.proto           

common.proto

syntax = "proto3";

// how should I decide the package for this file based on my project structure?
package project.protos.common;

message Common {
    // ...
}

app.proto,它引用 common.proto(在另一个单独的目录中)和 util.proto(在子目录中)

syntax = "proto3";

package project.protos.custom;

import "project/protos/common/common.proto";
import "project/protos/custom/util/util.proto";
import "google/protobuf/timestamp.proto";

message App {
    project.protos.common.Common common = 3;
    project.protos.custom.util.Util util = 4;
}

util.proto

syntax = "proto3";

package project.protos.custom.util;

option java_multiple_files = true;

message Util {
    // ...
}

经过多次试验,发现如果我在root目录下运行protoc命令,使用命令:

protoc -I . --java_out=. project/protos/**/*.proto

然后导入工作正常,并且每个 proto 文件都被编译,没有错误。但是,假设我不是在根目录,而是在子目录项目中运行 protoc,使用类似的命令:

protoc -I . --java_out=. protos/**/*.proto

编译将失败并出现以下错误:

project/protos/common/common.proto: File not found.
project/protos/custom/util/util.proto: File not found.
protos/custom/app.proto:6:1: Import "project/protos/common/common.proto" was not found or had errors.
protos/custom/app.proto:8:1: Import "project/protos/custom/util/util.proto" was not found or had errors.
protos/custom/app.proto:19:5: "project.protos.common.Common" seems to be defined in "protos/common/common.proto", which is not imported by "protos/custom/app.proto".  To use it here, please add the necessary import.
protos/custom/app.proto:20:5: "project.protos.custom.util.Util" is not defined.

由于我大部分时间都在使用 Java,我目前正在考虑 package & import 在 protobuf 中的工作方式,就实际目录结构而言,类似于 Java 中 package & import 的工作方式,关于类路径。

也就是说,如果我想编译一个包指定为“project.protos.common”的proto,那么我应该在project dir的父目录上运行protoc命令,其中project/protos/common是有效的路径。

同样,如果我在另一个 proto 文件中导入一个 proto 并且导入路径设置为“project/protos/custom/util/util.proto”,那么我还应该确保在运行 protoc 时从目录中导入命令,路径 project/protos/custom/util/util.proto 存在。

我目前正在猜测我们提供给 -I 选项的任何路径,protoc 将以与 Java 类路径或 python 搜索路径相同的方式对待它们。导入时,protoc 将在每个指定的 -I 路径上查找导入的文件,遵循 import 语句指示的相对路径。

但是,在网上搜索了类似的问题并阅读了一些文章之后,现在我的印象是protobuf中的打包和导入实际上比我想象的要灵活得多。是不是我的理解错了?

【问题讨论】:

    标签: java protocol-buffers proto


    【解决方案1】:

    我将间接回答:

    1. 包名对应目录
    2. 一个包可以跨越单个目录中的多个文件
    3. (但是)单个文件必须导入 Protos,即使在同一个包中
    4. 通过一些 org id 来命名空间|范围包很有用(例如,google 代表 timestamp
    5. 相关包的层次结构(例如 google.protobuf 清单为 google/protobuf/...)与其文件系统位置无关。
    6. 虽然包层次结构是固定的,但在生成特定于语言的绑定时“放置”具有灵活性。

    我将尝试提供每个示例:

    protocinclude 目录为例,包google.protobuf 清楚地将其标识为源自google 的包,代表protobuf“stuff”。

    包必须在目录中表示为google/protobuf,但它在系统中的位置是任意的并且没有依赖关系(请参阅--proto_path)。

    包中的文件,例如api.proto 必须导入,例如type.proto(使用完整的命名空间路径(即google/protobuf/type.proto),即使它们共享一个包。

    在运行protoc .... foo.proto 时,如果foo.proto 导入google/protobug/api.protoprotoc 需要一些方法来查找包,因此需要protoc --proto_path=path/to/google(尽管如果protoc 在路径中,include Linux 上不需要添加目录)。所有导入必须是类似的--proto_path'd。

    protoc 输出文件和(更重要的是)用于生成输出的命名空间具有一定的灵活性,这要归功于 proto 文件中的 option [langauge]_package 标志。

    我不熟悉 Java,但对于 Golang,我可以使用 option go_package 帮助我指定 Golang 模块名称 (github.com/[org]/[repo]) 以确保生成的文件放置在 repo 中,以便它们将被其他 Golang 模块正确导入。

    【讨论】:

    猜你喜欢
    • 2021-09-07
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2020-02-02
    相关资源
    最近更新 更多