• 为嵌入式设备编译Rust/dbus进程间通信组件


    嵌入式软件的构建

    笔者在嵌入式软件开发过程中,之所以注重软件的构建方式,是因为快速、合理的编译构建方式能够提升开发效率,缩短软件发布周期,加快软件迭代,并且促使软件架构朝着更合理的方式发展、演进。举个例子,分布式代码版本管理工具Git决定了Linux内核的开发方式,可以说没有Git这一工具,就没有稳定且功能强大的现代Linux内核;另外Linus本人也声称自己是一个工具迷Because hey, I'm a big believer in tools。对于嵌入式软件的开发而言,优秀的编译构建方法,也是一种常被忽略的重要工具。

    对于Rust工程而言,其包含了一个完整的包管理工具,编译构建的可发挥空间没有C/C++工程那么大,但Rust工程常常是一个庞大工程的一部分,了解、解决一些常见的编译构建问题,也非常重要。近些年流行起来的“微服务架构”的核心思想本质上是一种老生重谈,简言之是通过一些进程内同步、进程间通信的方式将各个功能分为单个微小的服务。笔者一直在嵌入式软件开发中寻找更为合适的进程间组件,本文记录了笔者为嵌入式ARM设备交叉编译Rust/dbus库过程中解决的一些问题(虽然dbus的数据传递效率不适合性能稍低的嵌入式设备)。

    交叉编译Rust/dbus的错误

    开源社区提供了dbusRust语言的编程接口,可在此处访问。为了加快开发进度,笔者使用openwrt编译了dbus的官方库;之后使用以下环境来编译Rust/dbus

    #!/bin/sh
    
    export TARGET_CC=arm-openwrt-linux-gnueabi-gcc
    OPENWRT_DIR='/home/yejq/program/openwrt'
    
    which -a ${TARGET_CC} >/dev/null 2>/dev/null
    if [ $? -ne 0 ] ; then
    	export STAGING_DIR="${OPENWRT_DIR}/staging_dir/target-arm_cortex-a7+neon-vfpv4_glibc_eabi"
    	export PATH="${OPENWRT_DIR}/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-11.2.0_glibc_eabi/bin:${PATH}"
    	export TARGET_CFLAGS='-march=armv7-a -Os -fPIC -D_GNU_SOURCE -ggdb'
    	export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=${TARGET_CC}
    fi
    unset OPENWRT_DIR
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    接下来使用以下命令编译dbus-0.9.6

    cargo build --release --target armv7-unknown-linux-gnueabihf
    cargo build --release --examples --target armv7-unknown-linux-gnueabihf
    
    • 1
    • 2

    结果遇到以下编译失败问题:

    Caused by:
      process didn't exit successfully: `/home/yejq/dbus-0.9.6/target/release/build/libdbus-sys-75db788f41890c8a/build-script-build` (exit status: 101)
      --- stdout
      cargo:rerun-if-env-changed=DBUS_1_NO_PKG_CONFIG
      cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_armv7-unknown-linux-gnueabihf
      cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_armv7_unknown_linux_gnueabihf
      cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
      cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
      cargo:rerun-if-env-changed=PKG_CONFIG_armv7-unknown-linux-gnueabihf
      cargo:rerun-if-env-changed=PKG_CONFIG_armv7_unknown_linux_gnueabihf
      cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
      cargo:rerun-if-env-changed=PKG_CONFIG
      cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_armv7-unknown-linux-gnueabihf
      cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_armv7_unknown_linux_gnueabihf
      cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
      cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
    
      --- stderr
      pkg_config failed: pkg-config has not been configured to support cross-compilation.
    
      Install a sysroot for the target platform and configure it via
      PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a
      cross-compiling wrapper for pkg-config and set it via
      PKG_CONFIG environment variable.
      One possible solution is to check whether packages
      'libdbus-1-dev' and 'pkg-config' are installed:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    可见,dbus-0.9.6依赖的libdbus-sys库编译出错了,原因是不能通过pkg-config找不到libdbus-1库;上面我们已经提到,该库已经由openwrt编译,但却找不到,如何解决这个问题呢(尽管openwrt为目柡设备的交叉编译生成了可用的pkg-config,但笔者希望不对openwrt SDK产生过多的依赖)?之后,笔者尝试为宿主机编译是成功的,因为我们为主机安装了libdbus-1-dev开发库。经分析可知,为主机编译dbus-0.9.6会生成一个libdbus-sysbuild.rs编译生成的应用,执行之,可以获得以下输出:

    ~/dbus-0.9.6$ ./target/release/build/libdbus-sys-75db788f41890c8a/build-script-build
    cargo:rerun-if-env-changed=DBUS_1_NO_PKG_CONFIG
    cargo:rerun-if-env-changed=PKG_CONFIG
    cargo:rerun-if-env-changed=DBUS_1_STATIC
    cargo:rerun-if-env-changed=DBUS_1_DYNAMIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
    cargo:rerun-if-env-changed=PKG_CONFIG_PATH
    cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
    cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
    cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
    cargo:rerun-if-env-changed=SYSROOT
    cargo:rerun-if-env-changed=DBUS_1_STATIC
    cargo:rerun-if-env-changed=DBUS_1_DYNAMIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
    cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu
    cargo:rustc-link-lib=dbus-1
    cargo:rerun-if-env-changed=PKG_CONFIG
    cargo:rerun-if-env-changed=DBUS_1_STATIC
    cargo:rerun-if-env-changed=DBUS_1_DYNAMIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
    cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
    cargo:rerun-if-env-changed=PKG_CONFIG_PATH
    cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
    cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    其中重要的一个编译选项是:cargo:rustc-link-lib=dbus-1,它指定了libdbus-sys依赖dbus的C/C++库文件。

    解决Rust/dbus的编译的错误

    libdbus-sys的官方文档中,给出一个交叉编译的方法;但笔者另辟蹊径,找到了另一种方法。首先,将libdbus-sys剥离出来(版本号为libdbus-sys-0.2.2),使用Git工具进行版本控制,修改该工程下的build.rs编译脚本后在本地提交:

    diff --git a/build.rs b/build.rs
    index 5e2d1cd..303fa03 100644
    --- a/build.rs
    +++ b/build.rs
    @@ -1,18 +1,3 @@
    -extern crate pkg_config;
    -
     fn main() {
    -    // See https://github.com/joshtriplett/metadeps/issues/9 for why we don't use
    -    // metadeps here, but instead keep this manually in sync with Cargo.toml.
    -    if let Err(e) = pkg_config::Config::new().atleast_version("1.6").probe("dbus-1") {
    -        eprintln!("pkg_config failed: {}", e);
    -        eprintln!(
    -            "One possible solution is to check whether packages\n\
    -            'libdbus-1-dev' and 'pkg-config' are installed:\n\
    -            On Ubuntu:\n\
    -            sudo apt install libdbus-1-dev pkg-config\n\
    -            On Fedora:\n\
    -            sudo dnf install dbus-devel pkgconf-pkg-config\n"
    -        );
    -        panic!();
    -    }
    +    println!("cargo:rustc-link-lib=dbus-1");
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    build.rs脚本中,仅输出了libdbus-sys编译可执行需要链接的库dbus-1,如果必要,也可以再加上该库所在的路径,例如:cargo:rustc-link-search=/path/to/libdbus-1.so。随后,笔者对dbus-0.9.6作以下修改:

    diff --git a/Cargo.toml b/Cargo.toml
    index 5a32ddb..6670586 100644
    --- a/Cargo.toml
    +++ b/Cargo.toml
    @@ -48,6 +48,9 @@ default-features = false
     [dependencies.libc]
     version = "0.2.66"
     
    +[patch.crates-io]
    +libdbus-sys = { git = "file:///home/yejq/libdbus-sys-0.2.2/.git" }
    +
     [dependencies.libdbus-sys]
     version = "0.2.2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里笔者使用patch.crates-io替换了libdbus-sys的默认源仓库;因笔者个人环境中没有可用的Git代码托管服务,这里使用了文件系统的路径作为代码的URLpatch.crates-io相关的详细说明请参考官方文档。至此,Rust/dbus库就能够编译成功了:

    ~/dbus-0.9.6/target/armv7-unknown-linux-gnueabihf/release$ ls -l *.d examples/client examples/match_signal
    -rwxrwxr-x 2 yejq yejq 3656892 Nov 26 17:00 examples/client
    -rwxrwxr-x 2 yejq yejq 3738332 Nov 26 17:00 examples/match_signal
    -rw-rw-r-- 1 yejq yejq    1782 Nov 26 16:59 libdbus.d
    ~/dbus-0.9.6/target/armv7-unknown-linux-gnueabihf/release$ file examples/client examples/match_signal
    examples/client:       ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 5.4.0, with debug_info, not stripped
    examples/match_signal: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 5.4.0, with debug_info, not stripped
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    必须强调的是,dbus-0.9.6自身是一个Rust的模块(crate),如要基于此开发其他应用,也需要将dbus-0.9.6(在本地)提交,然后在其他Rust工程的Cargo.toml中加入以下代码:

    [patch.crates-io]
    libdbus-sys = { git = "file:///home/yejq/libdbus-sys-0.2.2/.git" }
    dbus = { git = "file:///home/yejq/dbus-0.9.6/.git" }
    
    • 1
    • 2
    • 3

    在嵌入式ARM设备上演示DBus应用

    笔者在运行openwrt的嵌入式ARM设备上运行dbus-0.9.6/examples/monitor.rs编译生成的monitor应用,会出现以下异常:

    root@OpenWrt:/tmp# ./monitor 
    thread 'main' panicked at 'D-Bus connection failed: D-Bus error: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead (org.freedesktop.DBus.Error.NotSupported)', examples/monitor.rs:11:42
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    • 1
    • 2
    • 3

    原因是未设定dbus相关的环境变量导致的,解决方法是将dbus-launch命令行输出的结果导入shell的环境变量,即可正常运行:

    root@OpenWrt:/tmp# dbus-launch
    DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Zh9Y2UorMi,guid=99371ddb5dee201edfa038fa6381d7f5
    DBUS_SESSION_BUS_PID=4250
    root@OpenWrt:/tmp# export $(dbus-launch)
    root@OpenWrt:/tmp# ./monitor 
    Got message: Message { Type: Signal, Path: "/org/freedesktop/DBus", Interface: "org.freedesktop.DBus", Member: "NameAcquired", Sender: "org.freedesktop.DBus", Destination: ":1.0", Serial: 2, Args: [":1.0"] }
    Got message: Message { Type: Signal, Path: "/org/freedesktop/DBus", Interface: "org.freedesktop.DBus", Member: "NameLost", Sender: "org.freedesktop.DBus", Destination: ":1.0", Serial: 4, Args: [":1.0"] }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因该设备未运行其他使用dbus进程间通信的服务(除dbus-daemon守护进程外),monitor监听到的消息只有两条。

  • 相关阅读:
    linux环境下编译,安卓平台使用的luajit库
    centos7.x本地挂载阿里云oss
    使用Spring Security和Thymeleaf进行CSRF保护
    【luogu CF1534F2】Falling Sand (Hard Version)(性质)(dfs)(线段树 / 单调队列 / 贪心)
    计算机毕业设计:基于python机器学习的全国气象数据采集预测可视化系统 预测模型+爬虫(包含文档+源码+部署教程)
    Goosehill大G桨板|潮流水上运动,这个夏天带你一起去
    android update_engine分析二
    Kakao账号如何注册使用?如何Kakao多开?外贸必备全面教程
    PHP8数组的类型-PHP8知识详解
    嵌入式开发学习之STM32F407定时器中断配置(四)
  • 原文地址:https://blog.csdn.net/yeholmes/article/details/128054623