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

审核编辑 黄宇

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

    关注

    25

    文章

    4542

    浏览量

    94738
  • Rust
    +关注

    关注

    1

    文章

    225

    浏览量

    6415
  • 鸿蒙
    +关注

    关注

    55

    文章

    1866

    浏览量

    42181
  • OpenHarmony
    +关注

    关注

    24

    文章

    3442

    浏览量

    15250
收藏 人收藏

    评论

    相关推荐

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

    产品解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。产品解决方案的源码路径规则为:**ve
    的头像 发表于 05-09 10:32 597次阅读
    <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 405次阅读
    <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>】

    盘点那些硬件+项目学习套件:Hi3861鸿蒙开发板及入门常见问题解答

    的一款用于鸿蒙设备开发鸿蒙物联网开发学习的开发板。主控为华为海思Hi3861LV100芯片,内置WiFi功能,支持
    发表于 02-01 16:55

    鸿蒙开发板试用】HiSpark Wi-Fi IoT 鸿蒙开发板 试用活动名单公布

    ``开发板来了~抱歉让大家久等了~ 经过10天的申请,截止今天一共有399位开发者提交了HiSpark Wi-Fi IoT 鸿蒙开发板试用申请。试用链接:https
    发表于 09-21 19:57

    基于OpenHarmony应用开发的签名配置

    开发OpenHarmony应用的第一步就是配置环境,如果你需要使用开发板(真机)进行调试,那就免不了配置签名信息,本文详细介绍了基于
    发表于 03-11 15:32

    鸿蒙openharmony刷到RK3566开发板上的步骤

    开发板可以控制更多的硬件,通过软硬结合得方式更好得体验鸿蒙。本文介绍的是如何把鸿蒙openharmony刷到瑞芯微RK3566开发板上。网上
    发表于 03-15 14:36

    RK3568开发板鸿蒙OpenHarmony系统固件烧写步骤

    ”)的压缩包到 Windows 的任意路径,然后解压压缩包会得到 RKDevTool_release_v2.84 文件夹  2 拷贝鸿蒙镜像到烧写器中,鸿蒙镜像网盘下载地址为“iTOP-3568 开发板
    发表于 07-15 16:15

    OpenHarmony 致远开发板开发指南

    、在线教育等诸多行业需求。“致远”开发板外观图如图1所示:图1:致远开发板外观图致远开发板开发指南本文档用来指导
    发表于 07-21 11:03

    【重磅来袭】OpenHarmony生态开发板抢先体验!

    “竞”鸿蒙开发板硬件指导手册6、润和软件大禹系列HH-SCDAYU200开发套件立即申请:https://bbs.elecfans.com/try_dayu200.html
    发表于 07-28 11:16

    每日推荐 | 鸿蒙IPC开发板免费试用,OpenHarmony内核对象队列算法详解

    HiSpark IPC DIY Camera开发板免费试用啦,想要申请的小伙伴看过来啦!推荐理由:各位开发者看过来了,还没有试用过这块鸿蒙IPC开发板
    发表于 08-10 10:26

    迅为RK3568开发板鸿蒙OpenHarmony系统固件烧写步骤

    1、迅为RK3568开发板鸿蒙OpenHarmony系统固件烧写首先拷贝烧写器(烧写器在光盘资料“iTOP-3568 开发板\01_【iTOP-RK3568
    发表于 08-26 17:45

    【软通动力鸿湖万联扬帆系列“竞”开发板试用体验】鸿湖万联扬帆系列“竞”开发板试用测评报告一初识鸿蒙系统

    鸿蒙操作系统的内容,但细心观察会发现,我们拿到的鸿蒙开发板的系统叫 OpenHarmong,那么这个OpenHarMony 和HarMony 是什么关系呢?经过一番查询资料,大概了解
    发表于 09-18 23:29

    【触觉智能 Purple Pi OH 开发板体验】一、OpenHarmony鸿蒙系统)开发环境配置以及示例代码

    不同HarmonyOS 支持 previewer 预览、模拟器运行、真机运行三种方式;OpenHarmony 支持 previewer 预览、真机(目前主要使用 3516 系列开发板)运行。首先,目前
    发表于 08-31 11:03

    [鸿蒙]OpenHarmony4.0的Rust开发

    背景 Rust 是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust 官方也使用 Cargo 工具来专门为 Rust 代码创建工程和构建编译
    的头像 发表于 02-26 17:28 389次阅读
    [<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开发板:【子系统配置规则

    通过build仓下的subsystem_config.json可以查看所有子系统的配置规则
    的头像 发表于 05-08 22:07 82次阅读
    <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>】