Derleme sistemi, rust_bindgen modül türü aracılığıyla bindgen bağlamalarını oluşturmayı destekler. Bindgen, C kitaplıklarına Rust FFI bağlamaları sağlar (cppstd mülkünün ayarlanmasını gerektiren sınırlı C++ desteğiyle).

rust_bindgen'in temel kullanımı

Aşağıda, bindgen kullanan bir modülün nasıl tanımlanacağına ve bu modülün kafes olarak nasıl kullanılacağına dair bir örnek verilmiştir. Harici kod için olduğu gibi bir include!() makrosu aracılığıyla bindgen bağlamalarını kullanmanız gerekiyorsa Kaynak Oluşturucular sayfasına 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 örnek bir C kitaplığı 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ımlayın

Alakalı tüm üstbilgileri içeren bir sarmalayıcı üstbilgisi (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 başlıklı bindgen kılavuz bölümüne bakın.

include!() makrosu kullanmanın ön koşulu olarak bir rust_bindgen modülünü tanımlamak için bu bölümü kullandıysanız Kaynak Oluşturucular sayfasındaki Ön koşul'a dönün. Aksi takdirde sonraki bölümlere geçin.

Bağlamaları kafes olarak kullanın

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) }
}

Son olarak, ikili dosyayı oluşturmak için m hello_bindgen işlevini çağırın.

Bindgen bağlamalarını test et

Bindgen bağlamaları genellikle bellek düzeni uyuşmazlıklarını önlemek için oluşturulmuş bir dizi 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.

Bunlar için bir test ikili dosyası, external/rust/hello_bindgen/Android.bp içinde bir rust_test modülü tanımlanarak kolayca üretilebilir:

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, tür tanımlarından, işlev imzalarından ve ilgili sabitlerden oluştuğu için genellikle çok küçüktür. Bu nedenle, bu kitaplıkları dinamik olarak bağlamak genellikle gereksizdir. Bu modülleri rustlibs üzerinden kullanırken otomatik olarak statik bir varyantın seçilmesi için dinamik bağlantıyı devre dışı bıraktık.

Varsayılan olarak rust_bindgen modülleri, [":__subpackages__"] değerine sahip bir visibility mülküne sahiptir. Bu mülk, yalnızca aynı Android.bp dosyasındaki veya dizin hiyerarşisinde bu dosyanın altındaki modüllerin bu mülkü görmesine izin verir. Bunun iki amacı vardır:

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

Genellikle, diğer geliştiricilerin kullanması için oluşturulan modülün etrafına, bağlamalarla aynı dizin ağacına eklediğiniz güvenli bir sarmalayıcı kitaplığı sağlamanız gerekir. Kullanım alanınız için bu yöntem işe yaramazsa görünürlük özelliğine ek paketler ekleyebilirsiniz. İlave görünürlük kapsamları eklerken lütfen gelecekte aynı sürece bağlanabilecek iki kapsam eklememeye dikkat edin, aksi takdirde bu kapsamlar birbirine bağlanamayabilir.

Önemli rust_bindgen özellikleri

Aşağıda 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 özellikle önemlidir veya rust_bindgen modülü türüne özgü benzersiz bir davranış sergiler.

stem, name, crate_name

rust_bindgen, kitaplık varyantları oluşturduğundan stem, name ve crate_name mülkleri için rust_library modülleriyle aynı gereksinimleri paylaşır. Referans olarak Önemli Rust kitaplığı özellikleri bölümüne bakın.

wrapper_src

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

source_stem

Bu, oluşturulan kaynak dosyanın dosya adıdır. stem mülkü yalnızca oluşturulan kitaplık varyantlarının çıkış dosya adını kontrol ettiğinden, bağlamaları paket olarak kullanıyor olsanız bile bu alan tanımlanmalıdır. Bir modül rustlibs üzerinden kasalardan ziyade birden fazla kaynak oluşturucuya (bindgen ve protobuf gibi) bağımlıysa bu modülün bağımlılığı olan tüm kaynak üreticilerin benzersiz source_stem değerlerine sahip olduğundan emin olmanız gerekir. Bağımlı modüller, srcs içinde tanımlanan tüm SourceProvider bağımlılık kaynaklarını ortak bir OUT_DIR dizine kopyalar. Bu nedenle, source_stem'daki çakışmalar, oluşturulan kaynak dosyaların OUT_DIR dizininde üzerine yazılmasına neden olur.

c_std

Bu, kullanılacak C standardı sürümünü temsil eden bir dizedir. Geçerli değerler aşağıda listelenmiştir:

  • "gnu11" gibi belirli bir sürüm.
  • build/soong/cc/config/global.go'ta derleme sistemi tarafından tanımlanan bir değer olan "experimental", mevcut olduğunda C++1z gibi taslak sürümleri kullanabilir.
  • Ayarlanmamış veya "" (derleme sistemi varsayılanının kullanılacağını belirtir).

Bu ayarlanırsa dosya uzantısı yoksayılır ve başlığın, C başlığı olduğu varsayılır. Bu, cpp_std ile aynı anda ayarlanamaz.

cpp_std

cpp_std, kullanılacak C standart sürümünü temsil eden bir dizedir. Geçerli değerler:

  • Belirli bir sürüm (ör. "gnu++11")
  • build/soong/cc/config/global.go'ta derleme sistemi tarafından tanımlanan bir değer olan "experimental", mevcut olduğunda C++1z gibi taslak sürümleri kullanabilir.
  • Ayarlanmamış veya "" (derleme sisteminin varsayılanının kullanılacağını belirtir).

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

cflags

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

custom_bindgen

Gelişmiş kullanım alanları için bindgen, kitaplık olarak kullanılabilir. Bu kitaplık, özel bir Rust ikili dosyası kapsamında değiştirilebilecek bir API sağlar. custom_bindgen alanı, normal bindgen ikili dosyası yerine bindgen API'yi kullanan bir rust_binary_host modülünün modül adını alır.

Bu özel ikili, bindgen'e 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 büyük bir kısmı bindgen kitaplığı tarafından yürütülür. Bu kullanıma dair 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 nadiren tanımlanması veya değiştirilmesi gerekir.

işleyici_static_inline ve static_inline_library

Bu iki özelliğin birlikte kullanılması amaçlanmıştır. Böylece, dışa aktarılan bağlama bağlamalarına eklenebilecek statik satır içi işlevler için sarmalayıcılar oluşturabilirsiniz.

Bunları kullanmak için handle_static_inline: true ve static_inline_library'yi, rust_bindgen modülünü kaynak girişi olarak tanımlayan ilgili bir 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 fucntions
        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: ["."],
    }