nto-qnx

层级:3

QNX® Neutrino (nto) 实时操作系统。该支持由 Elektrobit Automotive GmbHBlackberry QNX 共同实施。

目标维护者

要求

目前,支持以下 QNX Neutrino 版本和编译目标

QNX Neutrino 版本目标架构完全支持no_std 支持
7.1AArch64
7.1x86_64
7.0x86

可以添加 QNX Neutrino 支持的其他架构。

在上表中,“完全支持”表示支持使用完整标准库构建 Rust 应用程序。“no_std 支持”表示仅提供 corealloc

要为 QNX Neutrino 构建或使用 Rust 工具链,必须安装并初始化 QNX 软件开发平台 (SDP)。初始化通常通过获取 qnxsdp-env.sh 来完成(这将作为 SDP 的一部分安装,另请参见 SDP 提供的安装说明)。之后,qcc(QNX C/C++ 编译器)应该可用(在 $PATH 变量中)。例如,qcc 将用于链接可执行文件。

链接 no_std 应用程序时,它们必须链接到 libc.so(参见示例)。这是必需的,因为应用程序始终链接到 crt 库,而 crt 依赖于 libc.so。使用标准库时,这会自动完成。

小型示例应用程序

下面显示了一个小型 no_std 示例。使用标准库的应用程序也可以正常工作。

#![no_std]
#![no_main]
#![feature(lang_items)]

// We must always link against libc, even if no external functions are used
// "extern C" - Block can be empty but must be present
#[link(name = "c")]
extern "C" {
    pub fn printf(format: *const core::ffi::c_char, ...) -> core::ffi::c_int;
}

#[no_mangle]
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
    const HELLO: &'static str = "Hello World, the answer is %d\n\0";
    unsafe {
        printf(HELLO.as_ptr() as *const _, 42);
    }
    0
}

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
    loop {}
}

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

Rust 对 QNX Neutrino 的支持已在 QNX Neutrino 7.0 和 7.1 中测试。

没有其他已知要求。

条件编译

对于条件编译,定义了以下 QNX Neutrino 特定属性

  • target_os = "nto"
  • target_env = "nto71"(对于 QNX Neutrino 7.1)
  • target_env = "nto70"(对于 QNX Neutrino 7.0)

构建目标

  1. 创建 config.toml

示例内容

profile = "compiler"
change-id = 115898
  1. x86_64-unknown-linux-gnu 主机(对于 aarch64x86_64 目标)编译 Rust 工具链

编译 Rust 工具链需要与编译 C 二进制文件相同的环境变量。请参阅 QNX 开发人员手册

要为 QNX Neutrino(aarch64 和 x86_64)和 Linux(x86_64)编译

export build_env='
    CC_aarch64-unknown-nto-qnx710=qcc
    CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx
    CXX_aarch64-unknown-nto-qnx710=qcc
    AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar
    CC_x86_64-pc-nto-qnx710=qcc
    CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx
    CXX_x86_64-pc-nto-qnx710=qcc
    AR_x86_64_pc_nto_qnx710=ntox86_64-ar'

env $build_env \
    ./x.py build \
        --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \
        rustc library/core library/alloc library/std

运行 Rust 测试套件

Rust 编译器和标准库的测试套件可以像其他 Rust 目标一样执行。测试环境应与编译器编译期间使用的环境匹配(参考上面的 build_envqcc/PATH),并添加 TEST_DEVICE_ADDR 环境变量。TEST_DEVICE_ADDR 变量控制远程运行器,应指向目标,尽管以下示例中显示的是 localhost。请注意,一些测试正在失败,这就是为什么它们目前被目标维护者排除的原因,这可以在以下示例中看到。

要在 x86_64 QNX Neutrino 目标上运行所有测试

export TEST_DEVICE_ADDR="localhost:12345" # must address the test target, can be a SSH tunnel
export build_env='
    CC_aarch64-unknown-nto-qnx710=qcc
    CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx
    CXX_aarch64-unknown-nto-qnx710=qcc
    AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar
    CC_x86_64-pc-nto-qnx710=qcc
    CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx
    CXX_x86_64-pc-nto-qnx710=qcc
    AR_x86_64_pc_nto_qnx710=ntox86_64-ar'

# Disable tests that only work on the host or don't make sense for this target.
# See also:
# - src/ci/docker/host-x86_64/i686-gnu/Dockerfile
# - https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Running.20tests.20on.20remote.20target
# - .github/workflows/ci.yml
export exclude_tests='
    --exclude src/bootstrap
    --exclude src/tools/error_index_generator
    --exclude src/tools/linkchecker
    --exclude tests/ui-fulldeps
    --exclude rustc
    --exclude rustdoc
    --exclude tests/run-make-fulldeps'

env $build_env \
    ./x.py test \
        $exclude_tests \
        --stage 1 \
        --target x86_64-pc-nto-qnx710

构建 Rust 程序

Rust 尚未为此目标提供预编译的工件。要为此目标编译,您必须启用目标构建 Rust(参见上面的“构建目标”),或者通过使用 build-std 或类似方法构建自己的 core 副本。

测试

编译后的可执行文件可以直接在 QNX Neutrino 上运行。

Rust std 库测试套件

目标需要足够的资源来执行所有测试。以下命令假设使用 QEMU 映像。

  • 确保 remote-test-server 使用的临时目录有足够的可用空间和 inode。已知 5GB 的可用空间和 40000 个 inode 足够(测试将创建超过 32k 个文件)。要在空目录中创建 QEMU 映像,请在目录中运行以下命令

    mkqnximage --type=qemu --ssh-ident=$HOME/.ssh/id_ed25519.pub --data-size=5000 --data-inodes=40000
    

    /data 应该有足够的可用资源。在运行 remote-test-server 时,相应地设置 TMPDIR 环境变量,例如

    TMPDIR=/data/tmp/rust remote-test-server --bind 0.0.0.0:12345
    
  • 确保 TCP 堆栈可以处理足够的并行连接(默认值为 200,应为 300 或更高)。在创建映像(参见上文)后,编辑文件 output/build/startup.sh

    1. 搜索 io-pkt-v6-hc
    2. 添加参数 -ptcpip threads_max=300,例如
      io-pkt-v6-hc -U 33:33 -d e1000 -ptcpip threads_max=300
      
    3. 使用与创建映像相同的参数再次运行 mkqnximage 来更新映像。
  • 运行和停止虚拟机

    要启动虚拟机,请在 VM 的目录中运行

    mkqnximage --run=-h
    

    要停止虚拟机,请在 VM 的目录中运行

    mkqnximage --stop
    
  • 确保本地网络

    确保“localhost”解析为 127.0.0.1。如果您无法 ping localhost,则某些测试可能会失败。确保将其附加到 /etc/hosts(如果第一个 ping 命令失败)。命令必须在虚拟机中执行!

    $ ping localhost
    ping: Cannot resolve "localhost" (Host name lookup failure)
    
    $ echo "127.0.0.1 localhost" >> /etc/hosts
    
    $ ping localhost
    PING localhost (127.0.0.1): 56 data bytes
    64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=1 ms
    

交叉编译工具链和 C 代码

编译 C 代码需要设置与编译 Rust 工具链相同的环境变量(参见上文),以确保 qcc 使用正确的参数。为了确保兼容性,不要指定任何其他参数,例如更改调用约定或内存布局。