天天看點

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

,我才意識到這是生成代碼報錯的直接原因。