0

Bài 3: Cài đặt công cụ và Biên dịch thủ công với protoc trong Golang

Ở hai bài học trước, chúng ta đã nắm vững cách viết cú pháp chuẩn cho các file định nghĩa .proto. Tuy nhiên, file .proto tự thân nó chỉ là một file văn bản thô (plain text). Để ứng dụng Golang của bạn có thể hiểu và sử dụng được các cấu trúc dữ liệu đó, chúng ta cần biên dịch chúng thành mã nguồn Go (.pb.go).

Trong bài học này, chúng ta sẽ thực hiện cài đặt các công cụ biên dịch cốt lõi và thực hiện biên dịch thủ công qua dòng lệnh.

1. Chuẩn bị bộ công cụ biên dịch (Toolchain)

Để biên dịch một file .proto sang mã nguồn Golang, bạn cần cài đặt 3 thành phần chính trên máy tính:

  1. protoc (Protocol Compiler): Trình biên dịch gốc bằng C++ do Google phát triển, chịu trách nhiệm đọc file .proto và phân tích cú pháp.

  2. protoc-gen-go: Go plugin chính thức giúp protoc sinh ra các cấu trúc Struct và hàm mã hóa/giải mã (Serialization) tương thích với Go.

  3. protoc-gen-go-grpc: Go plugin dùng riêng để sinh ra mã nguồn giao tiếp gRPC (Client/Server stubs) nếu file .proto của bạn có định nghĩa service.

Hướng dẫn cài đặt nhanh:

  • Trên macOS (dùng Homebrew):

    Bash

    brew install protobuf
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    
    
  • Trên Linux (Ubuntu/Debian):

    Bash

    sudo apt update && sudo apt install -y protobuf-compiler
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    
    
  • Lưu ý quan trọng: Hãy đảm bảo rằng đường dẫn thư mục chứa các binary của Go ($(go env GOPATH)/bin) đã được thêm vào biến môi trường PATH của hệ điều hành, nếu không protoc sẽ không tìm thấy các plugin để chạy.

2. Cấu trúc thư mục dự án chuẩn

Trước khi chạy lệnh biên dịch, việc tổ chức thư mục dự án gọn gàng là điều kiện tiên quyết để mã nguồn sinh ra không bị lẫn lộn. Một dự án Go chuẩn thường có cấu trúc như sau:

Plaintext

my-grpc-project/
├── go.mod
├── proto/
│   └── user.proto  <-- File định nghĩa gốc
└── pb/             <-- Thư mục chứa code Go được sinh ra tự động

Khởi tạo module Go và tải các thư viện cần thiết:

Bash

go mod init github.com/your-username/my-grpc-project
go get google.golang.org/protobuf
go get google.golang.org/grpc

3. Viết file .proto mẫu hoàn chỉnh

Tạo file proto/user.proto với nội dung tích hợp cả Message và gRPC Service để kiểm tra việc sinh code toàn diện:

Protocol Buffers

syntax = "proto3";

package user;

// Cấu hình đường dẫn sinh code trỏ thẳng vào thư mục pb bên ngoài
option go_package = "github.com/your-username/my-grpc-project/pb;pb";

message GetUserRequest {
    int64 id = 1;
}

message UserResponse {
    int64 id = 1;
    string name = 2;
    string email = 3;
}

// Định nghĩa gRPC Service để kiểm tra protoc-gen-go-grpc
service UserService {
    rpc GetUser(GetUserRequest) returns (UserResponse);
}

4. Thực thi lệnh biên dịch thủ công với protoc

Mở terminal tại thư mục gốc của dự án (my-grpc-project), chạy câu lệnh protoc sau đây:

Bash

protoc \
  --proto_path=proto \
  --go_out=pb \
  --go_opt=paths=source_relative \
  --go-grpc_out=pb \
  --go-grpc_opt=paths=source_relative \
  proto/user.proto

Giải thích chi tiết từng tham số trong câu lệnh:

  • --proto_path=proto (hoặc -I=proto): Chỉ định cho trình biên dịch biết thư mục chứa các file .proto nguồn.

  • --go_out=pb: Yêu cầu sử dụng plugin protoc-gen-go để sinh code Go và đặt kết quả vào thư mục pb.

  • --go_opt=paths=source_relative: Giữ nguyên cấu trúc cây thư mục giống hệt như trong thư mục proto khi sinh ra ở thư mục đích.

  • --go-grpc_out=pb và --go-grpc_opt=paths=source_relative: Yêu cầu sinh thêm các interface gRPC Client/Server tương ứng.

  • proto/user.proto: Đường dẫn của file .proto cần biên dịch.

5. Kiểm tra kết quả

Sau khi chạy lệnh thành công, hãy kiểm tra thư mục pb/ của bạn. Bạn sẽ thấy hai file mới được tự động sinh ra:

  1. user.pb.go: Chứa toàn bộ các Struct Go (GetUserRequest, UserResponse) và các phương thức mã hóa nhị phân (Marshal, Unmarshal).

  2. user_grpc.pb.go: Chứa các interface gRPC Client và Server (UserServiceClient, UserServiceServer) để bạn dễ dàng viết code network ở các bài sau.

💡 Mẹo nhỏ: Việc gõ một dòng lệnh protoc dài dòng như trên mỗi khi sửa một dấu chấm trong file .proto rất dễ gây mỏi tay và sai sót. Trong thực tế, các kỹ sư sẽ gom nhóm chúng lại thành một câu lệnh tự động bằng Makefile. Đó chính là nội dung của Bài 5 sắp tới.

Bây giờ cấu trúc dữ liệu đã được biên dịch thành mã nguồn Go hoàn chỉnh. Ở bài học tiếp theo, chúng ta sẽ bắt tay vào việc viết code thực tế để hiện thực hóa gRPC Server và Client.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí