某一天,正想用 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;
}
结果,用 protoc
和 proto-gen-go
插件生成代码的时候,一直生成不了,报错。
后来提 Issue、换版本都没有解决。
最后,Issue 有个回复提到了生成内容中多了 Active code page: 1252
,我才意识到这是生成代码报错的直接原因。