天天看点

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;
}
           

结果,用

protoc

proto-gen-go

插件生成代码的时候,一直生成不了,报错。

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

最后,Issue 有个回复提到了生成内容中多了

Active code page: 1252

,我才意识到这是生成代码报错的直接原因。