Bindgen bağlama modülleri

Derleme sistemi, rust_bindgen modül türü aracılığıyla bindgen bağlamalarının oluşturulmasını destekler. Bindgen, C kitaplıkları için Rust FFI bağlamaları sağlar (bazı sınırlı C++ desteğiyle birlikte, bu da cppstd özelliğinin ayarlanmasını gerektirir).

Temel rust_bindgen kullanımı

Aşağıda, bindgen kullanan bir modülün nasıl tanımlanacağı ve bu modülün nasıl bir paket olarak kullanılacağı ile ilgili bir örnek verilmiştir. Harici kod gibi durumlarda include!() makrosu aracılığıyla bindgen bağlamalarını kullanmanız gerekiyorsa Kaynak oluşturucular bölümüne bakın.

Rust'tan çağrılacak örnek C kitaplığı

Aşağıda, Rust'ta kullanılmak üzere bir yapı ve işlev tanımlayan bir C kitaplığı örneği verilmiştir.

external/rust/libbuzz/libbuzz.h

typedef struct foo {
    int x;
} foo;

void fizz(int i, foo* cs);

external/rust/libbuzz/libbuzz.c

#include <stdio.h>
#include "libbuzz.h"

void fizz(int i, foo* my_foo){
    printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}

rust_bindgen modülü tanımlama

Tüm alakalı başlıkları içeren bir sarmalayıcı başlık (external/rust/libbuzz/libbuzz_wrapper.h) tanımlayın:

// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"

Android.bp dosyasını external/rust/libbuzz/Android.bp olarak tanımlayın:

cc_library {
    name: "libbuzz",
    srcs: ["libbuzz.c"],
}

rust_bindgen {
     name: "libbuzz_bindgen",

     // Crate name that's used to generate the rust_library variants.
     crate_name: "buzz_bindgen",

     // Path to the wrapper source file.
     wrapper_src: "libbuzz_wrapper.h",

     // 'source_stem' controls the output filename.
     // This is the filename that's used in an include! macro.
     //
     // In this case, we just use "bindings", which produces
     // "bindings.rs".
     source_stem: "bindings",

     // Bindgen-specific flags and options to customize the bindings.
     // See the bindgen manual for more information.
     bindgen_flags: ["--verbose"],

     // Clang flags to be used when generating the bindings.
     cflags: ["-DSOME_FLAG"],

     // Shared, static, and header libraries which export the necessary
     // include directories must be specified.
     //
     // These libraries will also be included in the crate if static,
     // or propagated to dependents if shared.
     // static_libs: ["libbuzz"]
     // header_libs: ["libbuzz"]
     shared_libs: ["libbuzz"],
}

Bindgen işaretlerini kullanma hakkında daha fazla bilgi edinmek için Oluşturulan Bağlantıları Özelleştirme ile ilgili bindgen kılavuzu bölümüne bakın.

Bu bölümü kullanarak rust_bindgen modülünü include!() makrosunu kullanmak için ön koşul olarak tanımladıysanız Kaynak Oluşturucular sayfasındaki Ön koşul bölümüne dönün. Aksi takdirde, sonraki bölümlere geçin.

Bağlamaları sandık olarak kullanma

Aşağıdaki içerikle external/rust/hello_bindgen/Android.bp oluşturun:

rust_binary {
   name: "hello_bindgen",
   srcs: ["main.rs"],

   // Add the rust_bindgen module as if it were a rust_library dependency.
   rustlibs: ["libbuzz_bindgen"],
}

Aşağıdaki içerikle external/rust/hello_bindgen/src/main.rs oluşturun:

//! Example crate for testing bindgen bindings

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

Ardından, ikili dosyayı oluşturmak için m hello_bindgen'ı arayın.

Test bindgen bağlamaları

Bindgen bağlamaları, genellikle bellek düzeni uyuşmazlıklarını önlemek için bir dizi oluşturulmuş düzen testi içerir. AOSP, bu testler için tanımlanmış bir test modülünüz olmasını ve testlerin projenizin normal test paketi kapsamında çalıştırılmasını önerir.

rust_test içinde bir external/rust/hello_bindgen/Android.bp modülü tanımlayarak bunlar için test ikili programı oluşturabilirsiniz:

rust_test {
    name: "bindings_test",
    srcs: [
        ":libbuzz_bindgen",
    ],
    crate_name: "buzz_bindings_test",
    test_suites: ["general-tests"],
    auto_gen_config: true,

    // Be sure to disable lints as the generated source
    // is not guaranteed to be lint-free.
    clippy_lints: "none",
    lints: "none",
}

Görünürlük ve bağlantı

Oluşturulan bağlamalar genellikle küçük olur. Bunun nedeni, tür tanımları, işlev imzaları ve ilgili sabitlerden oluşmalarıdır. Bu nedenle, bu kitaplıkları dinamik olarak bağlamak gereksizdir. Bu modüller için dinamik bağlantıyı devre dışı bıraktık. Böylece, bu modüller rustlibs ile kullanıldığında statik bir varyant otomatik olarak seçilir.

Varsayılan olarak, rust_bindgen modüllerinin visibility özelliği [":__subpackages__"]'dir. Bu özellik, aynı Android.bp dosyasındaki veya dizin hiyerarşisinde bu dosyanın altında yer alan modüllerin dosyayı görmesine izin verir. Bu durum iki amaca hizmet eder:

  • Ağacın başka yerlerinde ham C bağlamalarının kullanılmasını engeller.
  • Statik ve dinamik bağlantı karışımıyla elmas bağlantı sorunlarını önler.

Bağlamalarla aynı dizin ağacına eklediğiniz oluşturulmuş modülün etrafında, diğer geliştiricilerin kullanması için tasarlanmış güvenli bir sarmalayıcı kitaplık sağlamanız gerekir. Bu yöntem kullanım alanınız için işe yaramazsa visibility'a ek paketler ekleyebilirsiniz. Ek görünürlük kapsamları eklerken, gelecekte aynı işleme bağlanabilecek iki kapsam eklemeyin. Aksi takdirde bağlantı oluşturulamayabilir.

Önemli rust_bindgen özellikleri

Bu bölümde tanımlanan özellikler, tüm modüller için geçerli olan önemli ortak özelliklere ek olarak verilmiştir. Bunlar, Rust bindgen modülleri için önemlidir veya rust_bindgen modül türüne özgü benzersiz davranışlar sergiler.

stem, name, crate_name

rust_bindgen kitaplık varyantları oluşturur. Bu nedenle, stem, name ve crate_name özellikleri için rust_library modülleriyle aynı koşulları paylaşırlar. Referans için Önemli Rust kitaplık özellikleri başlıklı makaleyi inceleyin.

wrapper_src

Bu, bu bağlamalar için gereken üst dosyaları içeren bir sarmalayıcı üst dosyasının göreli yoludur. Dosya uzantısı, başlığın nasıl yorumlanacağını ve varsayılan olarak hangi -std işaretinin kullanılacağını belirler. Uzantı .hh veya .hpp değilse bunun bir C başlığı olduğu varsayılır. C++ başlığınızın başka bir uzantısı olması gerekiyorsa dosyanın C dosyası olduğunu varsayan varsayılan davranışı geçersiz kılmak için cpp_std özelliğini ayarlayın.

source_stem

Bu, oluşturulan kaynak dosyanın dosya adıdır. Bu alan, bağlamaları bir paket olarak kullanıyor olsanız bile tanımlanmalıdır. Bunun nedeni, stem özelliğinin yalnızca oluşturulan kitaplık varyantlarının çıkış dosya adını kontrol etmesidir. Bir modül, rustlibs üzerinden sandık olarak değil, kaynak olarak birden fazla kaynak oluşturucuya (ör. bindgen ve protobuf) bağlıysa bu modülün bağımlılıkları olan tüm kaynak oluşturucuların benzersiz source_stem değerlerine sahip olduğundan emin olun. Bağımlı modüller, SourceProvider srcs içinde tanımlanan tüm bağımlılıkların kaynaklarını ortak bir OUT_DIR dizinine kopyalar. Bu nedenle, source_stem içindeki çakışmalar, oluşturulan kaynak dosyaların OUT_DIR dizininde üzerine yazılmasına neden olur.

c_std

Bu, hangi C standardı sürümünün kullanılacağını gösteren bir dizedir. Geçerli değerler burada listelenmiştir:

  • Belirli bir sürüm (ör. gnu11)
  • experimental, build/soong/cc/config/global.go içinde derleme sistemi tarafından tanımlanan bir değerdir. Bu değer, build/soong/cc/config/global.go içinde kullanılabildiğinde C++1z gibi taslak sürümleri kullanabilir.
  • Derleme sistemi varsayılanının kullanılması gerektiğini belirten ayarlanmamış veya ""

Bu ayar belirlenirse dosya uzantısı yoksayılır ve üstbilginin C üstbilgisi olduğu varsayılır. Bu ayar, cpp_std ile aynı anda ayarlanamaz.

cpp_std

cpp_std, hangi C standardı sürümünün kullanılacağını gösteren bir dizedir. Geçerli değerler burada listelenmiştir:

  • Belirli bir sürüm (ör. gnu++11)
  • experimental, build/soong/cc/config/global.go içinde derleme sistemi tarafından tanımlanan bir değerdir. Bu değer, build/soong/cc/config/global.go içinde kullanılabildiğinde C++1z gibi taslak sürümleri kullanabilir.
  • Derleme sistemi varsayılanının kullanılması gerektiğini belirten ayarlanmamış veya ""

Bu ayar belirlenirse dosya uzantısı yoksayılır ve başlığın C++ başlığı olduğu varsayılır. Bu ayar, c_std ile aynı anda ayarlanamaz.

cflags

cflags, başlıkların doğru şekilde yorumlanması için gereken Clang işaretlerinin dize listesini sağlar.

custom_bindgen

İleri seviye kullanım alanları için bindgen, özel bir Rust ikili programının parçası olarak değiştirilebilen bir API sağlayan bir kitaplık olarak kullanılabilir. custom_bindgen alanı, normal bindgen ikili programı yerine bindgen API'sini kullanan bir rust_binary_host modülünün modül adını alır.

Bu özel ikili, bindgen'ya benzer şekilde bağımsız değişkenler beklemelidir. Örneğin:

$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]

Bu işlemlerin çoğu bindgen kitaplığı tarafından gerçekleştirilir. Bu kullanımla ilgili bir örnek görmek için external/rust/crates/libsqlite3-sys/android/build.rs adresini ziyaret edin.

Ayrıca, kitaplığın derlenmesini kontrol etmek için kitaplık özelliklerinin tamamı kullanılabilir. Ancak bu özelliklerin tanımlanması veya değiştirilmesi nadiren gerekir.

handle_static_inline ve static_inline_library

Bu iki özellik birlikte kullanılmak üzere tasarlanmıştır ve dışa aktarılan bindgen bağlamalarına dahil edilebilecek statik satır içi işlevler için sarmalayıcıların oluşturulmasına olanak tanır.

Bu işlevleri kullanmak için handle_static_inline: true ve static_inline_library değerini, rust_bindgen modülünü kaynak girişi olarak tanımlayan ilgili cc_library_static olarak ayarlayın.

Örnek kullanım:

    rust_bindgen {
        name: "libbindgen",
        wrapper_src: "src/any.h",
        crate_name: "bindgen",
        stem: "libbindgen",
        source_stem: "bindings",

        // Produce bindings for static inline functions
        handle_static_inline: true,
        static_inline_library: "libbindgen_staticfns"
    }

    cc_library_static {
        name: "libbindgen_staticfns",

        // This is the rust_bindgen module defined above
        srcs: [":libbindgen"],

        // The include path to the header file in the generated C file is
        // relative to build top.
        include_dirs: ["."],
    }