1 鸿蒙OpenHarmony开发板解析:【Rust模块配置规则和指导】-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙OpenHarmony开发板解析:【Rust模块配置规则和指导】

jf_46214456 来源: jf_46214456 作者: jf_46214456 2024-05-10 11:32 次阅读

概述

Rust是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust官方也使用Cargo工具来专门为Rust代码创建工程和构建编译。 OpenHarmony为了集成C/C++代码和提升编译速度,使用了GN + Ninja的编译构建系统。GN的构建语言简洁易读,Ninja的汇编级编译规则直接高效。 为了在OpenHarmony中集成Rust代码,并最大程度发挥Rust和OpenHarmony中原有C/C++代码的交互性,采用GN作为统一构建工具,即通过GN构建Rust源码文件(xxx.rs),并增加与C/C++互操作、编译时lint、测试、IDL转换、三方库集成、IDE等功能。同时扩展gn框架,支持接口自动化转换,最大程度简化开发。

基本概念

术语描述
CargoCargo是Rust官方使用的构建工具,允许Rust项目声明其各种依赖项,并确保您始终获得可重复的构建。
cratecrate是一个独立的可编译单元。
LintLint是指出常见编程错误、错误、样式错误和可疑结构的工具。可以对程序进行更加广泛的错误分析。

配置规则

OpenHarmony提供了用于Rust代码编译构建的各类型GN模板,可以用于编译Rust可执行文件,动态库和静态库等。各类型模板说明如下:

GN模板功能输出
ohos_rust_executablerust可执行文件rust可执行文件,不带后缀
ohos_rust_shared_liaryrust动态库rust dylib动态库,默认后缀.dylib.so
ohos_rust_static_liaryrust静态库rust rlib静态库,默认后缀.rlib
ohos_rust_proc_macrorust proc_macrorust proc_macro库, 默认后缀.so
ohos_rust_shared_ffirust FFI动态库rust cdylib动态库,给C/C++模块调用,默认后缀.so
ohos_rust_static_ffirust FFI静态库rust staticlib库,给C/C++模块调用,默认后缀.a
ohos_rust_cargo_crate三方包Cargo craterust三方crate,支持rlib、dylib、bin
ohos_rust_systemtestrust系统测试用例rust可执行系统测试用例,不带后缀
ohos_rust_unittestrust单元测试用例rust可执行单元测试用例,不带后缀
ohos_rust_fuzztestrust Fuzz测试用例rust可执行Fuzz测试用例,不带后缀

配置指导

配置Rust模块与C/C++模块类似,参考[模块配置规则]。下面是使用不同模板的示例。

开发前请熟悉鸿蒙开发指导文档:[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]

配置Rust静态库示例

该示例用于测试Rust可执行bin文件和静态库rlib文件的编译,以及可执行文件对静态库的依赖,使用模板ohos_rust_executable和ohos_rust_static_library。操作步骤如下:

  1. 创建build/rust/tests/test_rlib_crate/src/simple_printer.rs,如下所示:
    //! simple_printer
    
    /// struct RustLogMessage
    
    pub struct RustLogMessage {
        /// i32: id
        pub id: i32,
        /// String: msg
        pub msg: String,
    }
    
    /// function rust_log_rlib
    pub fn rust_log_rlib(msg: RustLogMessage) {
        println!("id:{} message:{:?}", msg.id, msg.msg)
    }
    
  2. 创建build/rust/tests/test_rlib_crate/src/main.rs,如下所示:
    //! rlib_crate example for Rust.
    
    extern crate simple_printer_rlib;
    
    use simple_printer_rlib::rust_log_rlib;
    use simple_printer_rlib::RustLogMessage;
    
    fn main() {
        let msg: RustLogMessage = RustLogMessage {
            id: 0,
            msg: "string in rlib crate".to_string(),
        };
        rust_log_rlib(msg);
    }
    
  3. 配置gn脚本build/rust/tests/test_rlib_crate/BUILD.gn,如下所示:
    import("//build/ohos.gni")
    
    ohos_rust_executable("test_rlib_crate") {
      sources = [ "src/main.rs" ]
      deps = [ ":simple_printer_rlib" ]
    }
    
    ohos_rust_static_library("simple_printer_rlib") {
      sources = [ "src/simple_printer.rs" ]
      crate_name = "simple_printer_rlib"
      crate_type = "rlib"
      features = [ "std" ]
    }
    
  4. 执行编译得到的可执行文件,运行结果如下:
    test_rlib_crate

配置三方库示例

rust三方库的BUILD.gn文件可通过cargo2gn工具自动生成。参见:[Cargo2gn工具操作指导]

该示例用于测试包含预编译文件build.rs的三方静态库rlib文件的编译,使用了模板ohos_rust_executable和ohos_rust_cargo_crate。操作步骤如下:

  1. 创建build/rust/tests/test_rlib_cargo_crate/crate/src/lib.rs,如下所示:
    include!(concat!(env!("OUT_DIR"), "/generated/generated.rs"));
    
    pub fn say_hello_from_crate() {
        assert_eq!(run_some_generated_code(), 45);
        #[cfg(is_new_rustc)]
        println!("Is new rustc");
        #[cfg(is_old_rustc)]
        println!("Is old rustc");
        #[cfg(is_ohos)]
        println!("Is ohos");
        #[cfg(is_mac)]
        println!("Is darwin");
        #[cfg(has_feature_a)]
        println!("Has feature_a");
        #[cfg(not(has_feature_a))]
        panic!("Wasn't passed feature_a");
        #[cfg(not(has_feature_b))]
        #[cfg(test_a_and_b)]
        panic!("feature_b wasn't passed");
        #[cfg(has_feature_b)]
        #[cfg(not(test_a_and_b))]
        panic!("feature_b was passed");
    }
    
    #[cfg(test)]
    mod tests {
        /// Test features are passed through from BUILD.gn correctly. This test is the target configuration.
        #[test]
        #[cfg(test_a_and_b)]
        fn test_features_passed_target1() {
            #[cfg(not(has_feature_a))]
            panic!("feature a was not passed");
            #[cfg(not(has_feature_b))]
            panic!("feature b was not passed");
        }
    
        #[test]
        fn test_generated_code_works() {
            assert_eq!(crate::run_some_generated_code(), 45);
        }
    }
    
  2. 创建build/rust/tests/test_rlib_cargo_crate/crate/src/main.rs,如下所示:
    pub fn main() {
        test_rlib_crate::say_hello_from_crate();
    }
    
  3. 创建build/rust/tests/test_rlib_cargo_crate/crate/build.rs,如下所示:
    use std::env;
    use std::path::Path;
    use std::io::Write;
    use std::process::Command;
    use std::str::{self, FromStr};
    
    fn main() {
        println!("cargo:rustc-cfg=build_script_ran");
        let my_minor = match rustc_minor_version() {
            Some(my_minor) = > my_minor,
            None = > return,
        };
    
        if my_minor >= 34 {
            println!("cargo:rustc-cfg=is_new_rustc");
        } else {
            println!("cargo:rustc-cfg=is_old_rustc");
        }
    
        let target = env::var("TARGET").unwrap();
    
        if target.contains("ohos") {
            println!("cargo:rustc-cfg=is_ohos");
        }
        if target.contains("darwin") {
            println!("cargo:rustc-cfg=is_mac");
        }
    
        let feature_a = env::var_os("CARGO_FEATURE_MY_FEATURE_A").is_some();
        if feature_a {
            println!("cargo:rustc-cfg=has_feature_a");
        }
        let feature_b = env::var_os("CARGO_FEATURE_MY_FEATURE_B").is_some();
        if feature_b {
            println!("cargo:rustc-cfg=has_feature_b");
        }
    
        // Some tests as to whether we're properly emulating various cargo features.
        assert!(Path::new("build.rs").exists());
        assert!(Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("build.rs").exists());
        assert!(Path::new(&env::var_os("OUT_DIR").unwrap()).exists());
    
        // Confirm the following env var is set
        env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
    
        generate_some_code().unwrap();
    }
    
    fn generate_some_code() - > std::io::Result< () > {
        let test_output_dir = Path::new(&env::var_os("OUT_DIR").unwrap()).join("generated");
        let _ = std::fs::create_dir_all(&test_output_dir);
        // Test that environment variables from .gn files are passed to build scripts
        let preferred_number = env::var("ENV_VAR_FOR_BUILD_SCRIPT").unwrap();
        let mut file = std::fs::File::create(test_output_dir.join("generated.rs"))?;
        write!(file, "fn run_some_generated_code() - > u32 {{ {} }}", preferred_number)?;
        Ok(())
    }
    
    fn rustc_minor_version() - > Option< u32 > {
        let rustc_bin = match env::var_os("RUSTC") {
            Some(rustc_bin) = > rustc_bin,
            None = > return None,
        };
    
        let output = match Command::new(rustc_bin).arg("--version").output() {
            Ok(output) = > output,
            Err(_) = > return None,
        };
    
        let rustc_version = match str::from_utf8(&output.stdout) {
            Ok(rustc_version) = > rustc_version,
            Err(_) = > return None,
        };
    
        let mut pieces = rustc_version.split('.');
        if pieces.next() != Some("rustc 1") {
            return None;
        }
    
        let next_var = match pieces.next() {
            Some(next_var) = > next_var,
            None = > return None,
        };
    
        u32::from_str(next_var).ok()
    }
    
  4. 配置gn脚本build/rust/tests/test_rlib_cargo_crate/BUILD.gn,如下所示:
    import("//build/templates/rust/ohos_cargo_crate.gni")
    
    ohos_cargo_crate("target") {
      crate_name = "test_rlib_crate"
      crate_root = "crate/src/lib.rs"
      sources = [ "crate/src/lib.rs" ]
    
      #To generate the build_script binary
      build_root = "crate/build.rs"
      build_sources = [ "crate/build.rs" ]
      build_script_outputs = [ "generated/generated.rs" ]
    
      features = [
        "my-feature_a",
        "my-feature_b",
        "std",
      ]
      rustflags = [
        "--cfg",
        "test_a_and_b",
      ]
      rustenv = [ "ENV_VAR_FOR_BUILD_SCRIPT=45" ]
    }
    
    # Exists to test the case that a single crate has both a library and a binary
    ohos_cargo_crate("test_rlib_crate_associated_bin") {
      crate_root = "crate/src/main.rs"
      crate_type = "bin"
      sources = [ "crate/src/main.rs" ]
    
      #To generate the build_script binary
      build_root = "crate/build.rs"
      build_sources = [ "crate/build.rs" ]
      features = [
        "my-feature_a",
        "my-feature_b",
        "std",
      ]
      rustenv = [ "ENV_VAR_FOR_BUILD_SCRIPT=45" ]
      deps = [ ":target" ]
    }
    
  5. 执行编译得到的可执行文件,运行结果如下:
    test_rlib_cargo_crate

其他源码实例

在build/rust/tests目录下有Rust各类型模块的配置实例可供参考:

用例目录测试功能
build/rust/tests/test_bin_crate用ohos_rust_executable模板在host平台编译可执行文件,在target平台上运行可执行文件。
build/rust/tests/test_static_link测试可执行文件对标准库的静态链接。
build/rust/tests/test_dylib_crate测试对动态库的编译和动态链接功能
build/rust/tests/test_rlib_crate测试对静态库的编译和静态链接功能
build/rust/tests/test_proc_macro_crate测试对Rust过程宏的编译和链接功能。提供对不同类型的宏的测试用例。
build/rust/tests/test_cdylib_crate测试将Rust代码编译成C/C++动态库。
build/rust/tests/test_staticlib_crate测试将Rust代码编译成C/C++静态库。
build/rust/tests/rust_test_ut测试Rust代码单元测试模板功能(ability)。
build/rust/tests/rust_test_st测试Rust代码系统测试模板功能(ability)。
build/rust/tests/test_bin_cargo_crate测试Rust三方可执行文件的编译和运行。三方源码中包含build.rs。
build/rust/tests/test_rlib_cargo_crate测试Rust三方静态库的编译和静态链接。三方源码中包含build.rs。
build/rust/tests/test_proc_macro_cargo_crate测试Rust三方过程宏的编译和链接。三方源码中包含build.rs。
build/rust/tests/rust_test_fuzzb测试Rust代码Fuzz测试模板功能。

参考

特性点实例

Rust源码依赖调用C/C++库

OpenHarmony上C/C++模块动态库默认用.z.so后缀,但是Rust的编译命令通过-l链接时,默认只会链接.so后缀的动态库。因此如果要依赖一个C/C++动态库编译模块,需要在该动态库的GN构建文件中添加output_extension = "so"的声明,这样编译得到的动态库将会以".so"作为后缀,而不是".z.so"。 在Rust源码中如果直接链接动态库,后缀也需要使用".so",这时使用动态库的中间名,不需要添加lib前缀。例如Rust源码中链接libhilog.so:

#[link(name = "hilog")]

externs使用

某个模块如果依赖二进制的rlib库,可以使用externs属性:

executable("foo") {
    sources = [ "main.rs" ]
    externs = [{                    # 编译时会转成`--extern bar=path/to/bar.rlib`
        crate_name = "bar"
        path = "path/to/bar.rlib"
    }]
}

Lint规则

OpenHarmony框架支持rustc lints和clippy lints两种Lint,每种Lint划为三个等级的标准:"openharmony"、"vendor"和"none",严格程度按照"openharmony" -> "vendor" -> "none"逐级递减。 配置Rust模块时可以通过rustc_lints和clippy_lints来指定使用Lint的等级。 模块中没有配置rustc_lints或者clippy_lints时会根据模块所在路径来匹配lints等级。不同路径下的Rust代码的语法规范会有不同程度地约束,因此用户在OpenHarmony配置Rust代码编译模块时还应关注模块所在路径。

rustc lints和clippy lints的各等级标志

lints类型模块属性lints等级lints等级标志lints内容
rustc_lintsrustc_lintsopenharmonyRustOhosLints"-A deprecated", "-D missing-docs", "-D warnigngs"
rustc_lintsrustc_lintsvendorRustcVendorLints"-A deprecated", "-D warnigs"
rustc_lintsrustc_lintsnoneallowAllLints"-cap-lints allow"
clippy lintsclippy lintsopenharmonyClippyOhosLints"-A clippy::type-complexity", "-A clippy::unnecessary-wraps", "-A clippy::unusual-byte-groupings", "-A clippy::upper-case-acronyms"
clippy lintsclippy lintsvendorClippyVendorLints"-A clippy::complexity", "-A Clippy::perf", "-A clippy::style"
clippy lintsclippy lintsnoneallowAllLints"--cap-lints allow"

搜狗高速浏览器截图20240326151450.png

代码路径与lints等级的对应关系

路径Lints等级
thirdpartynone
prebuiltsnone
vendorvendor
devicevendor
othersopenharmony

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 开发板
    +关注

    关注

    25

    文章

    5032

    浏览量

    97371
  • Rust
    +关注

    关注

    1

    文章

    228

    浏览量

    6598
  • 鸿蒙
    +关注

    关注

    57

    文章

    2339

    浏览量

    42803
  • OpenHarmony
    +关注

    关注

    25

    文章

    3713

    浏览量

    16251
收藏 人收藏

    评论

    相关推荐

    OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于Hi3518开发板)】

    基于Hi3518开发板,使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3518开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。
    的头像 发表于 04-22 15:46 2007次阅读
    <b class='flag-5'>OpenHarmony</b><b class='flag-5'>鸿蒙</b>南向<b class='flag-5'>开发</b>案例:【智能猫眼(基于Hi3518<b class='flag-5'>开发板</b>)】

    鸿蒙OpenHarmony开发板:【产品配置规则

    产品解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。产品解决方案的源码路径规则为:**ve
    的头像 发表于 05-09 10:32 1122次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OpenHarmony</b><b class='flag-5'>开发板</b>:【产品<b class='flag-5'>配置</b><b class='flag-5'>规则</b>】

    鸿蒙OpenHarmony开发板解析:【 模块配置规则

    编译子系统通过模块、部件和产品三层配置来实现编译和打包。模块就是编译子系统的一个目标,包括(动态库、静态库、配置文件、预编译模块等)。
    的头像 发表于 05-10 14:39 1021次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OpenHarmony</b><b class='flag-5'>开发板</b><b class='flag-5'>解析</b>:【 <b class='flag-5'>模块</b><b class='flag-5'>配置</b><b class='flag-5'>规则</b>】

    鸿蒙OpenHarmony开发板解析:【芯片解决方案】

    芯片解决方案是指基于某款开发板的完整解决方案,包含驱动、设备侧接口适配、开发板sdk等。
    的头像 发表于 05-10 15:42 1226次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OpenHarmony</b><b class='flag-5'>开发板</b><b class='flag-5'>解析</b>:【芯片解决方案】

    鸿蒙OpenHarmony南向/北向快速开发教程-迅为RK3568开发板

    大家期待已久的迅为RK3568开发板终于迎来了鸿蒙4.1系统的强势支持!想知道如何实现快速开发学习吗?跟着我们一起来探索吧! 迅为RK3568开发板: 想象一下,你手中的RK3568
    发表于 07-23 10:44

    TI DM388评估模块开发板开发指导手册

    TI DM388评估模块开发板开发指导手册
    发表于 11-25 18:06 15次下载

    openharmony开发openharmony开发板

    现在市面上支持OpenHarmony开发板已经非常多了,OpenHarmony不仅仅只能在海思系列芯片上运行,比较常见的有HiSpark、小熊派系列。这些开发板都是基于海思的Hi38
    的头像 发表于 06-24 09:03 3668次阅读

    [鸿蒙]OpenHarmony4.0的Rust开发

    背景 Rust 是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust 官方也使用 Cargo 工具来专门为 Rust 代码创建工程和构建编译
    的头像 发表于 02-26 17:28 872次阅读
    [<b class='flag-5'>鸿蒙</b>]<b class='flag-5'>OpenHarmony</b>4.0的<b class='flag-5'>Rust</b><b class='flag-5'>开发</b>

    OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于3516开发板)】

    基于Hi3516开发板,使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3516开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。
    的头像 发表于 04-19 22:01 598次阅读
    <b class='flag-5'>OpenHarmony</b><b class='flag-5'>鸿蒙</b>南向<b class='flag-5'>开发</b>案例:【智能猫眼(基于3516<b class='flag-5'>开发板</b>)】

    鸿蒙OpenHarmony开发板解析:【系统能力配置规则

    SysCap(SystemCapability,系统能力)是部件向开发者提供的接口的集合。
    的头像 发表于 05-11 10:10 529次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OpenHarmony</b><b class='flag-5'>开发板</b><b class='flag-5'>解析</b>:【系统能力<b class='flag-5'>配置</b><b class='flag-5'>规则</b>】

    瑞芯微RK3566鸿蒙开发板OpenHarmony标准系统应用兼容性测试指导

    本文OpenHarmony标准系统应用兼容性测试指导,适用鸿蒙系统软件开发测试的新手入门学习课程,设备为触觉智能的瑞芯微RK3566开发板
    的头像 发表于 09-10 11:56 371次阅读
    瑞芯微RK3566<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发板</b><b class='flag-5'>OpenHarmony</b>标准系统应用兼容性测试<b class='flag-5'>指导</b>

    触觉智能Purple Pi OH鸿蒙开发板成功适配OpenHarmony5.0 Release,开启新征程

    触觉智能Purple Pi OH鸿蒙开发板,成功适配OpenHarmony5.0 Release版本!为大家带来OpenHarmony5.0特性讲解!关注触觉智能,为大家带来更多
    的头像 发表于 10-25 10:51 380次阅读
    触觉智能Purple Pi OH<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发板</b>成功适配<b class='flag-5'>OpenHarmony</b>5.0 Release,开启新征程

    如何在开源鸿蒙OpenHarmony开启SELinux模式?RK3566鸿蒙开发板演示

    本文介绍开源鸿蒙OpenHarmony系统下,开启/关闭SELinux权限的方法,触觉智能Purple Pi OH鸿蒙开发板演示,已适配全新Open
    的头像 发表于 11-18 19:03 305次阅读
    如何在开源<b class='flag-5'>鸿蒙</b><b class='flag-5'>OpenHarmony</b>开启SELinux模式?RK3566<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发板</b>演示

    OpenHarmony属性信息怎么修改?触觉智能RK3566鸿蒙开发板来演示

    本文介绍开源鸿蒙OpenHarmony系统下,修改产品属性信息的方法,触觉智能Purple Pi OH鸿蒙开发板演示,已适配全新OpenHarmon
    的头像 发表于 11-27 09:31 144次阅读
    <b class='flag-5'>OpenHarmony</b>属性信息怎么修改?触觉智能RK3566<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发板</b>来演示

    OpenHarmony默认30秒熄屏太麻烦?触觉智能鸿蒙开发板教你轻松取消

    OpenHarmony系统开机后 30 秒会自动息屏,教大家两招轻松取消自动息屏,触觉智能Purple Pi OH鸿蒙开发板演示,已适配全新OpenHarmony5.0 Release
    的头像 发表于 12-09 11:45 194次阅读
    <b class='flag-5'>OpenHarmony</b>默认30秒熄屏太麻烦?触觉智能<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发板</b>教你轻松取消