nto-qnx

Tier: 3

BlackBerry® QNX® Neutrino (nto) Real-time operating system. The support has been implemented jointly by Elektrobit Automotive GmbH and BlackBerry.

Target maintainers

  • Florian Bartels, Florian.Bartels@elektrobit.com, https://github.com/flba-eb
  • Tristan Roach, TRoach@blackberry.com, https://github.com/gh-tr

Requirements

Currently, only cross-compilation for QNX Neutrino on AArch64 and x86_64 are supported (little endian). Adding other architectures that are supported by QNX Neutrino is possible.

The standard library does not yet support QNX Neutrino. Therefore, only no_std code can be compiled.

core and alloc (with default allocator) are supported.

Applications must link against libc.so (see example). This is required because applications always link against the crt library and crt depends on libc.so.

The correct version of qcc must be available by setting the $PATH variable (e.g. by sourcing qnxsdp-env.sh of the QNX Neutrino toolchain).

Small example application

#![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() {}

The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.1.

There are no further known requirements.

Conditional compilation

For conditional compilation, following QNX Neutrino specific attributes are defined:

  • target_os = "nto"
  • target_env = "nto71" (for QNX Neutrino 7.1)

Building the target

  1. Create a config.toml

Example content:

profile = "compiler"
changelog-seen = 2
  1. Compile the Rust toolchain for an x86_64-unknown-linux-gnu host (for both aarch64 and x86_64 targets)

Run the following:

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" \
        ./x.py build --target aarch64-unknown-nto-qnx710 --target x86_64-pc-nto-qnx710 --target x86_64-unknown-linux-gnu rustc library/core library/alloc/

Building Rust programs

Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you must either build Rust with the target enabled (see "Building the target" above), or build your own copy of core by using build-std or similar.

Testing

Compiled executables can directly be run on QNX Neutrino.

Cross-compilation toolchains and C code

Compiling C code requires the same environment variables to be set as compiling the Rust toolchain (see above), to ensure qcc is used with proper arguments. To ensure compatibility, do not specify any further arguments that for example change calling conventions or memory layout.