ohos_rust_binding 0.1.0

Rust binding for OHOS
Documentation
use bindgen::Builder;
use std::{env, path::PathBuf};

const SUPPORTED_TARGETS: &[&str] = &["aarch64-unknown-linux-ohos"];

fn main() {
    // Get cargo build target
    let target = env::var("TARGET").expect("TARGET environment variable not set");

    if !SUPPORTED_TARGETS.contains(&target.as_str()) {
        println!(
            "cargo:warning=Skipping bindgen generation on unsupported target: {}",
            target
        );
        return;
    }

    let home = env::var("OHOS_NATIVE_HOME").expect("OHOS_NATIVE_HOME environment variable not set");
    // Add native SDK bin path to front of PATH
    let bin_path = env::var("PATH").unwrap_or_default();
    env::set_var("PATH", format!("{}/llvm/bin:{}", home, bin_path));

    let builder = bindgen::Builder::default()
        .clang_arg("-x")
        .clang_arg("c++")
        .clang_arg(format!("--target={}", target))
        .rust_target(bindgen::RustTarget::Stable_1_68)
        .default_enum_style(bindgen::EnumVariation::ModuleConsts);

    generate_egl(&builder);
    generate_drawing(&builder);
    generate_log(&builder);
    generate_napi(&builder);
    generate_vsync(&builder);
    generate_window(&builder);
    generate_xcomponent(&builder);
    generate_rdb(&builder);
    generate_hidebug(&builder);
    generate_bundle(&builder);
    generate_input(&builder);
    generate_account(&builder);
    generate_hitrace(&builder);
    generate_asset(&builder);
    generate_hiappevent(&builder);
    generate_web(&builder);
}

fn generate_hiappevent(builder: &Builder) {
    generate(
        "hiappevent",
        &[
            "hiappevent/hiappevent.h",
            "hiappevent/hiappevent_cfg.h",
            "hiappevent/hiappevent_event.h",
            "hiappevent/hiappevent_param.h",
        ],
        &["hiappevent_ndk.z"],
        || {
            builder
                .clone()
                .allowlist_item("(OH_.*)|(EVENT.*)|(HiAppEvent.*)|(DOMAIN_.*)")
        },
    );
}

fn generate_asset(builder: &Builder) {
    generate(
        "asset",
        &["asset/asset_api.h", "asset/asset_type.h"],
        &["asset_ndk.z"],
        || builder.clone().allowlist_item("(OH.*)|(Asset_.*)"),
    );
}

fn generate_hitrace(builder: &Builder) {
    generate("hitrace", &["hitrace/trace.h"], &["hitrace_ndk.z"], || {
        builder.clone().allowlist_item("OH_.*")
    });
}

fn generate_account(builder: &Builder) {
    generate(
        "account",
        &[
            "BasicServicesKit/os_account.h",
            "BasicServicesKit/os_account_common.h",
        ],
        &["os_account_ndk"],
        || builder.clone().allowlist_item("OH_.*"),
    );
}

fn generate_input(builder: &Builder) {
    generate(
        "input",
        &[
            "multimodalinput/o_input_manager.h",
            "multimodalinput/oh_key_code.h",
        ],
        &["ohinput"],
        || {
            builder
                .clone()
                .allowlist_item("OH_.*")
                .allowlist_item("Input_.*")
        },
    );
}

fn generate_bundle(builder: &Builder) {
    generate(
        "bundle",
        &["bundle/native_interface_bundle.h"],
        &["bundle_ndk.z"],
        || builder.clone().allowlist_item("OH_.*"),
    );
}

fn generate_hidebug(builder: &Builder) {
    generate(
        "hidebug",
        &["hidebug/hidebug.h", "hidebug/hidebug_type.h"],
        &["ohhidebug"],
        || builder.clone().allowlist_item("OH_.*"),
    );
}

fn generate_rdb(builder: &Builder) {
    generate(
        "rdb",
        &[
            "database/rdb/oh_cursor.h",
            "database/rdb/oh_predicates.h",
            "database/rdb/oh_value_object.h",
            "database/rdb/oh_value_bucket.h",
            "database/rdb/relational_store.h",
            "database/rdb/relational_store_error_code.h",
            "database/data/data_asset.h",
        ],
        &["native_rdb_ndk.z"],
        || builder.clone().allowlist_item("OH_.*"),
    );
}

fn generate_xcomponent(builder: &Builder) {
    generate(
        "xcomponent",
        &["ace/xcomponent/native_interface_xcomponent.h"],
        &["ace_ndk.z"],
        || builder.clone().allowlist_item("OH_.*"),
    );
}

fn generate_window(builder: &Builder) {
    generate(
        "window",
        &[
            "native_window/external_window.h",
            "native_image/native_image.h",
        ],
        &["native_window", "native_image"],
        || builder.clone().allowlist_function("OH_.*"),
    );
}

fn generate_vsync(builder: &Builder) {
    generate(
        "vsync",
        &["native_vsync/native_vsync.h"],
        &["native_vsync"],
        || builder.clone().allowlist_function("OH_NativeVSync.*"),
    );
}

fn generate_egl(builder: &Builder) {
    generate(
        "egl",
        &["EGL/egl.h", "EGL/eglext.h", "EGL/eglplatform.h"],
        &["EGL", "GLESv3"],
        || builder.clone(),
    );
}

fn generate_drawing(builder: &Builder) {
    generate(
        "drawing",
        &[
            "native_drawing/drawing_bitmap.h",
            "native_drawing/drawing_brush.h",
            "native_drawing/drawing_canvas.h",
            "native_drawing/drawing_color.h",
            "native_drawing/drawing_font_collection.h",
            "native_drawing/drawing_gpu_context.h",
            "native_drawing/drawing_matrix.h",
            "native_drawing/drawing_path.h",
            "native_drawing/drawing_pen.h",
            "native_drawing/drawing_point.h",
            "native_drawing/drawing_rect.h",
            "native_drawing/drawing_register_font.h",
            "native_drawing/drawing_sampling_options.h",
            "native_drawing/drawing_shader_effect.h",
            "native_drawing/drawing_surface.h",
            "native_drawing/drawing_text_declaration.h",
            "native_drawing/drawing_text_typography.h",
            "native_drawing/drawing_types.h",
        ],
        &["native_drawing"],
        || {
            builder
                .clone()
                .allowlist_type("OH_Drawing_.*")
                .allowlist_function("OH_Drawing_.*")
        },
    );
}

fn generate_napi(builder: &Builder) {
    generate("napi", &["napi/native_api.h"], &["ace_napi.z"], || {
        builder.clone().allowlist_function("napi_.*")
    });
}

fn generate_log(builder: &Builder) {
    generate("log", &["hilog/log.h"], &["hilog_ndk.z"], || {
        builder.clone().allowlist_function("OH_LOG_.*")
    })
}

fn generate_web(builder: &Builder) {
    generate(
        "web",
        &[
            "web/arkweb_error_code.h",
            "web/arkweb_interface.h",
            "web/arkweb_net_error_list.h",
            "web/arkweb_scheme_handler.h",
            "web/arkweb_type.h",
            "web/native_interface_arkweb.h",
        ],
        &["ohweb"],
        || {
            builder
                .clone()
                .allowlist_type("ArkWeb_.*")
                .allowlist_function("OH_ArkWeb_.*")
        },
    );
}

fn generate(
    feature: &str,
    headers: &[&str],
    libs: &[&str],
    factory: impl FnOnce() -> bindgen::Builder,
) {
    let key = format!("CARGO_FEATURE_{}", feature.to_ascii_uppercase());
    let name = format!("wrapper_{}.hpp", feature);
    if env::var(&key).is_err() {
        return;
    }
    for lib in libs {
        println!("cargo:rustc-link-lib={}", lib);
    }
    println!("cargo:rerun-if-changed={}", name);
    let content = headers
        .iter()
        .map(|h| format!("#include <{}>", h))
        .collect::<Vec<_>>()
        .join("\n");
    let bindings = factory()
        .header_contents(&name, &content)
        .generate()
        .unwrap_or_else(|_| panic!("Unable to generate bindings for {}", feature));
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap_or_default());
    bindings
        .write_to_file(out_path.join(format!("{feature}_sys.rs")))
        .unwrap_or_else(|_| panic!("Unable to write bindings for {}", feature));
}