Генераторы источников

На этой странице представлен общий обзор того, как поддерживается сгенерированный исходный код и как его можно использовать в системе сборки.

Все генераторы исходного кода предоставляют схожую функциональность системы сборки. Три варианта использования генератора исходного кода, поддерживаемые системой сборки, — это генерация привязок C с использованием интерфейсов bindgen, AIDL и protobuf.

Ящики из сгенерированного источника

Каждый модуль Rust, который генерирует исходный код, может использоваться как контейнер, точно так же, как если бы он был определен как rust_library . (Это означает, что его можно определить как зависимость в свойствах rustlibs , rlibs и dylibs .) Лучший шаблон использования для кода платформы — использовать сгенерированный исходный код в качестве контейнера. Хотя макрос include! поддерживается для сгенерированного исходного кода, его основная цель — поддержка стороннего кода, который находится в external/ .

Существуют случаи, когда код платформы может по-прежнему использовать сгенерированный исходный код через макрос include!() , например, когда вы используете модуль genrule для генерации исходного кода уникальным образом.

Используйте include!() для включения сгенерированного исходного кода

Использование сгенерированного источника в качестве контейнера рассматривается в примерах на каждой конкретной (соответствующей) странице модуля. В этом разделе показано, как ссылаться на сгенерированный источник через макрос include!() . Обратите внимание, что этот процесс аналогичен для всех генераторов исходного кода.

Предпосылки

Этот пример основан на предположении, что вы определили модуль rust_bindgen ( libbuzz_bindgen ) и можете перейти к шагам по включению сгенерированного исходного кода для использования макроса include!() . Если вы этого не сделали, перейдите к разделу Определение модуля rust bindgen , создайте libbuzz_bindgen , а затем вернитесь сюда.

Обратите внимание, что части файла сборки применимы ко всем генераторам исходного кода.

Шаги по включению сгенерированного источника

Создайте external/rust/hello_bindgen/Android.bp со следующим содержимым:

rust_binary {
   name: "hello_bzip_bindgen_include",
   srcs: [
         // The primary rust source file must come first in this list.
         "src/lib.rs",

         // The module providing the bindgen bindings is
         // included in srcs prepended by ":".
         ":libbuzz_bindgen",
    ],

    // Dependencies need to be redeclared when generated source is used via srcs.
    shared_libs: [
        "libbuzz",
    ],
}

Создайте external/rust/hello_bindgen/src/bindings.rs со следующим содержимым:

#![allow(clippy::all)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(missing_docs)]

// Note that "bzip_bindings.rs" here must match the source_stem property from
// the rust_bindgen module.
include!(concat!(env!("OUT_DIR"), "/bzip_bindings.rs"));

Создайте external/rust/hello_bindgen/src/lib.rs со следующим содержимым:

mod bindings;

fn main() {
    let mut x = bindings::foo { x: 2 };
    unsafe { bindings::fizz(1, &mut x as *mut bindings::foo) }
}

Почему ящики для сгенерированного источника

В отличие от компиляторов C/C++, rustc принимает только один исходный файл, представляющий точку входа в двоичный файл или библиотеку. Он ожидает, что исходное дерево структурировано таким образом, что все требуемые исходные файлы могут быть автоматически обнаружены. Это означает, что сгенерированный исходный код должен быть либо помещен в исходное дерево, либо предоставлен через директиву include в исходном коде:

include!("/path/to/hello.rs");

Сообщество Rust зависит от скриптов build.rs и предположений о среде сборки Cargo, чтобы работать с этим различием . При сборке команда cargo устанавливает переменную среды OUT_DIR , в которую скрипты build.rs должны помещать сгенерированный исходный код. Используйте следующую команду для включения исходного кода:

include!(concat!(env!("OUT_DIR"), "/hello.rs"));

Это представляет собой проблему для Сунга, поскольку выходные данные для каждого модуля размещаются в собственном каталоге out/ 1. Не существует единого OUT_DIR , куда зависимости выводят свой сгенерированный исходный код.

Для кода платформы AOSP предпочитает упаковывать сгенерированный исходный код в контейнер, который можно импортировать, по нескольким причинам:

  • Предотвращайте конфликты имен сгенерированных исходных файлов.
  • Уменьшить количество шаблонного кода , проверяемого по всему дереву, который требует обслуживания. Любой шаблон, который требуется для компиляции сгенерированного исходного кода в контейнер, может поддерживаться централизованно.
  • Избегайте неявных взаимодействий между сгенерированным кодом и окружающим контейнером.
  • Снижение нагрузки на память и диск за счет динамического связывания часто используемых сгенерированных источников.

В результате все типы модулей генерации исходного кода Rust для Android создают код, который можно скомпилировать и использовать в качестве контейнера . Soong по-прежнему поддерживает сторонние контейнеры без изменений, если все сгенерированные исходные зависимости для модуля копируются в один каталог для каждого модуля, аналогично Cargo. В таких случаях Soong устанавливает переменную среды OUT_DIR в этот каталог при компиляции модуля, чтобы можно было найти сгенерированный исходный код. Однако по уже описанным причинам лучше всего использовать этот механизм в коде платформы только тогда, когда это абсолютно необходимо.


  1. Это не представляет никаких проблем для C/C++ и подобных языков, поскольку путь к сгенерированному исходному коду предоставляется непосредственно компилятору.

  2. Поскольку include! работает посредством текстового включения, он может ссылаться на значения из включающего пространства имен, изменять пространство имен или использовать конструкции вроде #![foo] . Эти неявные взаимодействия могут быть сложными для поддержки. Всегда предпочитайте макросы, когда взаимодействие с остальной частью контейнера действительно необходимо.