某一天,正想用 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
,我才意識到這是生成代碼報錯的直接原因。