
Rust 编译器中的 QNX 目标支持QNX SDP 7.x/8.0 目标选择、工具链构建、远程测试与 RELRO 调优【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本文基于 Rust 官方仓库中的平台支持文档 nto-qnx.md系统讲解 Rust 对 QNX SDPQNX Software Development Platform7.0 / 7.1 / 8.0 的 Tier 3 目标支持如何按网络栈io-pkt / io-sock选择 target tuple、如何准备qcc编译环境、如何用x.py构建 QNX 目标工具链、如何运行远程测试套件以及如何通过relro_leveloff解决部分 QNX 内核上的可执行文件加载失败问题。读完后你可以独立完成“从 QNX SDP 环境初始化 → 构建目标 → 编译 Rust 程序 → 在远程目标上跑测试”的完整流程。QNX 支持与 QNX SDP背景与定位Rust 对 QNX 的支持处于Tier 3级别覆盖 QNX SDP 的 7.0、7.1 和 8.0 三个版本。QNX SDP 是安装在宿主机上的开发环境包含宿主侧的 C 工具链、IDE 以及面向不同目标平台的板级支持包board support packages。用 QNX SDP 可以构建一个自定义运行时环境再部署到嵌入式设备上该运行时包含一个微内核microkernel、所选的服务组件以及可能用 Rust 编写的一个或多个应用。在 QNX SDP 7.x 中运行时基于 QNX Neutrino RTOS 7.x在 QNX SDP 8.0 中运行时基于 QNX OS 8.0。这次改名反映了 RTOS 的架构变化但两者都采用微内核设计——这也是 target tuple 中ntoNeutrino OS 的缩写与qnx两套命名并存的根源。从源码结构看QNX 各目标共享一套基础选项集中定义在 qnx_sdp.rs 中关键配置包括linker: Some(qcc.into())链接器固定为 QNX 的 C/C 编译器qcc这与文档中“必须初始化 QNX SDP 环境使qcc位于 PATH”的要求相互印证families: cvs![unix]、has_rpath: true、dynamic_linking: true、executables: trueQNX 目标被归入 unix 家族支持动态链接与可执行文件default_uwtable: true默认生成 unwind table使 backtrace 在任何 panic 策略下都能工作relro_level: RelroLevel::Full默认开启完整 RELRO——这正是后文“禁用 RELRO”一节要讨论的默认值crt_static_respected: true尊重-C target-featurecrt-static等静态链接选项position_independent_executables: true与static_position_independent_executables: true可执行文件默认位置无关。受支持的目标与网络栈选择文档给出的完整支持矩阵如下QNX 版本对应 SDP 版本Target TupleQNX 版本目标架构完整 std 支持no_std支持aarch64-unknown-qnxQNX SDP 8.0AArch64?✓x86_64-pc-qnxQNX SDP 8.0x86_64?✓aarch64-unknown-nto-qnx710_iosockQNX SDP 7.1io-sockAArch64?✓x86_64-pc-nto-qnx710_iosockQNX SDP 7.1io-sockx86_64?✓aarch64-unknown-nto-qnx710QNX SDP 7.1io-pktAArch64✓✓x86_64-pc-nto-qnx710QNX SDP 7.1io-pktx86_64✓✓aarch64-unknown-nto-qnx700QNX SDP 7.0AArch64?✓i686-pc-nto-qnx700QNX SDP 7.0x86-✓矩阵中的两个脚注决定了“该选哪个 target”的核心依据——网络栈的代际差异QNX SDP 7.0 仅提供io-pkt网络栈QNX SDP 7.1 默认使用io-pkt同时附带可选的io-sock网络栈QNX SDP 8.0 仅提供io-sock网络栈。表中 “full support” 指使用完整标准库构建 Rust 应用的能力?表示支持正在进行-表示不提供i686-pc-nto-qnx700即只有no_std支持。“no_stdsupport” 指构建#![no_std]应用、仅依赖core与alloc的能力所有 QNX 目标均支持。每个 target tuple 在源码中都有独立的 spec 文件例如 aarch64_unknown_nto_qnx710.rs、aarch64_unknown_nto_qnx710_iosock.rs、x86_64_pc_nto_qnx710.rs、i686_pc_nto_qnx700.rs、aarch64_unknown_qnx.rs 等均位于compiler/rustc_target/src/spec/targets/目录下。以 aarch64_unknown_nto_qnx710.rs 为例其描述为 “ARM64 QNX SDP 7.1 with io-pkt network stack”并通过Env::Nto71指定条件编译环境而 aarch64_unknown_nto_qnx710_iosock.rs 则使用ApiVariant::IoSock链接参数与Env::Nto71IoSock。值得注意的是 io-sock 目标的链接差异在 qnx_sdp.rs 中get_iosock_param函数会读取环境变量QNX_TARGET由qnxsdp-env.sh设置拼接出-L{QNX_TARGET}/{arch}/io-sock/lib这样的库搜索路径使链接器优先选择 io-sock 版本的库。源码注释明确指出该路径依赖宿主机环境、无法硬编码必须在编译器运行时动态确定若QNX_TARGET未设置链接参数会退化为提示字符串QNX_TARGET_not_set_please_source_qnxsdp-env.sh等价于把“忘记 source 环境”直接暴露为链接错误。各架构的qcc链接参数也在 qnx_sdp.rs 的pre_link_args中按架构区分AArch64 使用-Vgcc_ntoaarch64le_cxxx86_64 使用-Vgcc_ntox86_64_cxx。环境准备初始化 QNX SDP让 qcc 可用文档对构建或使用 Rust 工具链的前置要求非常明确安装并初始化对应版本的 QNX SDP。初始化通常通过 sourceqnxsdp-env.sh完成该脚本随 SDP 一起安装具体位置见 SDP 自带安装说明。初始化后qccQNX 的 C/C 编译器必须位于系统 PATH 中因为 Rust 编译过程中例如链接可执行文件时会调用它。这与前面源码中linker: Some(qcc.into())的设定完全对应rustc 把qcc当作 QNX 目标的链接器因此任何“编译 Rust → 链接可执行文件”的动作都隐式依赖 QNX SDP 的环境变量。另一条关键约束涉及no_std应用的链接链接no_std应用时必须链接libc.so。原因是应用始终链接crt库而crt依赖libc.so。使用标准库时这一步是自动完成的。也就是说#![no_std]只意味着不使用std并不免除对 C 运行时的链接依赖使用标准库时 rustc 会自动处理手写no_std构建如用build-std或自定义链接命令时则需要显式链接libc.so。条件编译target_os 与 target_env 的取值QNX 目标的条件编译属性定义如下与源码中Os/Env枚举一一对应target_os ntoQNX SDP 7.x 系列为向后兼容保留target_env nto70QNX SDP 7.0target_env nto71QNX SDP 7.1经典网络栈 io-pkttarget_env nto71_iosockQNX SDP 7.1新网络栈 io-socktarget_os qnxQNX SDP 8.0 及以上源码侧证据spec/mod.rs 中Env枚举定义为Nto70 nto70、Nto71 nto71、Nto71IoSock nto71_iosock7.x 各目标 spec如 aarch64_unknown_nto_qnx710.rs的注释说明“对 QNX SDP 7.x为向后兼容保留target_os nto用target_env区分版本”而 8.0 的目标如 aarch64_unknown_qnx.rs则设置os Os::Qnx、不设target_env。在第三方 crate 中据此写条件编译时的典型形式#[cfg(all(target_os nto, target_env nto71_iosock))] fn qnx71_iosock_only() {} #[cfg(target_os qnx)] fn qnx8_or_later() {}构建支持 QNX 目标的 Rust 工具链QNX 目标没有预编译的发布工件要使用该 target 必须自行构建工具链后文会给出基于build-std的替代路线。文档给出的构建步骤如下。第 1 步创建bootstrap.toml示例内容profile compiler change-id 999999 [build] host [x86_64-unknown-linux-gnu] target [x86_64-unknown-linux-gnu, aarch64-unknown-nto-qnx710]这里将aarch64-unknown-nto-qnx710加入build.target列表使构建系统为它编译core、alloc、std。仓库根目录提供了 bootstrap.example.toml 可作格式参考。第 2 步在加载了 QNX SDP 环境的前提下编译 Rust 工具链。由于需要正确的 QNX SDP 环境变量且qcc必须在 PATH 中通常在 Linux 宿主上执行source ~/qnx710/qnxsdp-env.sh ./x.py build rustc library/core library/alloc library/std为 QNX 构建 Rust 程序文档明确Rust 官方不发布该目标的预编译工件。要为 QNX 编译只有两条路按上一节启用目标构建 Rust 工具链使用build-std或类似机制自行构建一份core。编译出的可执行文件可以直接在 QNX 上运行方式有两种将其包含在磁盘镜像disk image中或通过网络拷贝到运行中的系统上。关于混合 C 代码编译 C 代码需要与编译 Rust 工具链相同的环境变量设置同样是为了让qcc以正确的参数被调用。为保证兼容性不要额外指定任何会改变调用约定或内存布局的参数。运行 Rust 测试套件远程执行与排除项Rust 编译器与标准库的测试套件可以像其他 Rust 目标一样在 QNX 上运行。测试环境应与编译工具链时的环境一致注意前面关于qnxsdp-env.sh的说明并额外设置TEST_DEVICE_ADDR环境变量它控制 remote runner应指向一个正在运行remote-test-server可执行文件的目标。仓库中该工具位于 src/tools/remote-test-server配合rustc_remote协议把测试编译后发送到目标执行。文档指出部分测试目前会失败因此目标维护者将其排除完整示例如下以 x86_64 QNX Neutrino 7.1 目标为例source ~/qnx710/qnxsdp-env.sh export TEST_DEVICE_ADDR1.2.3.4:12345 # 必须指向测试目标可以是 SSH 隧道 # 禁用仅在宿主上可运行、或对目标无意义的测试 export exclude_tests --exclude src/bootstrap --exclude src/tools/error_index_generator --exclude src/tools/linkchecker --exclude tests/ui-fulldeps --exclude rustc --exclude rustdoc ./x.py test \ $exclude_tests \ --stage 1 \ --target x86_64-pc-nto-qnx710排除项的语义src/bootstrap、error_index_generator、linkchecker、ui-fulldeps属于宿主侧工具或依赖宿主环境的测试rustc、rustdoc则指 rustc/rustdoc 自身的测试套件不在远程目标上跑。标准库测试QEMU 虚拟机的准备细节标准库测试对目标资源要求较高文档给出的命令以 QEMU 镜像为前提包含四个必须逐项处理的准备事项。1. 为 remote-test-server 的临时目录预留足够空间。已知 5GB 可用空间与 40000 个 inode 足够测试会创建超过 32k 个文件。在空目录内执行mkqnximage --typeqemu --ssh-ident$HOME/.ssh/id_ed25519.pub --data-size5000 --data-inodes40000确认/data有足够资源后运行remote-test-server时相应设置TMPDIRTMPDIR/data/tmp/rust remote-test-server --bind 0.0.0.0:123452. 提高 TCP 栈的并行连接上限。默认值是 200应提升到 300 或更高。创建镜像后编辑output/build/startup.sh查找io-pkt-v6-hc追加参数-ptcpip threads_max300例如io-pkt-v6-hc -U 33:33 -d e1000 -ptcpip threads_max300用与创建镜像时相同的参数重新运行mkqnximage更新镜像。3. 启动与停止虚拟机。在 VM 所在目录内执行# 启动 mkqnximage --run-h # 停止 mkqnximage --stop4. 确保本地回环可解析。确认localhost能解析为127.0.0.1否则 ping 不通 localhost 会导致部分测试失败。若首次ping失败向/etc/hosts追加记录注意以下命令必须在虚拟机内执行$ 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_seq0 ttl255 time1 ms禁用 RELRO特定 QNX 内核下的加载问题QNX 目标默认使用完整 RELRO对应 qnx_sdp.rs 中的relro_level: RelroLevel::Full。文档说明虽然默认不推荐关闭但某些 QNX 内核配置要求通过-C relro_leveloff禁用 RELRO例如写入.cargo/config.toml[target.aarch64-unknown-nto-qnx700] rustflags [-C, relro_leveloff]诊断方法如果 QNX 内核不允许 RELRO 而未禁用它运行编译产物会报syntax error: ... unexpected之类的错误——本质是内核试图用/bin/sh去解释这个二进制文件并失败。用DL_DEBUGall环境变量运行二进制可验证出现如下输出即可确认Resolution scope for Executable-/bin/sh: Executable-/bin/sh libc.so.4-/usr/lib/ldqnx-64.so.2看到该输出后就应按上述方式禁用relro。小结围绕 nto-qnx.md 这条主线QNX 目标支持在仓库中的实现落点可归纳为共享选项与链接参数在 compiler/rustc_target/src/spec/base/qnx_sdp.rs各 target tuple 的 spec 分布在compiler/rustc_target/src/spec/targets/下target_env的字符串映射在 compiler/rustc_target/src/spec/mod.rs远程测试依赖TEST_DEVICE_ADDR与 remote-test-server 的组合。实践要点按顺序即按网络栈选对 target → sourceqnxsdp-env.sh保证qcc与QNX_TARGET可用 →bootstrap.toml加 target 后用x.py build构建工具链或走build-std→ 用x.py test --stage 1配合排除项在远程目标跑测试 → 遇到内核不兼容 RELRO 时用-C relro_leveloff兜底。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考