protoc-gen-go: plugin output is unparseable | protoc 被 Windows 的命令行坑惨了!

某一天,正想用 Golang 和 gRPC 写个 hello, world
结果,通过 proto 文件生成 Golang 代码的时候,报错了
后来才发现,这个错误是 Windows CMD 启动时自动执行命令的锅

相关 Issue:protoc-gen-go: plugin output is unparseable #1054
StackOverFlow 相关问题:How to fix Windows batch file FOR command returing “Active code page: 65001”

问题

go:generate protoc --go_out=. room.proto 或者是在 PowerShell 执行 protoc --go_out=. room.proto,会爆出以下错误:

protoc-gen-go: Plugin output is unparseable

而且换了几个版本,都不行!

完整输出如下:

PS C:\Users\sia\GolandProjects\compass\proto> protoc --go_out=.  room.proto
--go_out: protoc-gen-go: Plugin output is unparseable: Active code page: 1252\r\nz\332&\n+github.com/TeslaCN/compass/proto/room.pb.goz\252&// Code generated by protoc-gen-go. DO NOT EDIT.\n// source: room.proto\n\npackage proto\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/golang/protobuf/proto\"\n\tmath \"math\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package\n\ntype RoomInfo struct {\n\tId                   string   `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tAddr                 string   `protobuf:\"bytes,2,opt,name=addr,proto3\" json:\"addr,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *RoomInfo) Reset()         { *m = RoomInfo{} }\nfunc (m *RoomInfo) String() string { return proto.CompactTextString(m) }\nfunc (*RoomInfo) ProtoMessage()    {}\nfunc (*RoomInfo) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_c5fd27dd97284ef4, []int{0}\n}\n\nfunc (m *RoomInfo) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_RoomInfo.Unmarshal(m, b)\n}\nfunc (m *RoomInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_RoomInfo.Marshal(b, m, deterministic)\n}\nfunc (m *RoomInfo) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_RoomInfo.Merge(m, src)\n}\nfunc (m *RoomInfo) XXX_Size() int {\n\treturn xxx_messageInfo_RoomInfo.Size(m)\n}\nfunc (m *RoomInfo) XXX_DiscardUnknown() {\n\txxx_messageInfo_RoomInfo.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_RoomInfo proto.InternalMessageInfo\n\nfunc (m *RoomInfo) GetId() string {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn \"\"\n}\n\nfunc (m *RoomInfo) GetAddr() string {\n\tif m != nil {\n\t\treturn m.Addr\n\t}\n\treturn \"\"\n}\n\ntype Response struct {\n\tCode                 int32    `protobuf:\"varint,1,opt,name=code,proto3\" json:\"code,omitempty\"`\n\tMsg                  string   `protobuf:\"bytes,2,opt,name=msg,proto3\" json:\"msg,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *Response) Reset()         { *m = Response{} }\nfunc (m *Response) String() string { return proto.CompactTextString(m) }\nfunc (*Response) ProtoMessage()    {}\nfunc (*Response) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_c5fd27dd97284ef4, []int{1}\n}\n\nfunc (m *Response) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_Response.Unmarshal(m, b)\n}\nfunc (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_Response.Marshal(b, m, deterministic)\n}\nfunc (m *Response) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Response.Merge(m, src)\n}\nfunc (m *Response) XXX_Size() int {\n\treturn xxx_messageInfo_Response.Size(m)\n}\nfunc (m *Response) XXX_DiscardUnknown() {\n\txxx_messageInfo_Response.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Response proto.InternalMessageInfo\n\nfunc (m *Response) GetCode() int32 {\n\tif m != nil {\n\t\treturn m.Code\n\t}\n\treturn 0\n}\n\nfunc (m *Response) GetMsg() string {\n\tif m != nil {\n\t\treturn m.Msg\n\t}\n\treturn \"\"\n}\n\nfunc init() {\n\tproto.RegisterType((*RoomInfo)(nil), \"register.RoomInfo\")\n\tproto.RegisterType((*Response)(nil), \"register.Response\")\n}\n\nfunc init() {\n\tproto.RegisterFile(\"room.proto\", fileDescriptor_c5fd27dd97284ef4)\n}\n\nvar fileDescriptor_c5fd27dd97284ef4 = []byte{\n\t// 215 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x90, 0xb1, 0x4e, 0xc3, 0x30,\n\t0x10, 0x86, 0x49, 0x28, 0x25, 0xbd, 0x01, 0xa1, 0x9b, 0x2a, 0xa6, 0xca, 0x13, 0x93, 0x83, 0x5a,\n\t0xf1, 0x02, 0x2d, 0x03, 0x2c, 0x0c, 0x16, 0x13, 0x9b, 0x1b, 0x1f, 0xc1, 0x12, 0xee, 0x45, 0x77,\n\t0x66, 0xe0, 0x85, 0x78, 0x4e, 0x14, 0x2b, 0x91, 0x18, 0x61, 0xf2, 0xa7, 0xdf, 0xfa, 0xf4, 0x49,\n\t0x07, 0x20, 0xcc, 0xc9, 0x0e, 0xc2, 0x99, 0xb1, 0x11, 0xea, 0xa3, 0x66, 0x12, 0x63, 0xa1, 0x71,\n\t0xcc, 0xe9, 0xe9, 0xf4, 0xc6, 0x78, 0x05, 0x75, 0x0c, 0xeb, 0x6a, 0x53, 0xdd, 0xae, 0x5c, 0x1d,\n\t0x03, 0x22, 0x2c, 0x7c, 0x08, 0xb2, 0xae, 0xcb, 0x52, 0xd8, 0xdc, 0x41, 0xe3, 0x48, 0x07, 0x3e,\n\t0x29, 0x8d, 0xff, 0x1d, 0x07, 0x2a, 0xc6, 0x85, 0x2b, 0x8c, 0xd7, 0x70, 0x9e, 0xb4, 0x9f, 0x94,\n\t0x11, 0xb7, 0xdf, 0x15, 0x2c, 0xc6, 0x04, 0x6e, 0x61, 0x79, 0x10, 0xf2, 0x99, 0x10, 0xed, 0xdc,\n\t0xb7, 0x73, 0xfc, 0xe6, 0xf7, 0x36, 0x05, 0xcc, 0x19, 0xde, 0xc3, 0xea, 0x91, 0xbc, 0xe4, 0x3d,\n\t0xf9, 0xfc, 0x0f, 0x6d, 0x07, 0x97, 0x0f, 0xa4, 0x59, 0xf8, 0xeb, 0xef, 0xd2, 0xde, 0xbc, 0x6e,\n\t0xfa, 0x98, 0xdf, 0x3f, 0x8f, 0xb6, 0xe3, 0xd4, 0xbe, 0x90, 0x7e, 0xf8, 0xc3, 0x73, 0xdb, 0x71,\n\t0x1a, 0xbc, 0x6a, 0x5b, 0x0e, 0x77, 0x5c, 0x96, 0x67, 0xf7, 0x13, 0x00, 0x00, 0xff, 0xff, 0xb6,\n\t0xf4, 0x05, 0x73, 0x4d, 0x01, 0x00, 0x00,\n}\n
PS C:\Users\sia\GolandProjects\compass\proto>

报错的直接原因,就是生成的内容中多了一句:

Active code page: 1252

问题关键点在于,protoc 在生成代码的时候,会启动一个新的 Shell 实例。在 Windows 环境,这个 Shell 可能就是 CMD。

在 Windows 的 CMD 启动的时候,如果配置了 AutoRun(自动执行命令),则每次 CMD 启动的时候都会先执行一下 AutoRun 配置的命令,所以输出结果就多了一些 protoc 无法识别的内容。

解决

按照 StackOverFlow 上的解决方案,就是检查注册表是否配置了自动运行命令,相关的 key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun

如果有的话,去除后重新尝试生成。

不知道 protoc 能否指定使用的 Shell。

过程

某一天,我准备用 Golang + gRPC 写写 hello, world,因此建了一个 Go 项目并引入了 gRPC 相关依赖。

建立了一个文件 room.proto

syntax = "proto3";
package register;
option go_package = "github.com/TeslaCN/compass/proto";
service Room {
    rpc Create (RoomInfo) returns (Response) {}
    rpc HeartBeat (RoomInfo) returns (Response) {}
    rpc Destroy (RoomInfo) returns (Response) {}
}
message RoomInfo {
    string id = 1;
    string addr = 2;
}
message Response {
    int32 code = 1;
    string msg = 2;
}

结果,用 protocproto-gen-go 插件生成代码的时候,一直生成不了,报错。

后来提 Issue、换版本都没有解决。

最后,Issue 有个回复提到了生成内容中多了 Active code page: 1252,我才意识到这是生成代码报错的直接原因。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuweijie@apache.org

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值