Генерация кода с tonic-build
Компилируйте proto в Rust.
«Генерация кода с tonic-build» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.
Что делает tonic-build
tonic-build запускается во время компиляции и преобразует файлы .proto в исходный код Rust. Он оборачивает prost-build для сообщений и дополняет его трейтами и клиентами служб gRPC.
Он запускается из скрипта сборки Cargo (build.rs), поэтому генерация автоматически выполняется до компиляции крейта.
Зависимости Cargo
Вам понадобятся крейты времени выполнения и крейт времени сборки. tonic и prost являются обычными зависимостями, а tonic-build указывается в разделе [build-dependencies].
tonic использует tokio как асинхронную среду выполнения, поэтому его тоже нужно подключить.
[dependencies]
tonic = "0.12"
prost = "0.13"
tokio = { version = "1", features = ["full"] }
[build-dependencies]
tonic-build = "0.12"Минимальный build.rs
Создайте build.rs в корне крейта. Вызовите tonic_build::compile_protos, передав путь к файлу proto.
По умолчанию это компилирует код и клиента, и сервера и записывает его в OUT_DIR Cargo.
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("proto/greeter.proto")?;
Ok(())
}Настройка сборщика
Для более точной настройки используйте tonic_build::configure(). Вы можете отключить генерацию клиента или сервера, задать пути вывода или добавить атрибуты типов.
Здесь мы создаём сервер, но пропускаем клиента — это удобно для крейта, предназначенного только для серверной части.
tonic_build::configure()
.build_client(false)
.build_server(true)
.compile_protos(&["proto/greeter.proto"], &["proto"])?;Пути поиска
Второй аргумент compile_protos — это список каталогов для поиска. Импорты внутри proto, например google/protobuf/empty.proto, разрешаются относительно этих корневых каталогов.
Всегда добавляйте каталог, содержащий Ваши proto-файлы, чтобы импорты между файлами разрешались корректно.
tonic_build::configure()
.compile_protos(
&["proto/greeter.proto", "proto/health.proto"],
&["proto"],
)?;Куда попадает код
Сгенерированные файлы записываются в каталог из переменной окружения OUT_DIR и получают имя на основе пакета proto, например greeter.v1.rs.
Подключите их к своему крейту с помощью макроса include_proto! внутри модуля.
pub mod greeter {
pub mod v1 {
tonic::include_proto!("greeter.v1");
}
}Что генерируется
Для каждой службы tonic создаёт серверный модуль с трейтом (например, greeter_server::Greeter) и оболочкой GreeterServer, а также клиентскую структуру GreeterClient.
Каждое сообщение превращается в структуру Rust с производными реализациями Clone, PartialEq и Message из prost.
// generated (sketch):
// pub mod greeter_server { pub trait Greeter { /* methods */ } }
// pub mod greeter_client { pub struct GreeterClient<T> { /* ... */ } }Добавление производных реализаций с помощью type_attribute
Часто для сгенерированных структур нужны дополнительные производные реализации, например serde::Serialize. Используйте type_attribute, чтобы добавить атрибуты к определённым типам или ко всем типам с помощью ..
Это позволяет передавать сгенерированные сообщения в JSON API или тестовые наборы данных.
tonic_build::configure()
.type_attribute(".", "#[derive(serde::Serialize)]")
.compile_protos(&["proto/greeter.proto"], &["proto"])?;Запуск повторной сборки
Cargo повторно запускает build.rs только тогда, когда считает, что входные данные изменились. Выводите строки cargo:rerun-if-changed, чтобы изменения proto-файлов принудительно запускали генерацию.
Без этого изменённый proto может не обрабатываться заново, пока Вы не измените файл Rust.
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=proto/greeter.proto");
tonic_build::compile_protos("proto/greeter.proto")?;
Ok(())
}Требование protoc
Исторически tonic-build запускал компилятор protoc во внешнем процессе, поэтому его требовалось устанавливать отдельно. Современные версии могут использовать парсер protox на чистом Rust и не зависеть от него.
Если Вы видите ошибку об отсутствии protoc, установите protoc или включите функцию компилятора, поставляемого вместе с пакетом.
// In CI you may install protoc, e.g.:
// apt-get install -y protobuf-compilerНаборы дескрипторов файлов
Для отражения или продвинутых инструментов попросите tonic-build создать набор дескрипторов файлов с помощью file_descriptor_set_path.
Полученные байты можно передать в tonic-reflection, чтобы инструменты вроде grpcurl могли обнаруживать Ваши службы во время выполнения.
tonic_build::configure()
.file_descriptor_set_path(
std::env::var("OUT_DIR").unwrap() + "/greeter.bin")
.compile_protos(&["proto/greeter.proto"], &["proto"])?;Быстрая проверка
Куда попадает сгенерированный tonic-код и как он подключается?
Итоги
Вы подключили зависимости, написали build.rs, настроили генерацию клиента и сервера, а также пути поиска, подключили код через include_proto!, добавили производные реализации, настроили условия повторной сборки и узнали о protoc и наборах дескрипторов.
Далее Вы реализуете серверный трейт, созданный tonic.
Часто задаваемые вопросы
Урок «Генерация кода с tonic-build» бесплатный?
Да — полный текст урока «Генерация кода с tonic-build» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.
Чему я научусь в уроке «Генерация кода с tonic-build»?
Компилируйте proto в Rust. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Learn Rust Coding?
Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Генерация кода с tonic-build»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Learn Rust Coding?
Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Protobuf и определения сервисов
- Генерация кода с tonic-build
- Реализация сервера gRPC
- Вызовы из клиента gRPC