当前位置:   article > 正文

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

openharmony lint

 概述

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_libraryrust动态库rust dylib动态库,默认后缀.dylib.so
ohos_rust_static_libraryrust静态库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,如下所示:

    1. //! simple_printer
    2. /// struct RustLogMessage
    3. pub struct RustLogMessage {
    4. /// i32: id
    5. pub id: i32,
    6. /// String: msg
    7. pub msg: String,
    8. }
    9. /// function rust_log_rlib
    10. pub fn rust_log_rlib(msg: RustLogMessage) {
    11. println!("id:{} message:{:?}", msg.id, msg.msg)
    12. }

  2. 创建build/rust/tests/test_rlib_crate/src/main.rs,如下所示:

    1. //! rlib_crate example for Rust.
    2. extern crate simple_printer_rlib;
    3. use simple_printer_rlib::rust_log_rlib;
    4. use simple_printer_rlib::RustLogMessage;
    5. fn main() {
    6. let msg: RustLogMessage = RustLogMessage {
    7. id: 0,
    8. msg: "string in rlib crate".to_string(),
    9. };
    10. rust_log_rlib(msg);
    11. }

  3. 配置gn脚本build/rust/tests/test_rlib_crate/BUILD.gn,如下所示:

    1. import("//build/ohos.gni")
    2. ohos_rust_executable("test_rlib_crate") {
    3. sources = [ "src/main.rs" ]
    4. deps = [ ":simple_printer_rlib" ]
    5. }
    6. ohos_rust_static_library("simple_printer_rlib") {
    7. sources = [ "src/simple_printer.rs" ]
    8. crate_name = "simple_printer_rlib"
    9. crate_type = "rlib"
    10. features = [ "std" ]
    11. }

  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,如下所示:

    1. include!(concat!(env!("OUT_DIR"), "/generated/generated.rs"));
    2. pub fn say_hello_from_crate() {
    3. assert_eq!(run_some_generated_code(), 45);
    4. #[cfg(is_new_rustc)]
    5. println!("Is new rustc");
    6. #[cfg(is_old_rustc)]
    7. println!("Is old rustc");
    8. #[cfg(is_ohos)]
    9. println!("Is ohos");
    10. #[cfg(is_mac)]
    11. println!("Is darwin");
    12. #[cfg(has_feature_a)]
    13. println!("Has feature_a");
    14. #[cfg(not(has_feature_a))]
    15. panic!("Wasn't passed feature_a");
    16. #[cfg(not(has_feature_b))]
    17. #[cfg(test_a_and_b)]
    18. panic!("feature_b wasn't passed");
    19. #[cfg(has_feature_b)]
    20. #[cfg(not(test_a_and_b))]
    21. panic!("feature_b was passed");
    22. }
    23. #[cfg(test)]
    24. mod tests {
    25. /// Test features are passed through from BUILD.gn correctly. This test is the target configuration.
    26. #[test]
    27. #[cfg(test_a_and_b)]
    28. fn test_features_passed_target1() {
    29. #[cfg(not(has_feature_a))]
    30. panic!("feature a was not passed");
    31. #[cfg(not(has_feature_b))]
    32. panic!("feature b was not passed");
    33. }
    34. #[test]
    35. fn test_generated_code_works() {
    36. assert_eq!(crate::run_some_generated_code(), 45);
    37. }
    38. }

  2. 创建build/rust/tests/test_rlib_cargo_crate/crate/src/main.rs,如下所示:

    1. pub fn main() {
    2. test_rlib_crate::say_hello_from_crate();
    3. }

  3. 创建build/rust/tests/test_rlib_cargo_crate/crate/build.rs,如下所示:

    1. use std::env;
    2. use std::path::Path;
    3. use std::io::Write;
    4. use std::process::Command;
    5. use std::str::{self, FromStr};
    6. fn main() {
    7. println!("cargo:rustc-cfg=build_script_ran");
    8. let my_minor = match rustc_minor_version() {
    9. Some(my_minor) => my_minor,
    10. None => return,
    11. };
    12. if my_minor >= 34 {
    13. println!("cargo:rustc-cfg=is_new_rustc");
    14. } else {
    15. println!("cargo:rustc-cfg=is_old_rustc");
    16. }
    17. let target = env::var("TARGET").unwrap();
    18. if target.contains("ohos") {
    19. println!("cargo:rustc-cfg=is_ohos");
    20. }
    21. if target.contains("darwin") {
    22. println!("cargo:rustc-cfg=is_mac");
    23. }
    24. let feature_a = env::var_os("CARGO_FEATURE_MY_FEATURE_A").is_some();
    25. if feature_a {
    26. println!("cargo:rustc-cfg=has_feature_a");
    27. }
    28. let feature_b = env::var_os("CARGO_FEATURE_MY_FEATURE_B").is_some();
    29. if feature_b {
    30. println!("cargo:rustc-cfg=has_feature_b");
    31. }
    32. // Some tests as to whether we're properly emulating various cargo features.
    33. assert!(Path::new("build.rs").exists());
    34. assert!(Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("build.rs").exists());
    35. assert!(Path::new(&env::var_os("OUT_DIR").unwrap()).exists());
    36. // Confirm the following env var is set
    37. env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
    38. generate_some_code().unwrap();
    39. }
    40. fn generate_some_code() -> std::io::Result<()> {
    41. let test_output_dir = Path::new(&env::var_os("OUT_DIR").unwrap()).join("generated");
    42. let _ = std::fs::create_dir_all(&test_output_dir);
    43. // Test that environment variables from .gn files are passed to build scripts
    44. let preferred_number = env::var("ENV_VAR_FOR_BUILD_SCRIPT").unwrap();
    45. let mut file = std::fs::File::create(test_output_dir.join("generated.rs"))?;
    46. write!(file, "fn run_some_generated_code() -> u32 {{ {} }}", preferred_number)?;
    47. Ok(())
    48. }
    49. fn rustc_minor_version() -> Option<u32> {
    50. let rustc_bin = match env::var_os("RUSTC") {
    51. Some(rustc_bin) => rustc_bin,
    52. None => return None,
    53. };
    54. let output = match Command::new(rustc_bin).arg("--version").output() {
    55. Ok(output) => output,
    56. Err(_) => return None,
    57. };
    58. let rustc_version = match str::from_utf8(&output.stdout) {
    59. Ok(rustc_version) => rustc_version,
    60. Err(_) => return None,
    61. };
    62. let mut pieces = rustc_version.split('.');
    63. if pieces.next() != Some("rustc 1") {
    64. return None;
    65. }
    66. let next_var = match pieces.next() {
    67. Some(next_var) => next_var,
    68. None => return None,
    69. };
    70. u32::from_str(next_var).ok()
    71. }

  4. 配置gn脚本build/rust/tests/test_rlib_cargo_crate/BUILD.gn,如下所示:

    1. import("//build/templates/rust/ohos_cargo_crate.gni")
    2. ohos_cargo_crate("target") {
    3. crate_name = "test_rlib_crate"
    4. crate_root = "crate/src/lib.rs"
    5. sources = [ "crate/src/lib.rs" ]
    6. #To generate the build_script binary
    7. build_root = "crate/build.rs"
    8. build_sources = [ "crate/build.rs" ]
    9. build_script_outputs = [ "generated/generated.rs" ]
    10. features = [
    11. "my-feature_a",
    12. "my-feature_b",
    13. "std",
    14. ]
    15. rustflags = [
    16. "--cfg",
    17. "test_a_and_b",
    18. ]
    19. rustenv = [ "ENV_VAR_FOR_BUILD_SCRIPT=45" ]
    20. }
    21. # Exists to test the case that a single crate has both a library and a binary
    22. ohos_cargo_crate("test_rlib_crate_associated_bin") {
    23. crate_root = "crate/src/main.rs"
    24. crate_type = "bin"
    25. sources = [ "crate/src/main.rs" ]
    26. #To generate the build_script binary
    27. build_root = "crate/build.rs"
    28. build_sources = [ "crate/build.rs" ]
    29. features = [
    30. "my-feature_a",
    31. "my-feature_b",
    32. "std",
    33. ]
    34. rustenv = [ "ENV_VAR_FOR_BUILD_SCRIPT=45" ]
    35. deps = [ ":target" ]
    36. }

  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属性:

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

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"HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿

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

代码路径与lints等级的对应关系
路径Lints等级
thirdpartynone
prebuiltsnone
vendorvendor
devicevendor
othersopenharmony

鸿蒙开发岗位需要掌握那些核心要领?

目前还有很多小伙伴不知道要学习哪些鸿蒙技术?不知道重点掌握哪些?为了避免学习时频繁踩坑,最终浪费大量时间的。

自己学习时必须要有一份实用的鸿蒙(Harmony NEXT)资料非常有必要。 这里我推荐,根据鸿蒙开发官网梳理与华为内部人员的分享总结出的开发文档。内容包含了:【ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战】等技术知识点。

废话就不多说了,接下来好好看下这份资料。

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习鸿蒙OpenHarmony知识←前往。下面是鸿蒙开发的学习路线图。

针对鸿蒙成长路线打造的鸿蒙学习文档。鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

其中内容包含:

《鸿蒙开发基础》鸿蒙OpenHarmony知识←前往

  1. ArkTS语言
  2. 安装DevEco Studio
  3. 运用你的第一个ArkTS应用
  4. ArkUI声明式UI开发
  5. .……

《鸿蒙开发进阶》鸿蒙OpenHarmony知识←前往

  1. Stage模型入门
  2. 网络管理
  3. 数据管理
  4. 电话服务
  5. 分布式应用开发
  6. 通知与窗口管理
  7. 多媒体技术
  8. 安全技能
  9. 任务管理
  10. WebGL
  11. 国际化开发
  12. 应用测试
  13. DFX面向未来设计
  14. 鸿蒙系统移植和裁剪定制
  15. ……

《鸿蒙开发实战》鸿蒙OpenHarmony知识←前往

  1. ArkTS实践
  2. UIAbility应用
  3. 网络案例
  4. ……

最后

鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/925165
推荐阅读
相关标签
  

闽ICP备14008679号