0Pricing
Learn Rust Coding · Урок

Генерация кода с 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 — локальная установка не требуется.

Все уроки этого курса

  1. Protobuf и определения сервисов
  2. Генерация кода с tonic-build
  3. Реализация сервера gRPC
  4. Вызовы из клиента gRPC
← Назад к Learn Rust Coding