Rust Howto (Request)

In that case you probably just need to install the (x86) rpm package like this:

sfdk engine exec sudo rpm -U <file.rpm>

New issues. Can’t build rpm for i486 host of the :

# local fork of  https://github.com/sailfishos/rust.git 
sfdk engine exec mb2 -t SailfishOS-4.1.0.24-i486 -s rust.spec build

+ PATH=/opt/cross/bin/:/home/mersdk/.mb2/wrappers/rust:/home/mersdk/.mb2/user-wrappers/rust:/usr/local/bin:/bin:/usr/bin
+ ./configure --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib --libexecdir=/usr/libexec --localstatedir=/var --sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info --disable-option-checking --libdir=/usr/lib --build=i686-unknown-linux-gnu --host=i686-unknown-linux-gnu --target=i686-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,aarch64-unknown-linux-gnu --python=python3 --local-rust-root=/home/mikael/MyStuff/src/rust/rust-1.52.1-i686-unknown-linux-gnu/usr --enable-local-rebuild --enable-llvm-link-shared --enable-ccache --enable-optimize --disable-docs --disable-compiler-docs --disable-jemalloc --disable-rpath --disable-codegen-tests --disable-verbose-tests --debuginfo-level=0 --debuginfo-level-std=2 --disable-debuginfo --disable-debuginfo-only-std --disable-debuginfo-tools --disable-debuginfo-lines --enable-extended --enable-vendor --set rust.codegen-units-std=1 --tools=cargo --llvm-root=/usr/ --enable-parallel-compiler --set target.i686-unknown-linux-gnu.cc=/usr/bin/cc --set target.i686-unknown-linux-gnu.ar=/usr/bin/ar --set target.armv7-unknown-linux-gnueabihf.cc=/opt/cross/bin/armv7hl-meego-linux-gnueabi-cc --set target.armv7-unknown-linux-gnueabihf.ar=/opt/cross/bin/armv7hl-meego-linux-gnueabi-ar --set target.aarch64-unknown-linux-gnu.cc=/opt/cross/bin/aarch64-meego-linux-gnu-cc --set target.aarch64-unknown-linux-gnu.ar=/opt/cross/bin/aarch64-meego-linux-gnu-ar --set build.verbose=2
/var/tmp/rpm-tmp.8hqBY8: line 65: ./configure: No such file or directory
error: Bad exit status from /var/tmp/rpm-tmp.8hqBY8 (%build)
    Bad exit status from /var/tmp/rpm-tmp.8hqBY8 (%build)

Can you share the source you’re attempting to build (including the spec file)? I think this would be a big help in understanding what might be happening.

Edit: Ah, sorry, I see in the comment where it’s coming from. I’ll give it a go myself.

It looks like the git-submodule branch is better set up for building with the sfdk. You’ll also need git lfs installed, and on the first run will need to run the prepare step to apply the patches. Something like this seems to work for me (it’s still running, so not fully tested), You’ll probably need to amend the steps for your set up.

# Set up git large file storage (this on Ubuntu)
sudo apt install git-lfs
git lfs install

# Clone the repo and submodules
git clone https://github.com/sailfishos/rust.git
cd rust
git checkout git-submodule
git submodule update --init
cd rust
git submodule update --init
cd ..

# Initial build with prepare step
sfdk config --session --push target SailfishOS-4.1.0.24-i486
sfdk build -p 

# Subsequent builds
sfdk config --session --push target SailfishOS-4.1.0.24-i486
sfdk build

Without more detail it’s hard to help I’m afraid. Which patch didn’t apply, and what was the error message? They apply fine for me here.

I forgot run 2nd git submodule inside the subdir. I try again…

Okey after some more testing I realized this submodule branch is not the solution since that branch is rust 1.44.

I also tried this in master branch:

sfdk build -p 
Fatal: No spec or yaml file found in './rpm/'

So, I’ve been toying a lot with Rust and build systems lately. The cleanest that I could find so far uses either my version of Rust 1.52 (if you use build scripts or target-conditional dependencies, this is needed), or the 1.52 that’s currently included with the tooling and targets of SailfishOS 4.2.0.19EA.

I’ve moulded and kneaded the spec and yaml files of a standard app such that it calls cargo build. I have worked on qmetaobject-rs (also this), such that it still works on Qt 5.6. I started a crate sailo-rs which wraps around sailfishapp. Combining all of these (and maybe also qmeta-async, if that’s your kinda kink — it certainly is mine) means you can actually build Sailfish applications in about 130 lines of Rust. As an example to that, I present you:

In order to build it, you’ll need the build instructions for Whisperfish’ SFDK branch, which should soon™ hit master. It involves only installing the custom Rust version (in fact, custom Cargo version), which Jolla will hopefully fix in the 4.3 or 4.4-series.

It integrates so well now, that you can even use QtCreator to build it. It contains a .pro file, and you only need to fiddle a bit with the build settings: you need to disable the qmake and make steps, and add sfdk build.

The run-configuration can look like this:

As of there, QtCreator will happily do many things that you’d do on a daily basis. I’ve even seen qmlive work, more or less!

6 Likes

(gonna try to answer some ill-answered or unanswered questions now)

We seem to have the same experience when building Whisperfish now: the VBox version has problems finding downloaded crates, the Docker version runs just fine.

-j 1 is also used in Whisperfish. There’s a bug in (presumably) SB2, which gets cargo stuck in a futex when running with “too high level of parallelism”. Eventually, it probably will also lock up on -j 1, but it seems to deter for now. If dropping the parallelism flag works for you, you could drop it locally. I’d still keep it in CI. I think @flypig may be able to give more context.

You’re probably running the VirtualBox SDK, which seems to behave badly w.r.t. the SB2 tooling-based cross compilation. @direc85 and me are trying to figure out, but it seems like the Docker-based SDK works better.

I use these two scripts to get Rust in a tooling and target:

build.sh (compiles the actual Rust and Cargo):

#!/bin/sh -ex
ARCHS="i486 armv7hl aarch64"

cd rust
for arch in $ARCHS; do
rpmbuild -bb rust.spec  --define "_target_cpu $arch"
done
cd ..

install.sh (Creates the stub compilers and repackages the stdlib):

#!/bin/sh -ex

ARCHS="i486 armv7hl aarch64"
TOOLING=SailfishOS-4.1
# TARGET=SailfishOS-3.4-on-4.1
TARGET=SailfishOS-4.1
VERSION=1.52.1+git1-1

sudo zypper install ~/rpmbuild/RPMS/i486/rust* ~/rpmbuild/RPMS/i486/cargo* || echo zypper error
cd cross
rpmbuild -bb rust-cross-aarch64.spec
rpmbuild -bb rust-cross-armv7hl.spec
cd ..

mkdir -p /srv/mer/toolings/$TOOLING/tmp/rust-rpms/
for f in ~/rpmbuild/RPMS/i486/rust* ~/rpmbuild/RPMS/i486/cargo*; do
    cp $f /srv/mer/toolings/$TOOLING/tmp/rust-rpms/
done

sdk-manage tooling package-install $TOOLING /tmp/rust-rpms/{rust-std-static-i686-unknown-linux-gnu-$VERSION.i486.rpm,rust-std-static-armv7-unknown-linux-gnueabihf-$VERSION.i486.rpm,rust-std-static-aarch64-unknown-linux-gnu-$VERSION.i486.rpm,rust-$VERSION.i486.rpm,cargo-$VERSION.i486.rpm}

rm -rf /srv/mer/toolings/$TOOLING/tmp/rust-rpms/*

for arch in $ARCHS; do
    sdk-manage target package-remove $TARGET-$arch rust cargo rust-std-static-i686-unknown-linux-gnu rust-std-static-aarch64-unknown-linux-gnu rust-std-static-armv7-unknown-linux-gnueabihf || echo continuing
done

for arch in $ARCHS; do
    sdk-manage target package-install $TARGET-$arch ~/rpmbuild/RPMS/$arch/*
done

These assume that you have https://github.com/sailfishos/rust and https://github.com/sailfishos/rust-cross in directories next to eachother, respectively rust and cross. I run these scripts inside the Platform SDK, not in mb2 (these packages used to build in mb2, but Jolla seems to have changed their strategy for the better here).

On SDK 4.1, you can use the repo on my home server, which hosts the patched cargo: ssu ar https://nas.rubdos.be/~rsmet/sailfish-repo/ rubdos. These do not have bumped version numbers, so you have to fiddle a bit with zypper. If someone has a good suggestion on how to get a personalised version number that will get upped by Jolla, let me know.

4 Likes

Hi @rubdos

Got some time today and made a little progress but still little lost.

I installed your prebuilt by run the ssu stuff inside the builder eg:
`
ssu ar Index of /~rsmet/sailfish-repo/ rubdos

zypper refresh
zypper install rust
sdk-manage target package-install SailfishOS-4.2.0.21-aarch64 rust
`

❯ sfdk engine exec sb2 -t SailfishOS-4.2.0.21-aarch64 cargo --version
cargo 1.52.0-dev <= seems correct?

The next step is now try build my rust app but still getting alot of error messages but probably doing it wrong way:

❯ sfdk engine exec sb2 -t SailfishOS-4.2.0.21-aarch64 cargo build --release --target=aarch64-unknown-linux-gnu

= note: aarch64-meego-linux-gnu-cc: error: unrecognized command line option ‘-m32’

Ah. I should have published those rust packages on my server with an incremented version number. SDK 4.2 packages 1.52 too, so that might get you some confusion.

Now, you don’t need to use --target in sb2. Jolla has a hack for that, because that doesn’t 100% work in sb2.
You instead need to set these:

export SB2_RUST_TARGET_TRIPLE=aarch64-unknown-linux-gnu
export SB2_RUST_EXECVP_SHIM="/usr/bin/env LD_PRELOAD=/usr/lib/libsb2/libsb2.so.1 /usr/bin/env"
export SB2_RUST_USE_REAL_EXECVP=Yes
export SB2_RUST_USE_REAL_FN=Yes
export SB2_RUST_NO_SPAWNVP=Yes

For further inspiration, I suggest you read the Whisperfish rpm-spec!

A small hint to save your fingers from some extra typing:

sfdk engine exec sb2 -t SailfishOS-4.2.0.21-aarch64 COMMAND ARGS...

is equivalent to

sfdk build-shell COMMAND ARGS...

(Provided that the above used target is the one currently selected with sfdk config.)

Oh, that’s useful, thanks! Much easier to remember too.

I toyed around with Rust development on sfos. Initially it seemed to work good, but when I use a build script I get a failed to determine package fingerprint for build script error. I tried it with the default packages for SailfishOS-4.3.0.12 and also with the packages from rubdos.

Is this a known issue? Are there workarounds?

Are you building in a git repository with a submodule? There does seem to be an issue that causes cargo to try to update the submodule, which can be worked-around by temporarily moving the .git directory during the build. It may be that you’re hitting the same issue.

You can see the workaround applied in the gecko spec file, where the git folder is moved before the build and then moved back again afterwards.

@flypig thanks, you put me on the right track. While the repo does not have submodules, I tried with a clean project and compilation started but failed with can't fint crate for ..., similar to what thigg had. Installing the docker based SDK fixed the issue for me and I’m able to use Rust in my C++ project.

I’m glad you got it sorted. SDK Rust support is still a work-in-progress. It’d be interesting to hear how you progress and what comes out of it.

I just started the oxidation of Kuri. In case someone else wants to use Rust in a C++ code base with Sailfish, this is basically how I did it.

At first, it was necessary to use the Docker based SDK. See above for the reasons.

File structure

my-app
  |- cpp/main.cpp
  |- rust/lib.rs
  |- build.rs
  |- Cargo.toml
  |- CMakeLists.txt

The CMakeLists.txt

add_custom_target(
    my-app-rs ALL
    COMMAND cargo build --release -j 1 --target=aarch64-unknown-linux-gnu}
    BYPRODUCTS
    target/aarch64-unknown-linux-gnu/cxxbridge/my-app-rs/rust/lib.rs.cc
    target/aarch64-unknown-linux-gnu/release/libmy_app_rs.a
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    VERBATIM
    USES_TERMINAL
)

add_library(my-app-rs-ffi STATIC
    target/aarch64-unknown-linux-gnu/cxxbridge/my-app-rs/rust/lib.rs.cc
)
set_target_properties(my-app-rs-ffi PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON)

add_dependencies(my-app-rs-ffi my-app-rs)

target_include_directories(my-app-rs-ffi PUBLIC
    target/aarch64-unknown-linux-gnu/cxxbridge
)
target_link_libraries(my-app-rs-ffi
    ${SAILFISH_LDFLAGS}
    target/aarch64-unknown-linux-gnu/release/libmy_app_rs.a
    dl
)

add_executable(harbour-my-app
    cpp/main.cpp
)
set_target_properties(harbour-my-app PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON)
target_link_libraries(harbour-my-app
    ${SAILFISH_LDFLAGS}
    my-app-rs-ffi
)

The Cargo.toml

[package]
name = "my-app-rs"
version = "0.1.0"
edition = "2018"

[lib]
name = "my_app_rs"
crate-type = ["staticlib"]
path = "rust/lib.rs"

[dependencies]
cxx = { version = "1.0", features = ["c++17"] }

[build-dependencies]
cxx-build = { version = "1.0" }

The build.rs

fn main() {
    cxx_build::bridge("rust/lib.rs")
        .compile("my-app-rs");

    println!("cargo:rerun-if-changed=rust/lib.rs");
}

The rust/lib.rs

pub struct Foo {}

impl Foo {
    pub fn new() -> Box<Self> {
        println!("#### Hello from Rust");
        Box::new(Foo {})
    }
}

pub fn new_foo() -> Box<Foo> {
    Foo::new()
}

#[cxx::bridge(namespace = "my_app")]
mod ffi {
    extern "Rust" {
        type Foo;
        fn new_foo() -> Box<Foo>;
    }
}

The cpp/main.cpp

#include "my-app-rs/rust/lib.rs.h"

int main(int argc, char* argv[]) {
    auto foo = my_app::new_foo();
    ...
}

The rpm/harbour-my-app.yaml

PkgBR:
- rust >= 1.52
- cargo >= 1.52
- rust-std-static

As you can see in the CMakeLists.txt und build.rs, the files containing a cxx::bridge need to be added to multiple locations. I’ve created a more sophisticated solution where one needs to add these files just once to rust_cxx_bridge_file_list.txt and cmake and cargo will use that list.

3 Likes

I’ve a weird issue with my Rust code running in a thread. When I start the application from the terminal everything works as expected but when I start from the app grid, the application hangs when the std::thread starts. I found a workaround for this issue by inserting a std::thread::yield() in the Rust code but now the app crashes when something is send to that thread via a crossbeam channel. I was not yet able to create a nice backtrace and was wondering I anybody has an idea about the different behavior when started from the terminal versus from the app grid?

In case someone has the same problem. It seems that mapplauncherd silica-qt5 booster has issues with my approach of integrating Rust into a C++ code base. It somehow makes the app crash when there is a thread is Rust code which blocks on an empty crossbeam channel.

To fix this, I needed to adjust the .desktop file and change

X-Nemo-Application-Type=silica-qt5

to

X-Nemo-Application-Type=qtquick2

The startup of the application seems to be a bit slower but except that it runs stable.

1 Like