[Программирование, Разработка мобильных приложений, Rust] Запускаем Rust-приложение на мобильной ОС Аврора
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Всем привет! Меня зовут Шамиль, я ведущий инженер-разработчик в КРОК. Помимо всего прочего мы в компании занимаемся ещё и разработкой мобильных приложений для операционной системы Аврора, есть даже центр компетенций по ней.
Для промышленной разработки мы, конечно же, пока используем связку C++ и QML, но однажды подсев на "ржавую" иглу Rust, я не мог не попробовать применить свой любимый язык программирования для написания мобильных приложений. В этой статье я опишу эксперимент по написанию простейшего приложения на Rust, предназначенного для запуска на мобильном устройстве под управлением вышеупомянутой ОС. Сразу оговорюсь, что легких путей я не искал — эксперименты проводил на сертифицированной версии Авроры, которая добавила огонька в этот процесс. Но, как говорится, только защищённая ОС, только хардкор.Пара выходных у меня ушла только на то, чтобы запустить минимальное консольное приложение (речь о нём пойдёт в первой части), ещё пара дней — на эксперименты с графическим интерфейсом, выбор оптимального подхода и запуск приложения с GUI (этому посвящена вторая часть повествования). В итоге получился минимальный “скелет” мобильного приложения, готового к сборке и запуску, на который при желании уже можно наращивать “мясо”.Готовим окружениеИтак, работа будет вестись из-под Ubuntu Linux с уже установленным Rust. В качестве подопытного планшета выступает Aquarius NS220 с сертифицированной ОС Аврора последней (на момент написания статьи) версии 3.2.2 с включённым режимом разработчика, который обеспечивает связь по SSH, а также привилегированный доступ с правами суперпользователя.Первым делом добавим средства кросскомпилятора для архитектуры ARM, так как на целевом планшете стоит именно такой процессор.
sudo apt install -y g++-arm-linux-gnueabihf
rustup target add armv7-unknown-linux-gnueabihf
В сертифицированной версии ОС Аврора не разрешается запускать неподписанные приложения. Подписывать надо проприетарной утилитой из состава Aurora Certified SDK под названием ompcert-cli, которая поддерживает на входе только пакет в формате RPM. Поэтому сразу установим замечательную утилитуcargo-rpm, которая возьмёт на себя всю рутинную работу по упаковке приложения в RPM-пакет:
cargo install cargo-rpm
Саму процедуру подписывания RPM-пакета я описывать не буду, она неплохо документирована в справочных материалах ОС Аврора.Aurora SDK можно скачать с сайта производителя.Часть 1. Hello. WorldTL;DR Исходники проекта можно найти в репозитории на Гитхабе.Создаем минимальный проектСоздаём пустое приложение на Rust:
cargo new aurora-rust-helloworld
Пытаемся сгенерировать .spec файл для RPM-пакета:
cargo rpm init
Получаем ошибки, что не хватает некоторых полей в Cargo.toml, добавляем их:Cargo.toml:
[package]
name = "aurora-rust-helloworld"
version = "0.1.0"
authors = ["Shamil Yakupov <syakupov@croc.ru>"]
edition = "2018"
description = "Rust example for Aurora OS"
license = "MIT"
Закидываем в папку .cargo конфигурационный файл с указанием правильного линкера для компоновки исполняемого файла под архитектуру ARM:.cargo/config.toml:
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
Собираем RPM-пакет:
cargo rpm init
cargo rpm build -v --target=armv7-unknown-linux-gnueabihf
Всё собралось, забираем RPM из папки target/armv7-unknown-linux-gnueabihf/release/rpmbuild/RPMS/armv7hl, подписываем его, копируем на планшет и пытаемся установить:
$ devel-su
Password:
# pkcon install-local ./aurora-rust-helloworld-0.1.0-1.armv7hl.rpm
Получаем ошибку:
Fatal error: nothing provides libc.so.6(GLIBC_2.32) needed by
aurora-rust-helloworld-0.1.0-1.armv7hl
Смотрим версию glibc на устройстве, и понимаем, что она явно ниже той, что нам требуется:
$ ldd --version
ldd (GNU libc) 2.28
Что ж, тогда попробуем забрать нужные библиотеки с планшета, закинуть их в директорию lib и слинковать с ними. Для верности будем пользоваться линкером, входящим в состав Aurora SDK, который закинем в директорию bin. Для начала посмотрим, какие именно библиотеки нам нужны. Меняем содержимое .cargo/config.toml:
[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib"]
linker = "bin/armv7hl-meego-linux-gnueabi-ld"
Пробуем собрать:
cargo build --release --target=armv7-unknown-linux-gnueabihf
Получаем ошибки:
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lgcc_s
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutil
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lrt
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lpthread
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lm
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -ldl
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lc
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutil
Копируем недостающие библиотеки с планшета:
mkdir -p lib
scp nemo@192.168.2.15:/usr/lib/libgcc_s.so ./lib
scp nemo@192.168.2.15:/usr/lib/libutil.so ./lib
scp nemo@192.168.2.15:/usr/lib/librt.so ./lib
scp nemo@192.168.2.15:/usr/lib/libpthread.so ./lib
scp nemo@192.168.2.15:/usr/lib/libm.so ./lib
scp nemo@192.168.2.15:/usr/lib/libdl.so ./lib
scp nemo@192.168.2.15:/usr/lib/libc.so ./lib
scp nemo@192.168.2.15:/usr/lib/libutil.so ./lib
Снова пытаемся собрать, получаем новую порцию ошибок:
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /lib/libc.so.6 when searching for /lib/libc.so.6
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/libc.so.6
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /usr/lib/libc_nonshared.a when searching for /usr/lib/libc_nonshared.a
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /usr/lib/libc_nonshared.a
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/ld-linux-armhf.so.3
Копируем недостающее:
scp nemo@192.168.2.15:/lib/libc.so.6 ./lib
scp nemo@192.168.2.15:/usr/lib/libc_nonshared.a ./lib
scp nemo@192.168.2.15:/lib/ld-linux-armhf.so.3 ./lib
Ещё надо подредактировать файл libc.so (который является фактически скриптом линкера), чтобы дать понять линкеру, где надо искать библиотеки:lib/libc.so:
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-armhf.so.3 ) )
Запускаем сборку RPM-пакета, копируем, пытаемся установить.Здесь позволю себе небольшое лирическое отступление. Перед установкой RPM-пакета на сертифицированной версии ОС Аврора запускается RPM-валидатор — утилита, которая проверяет, насколько собранный пакет удовлетворяет требованиям системы. И до тех пор, пока пакет не пройдёт валидацию, установить приложение не получится. Безопасность превыше всего.Итак, мы видим, что валидатор выдал несколько ошибок:вот таких
Desktop file
============
ERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File is missing - cannot validate .desktop file
Paths
=====
WARNING [/usr/share/aurora-rust-helloworld] Directory not found
ERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File not found
WARNING [/usr/share/icons/hicolor/86x86/apps/aurora-rust-helloworld.png] File not found
WARNING [/usr/share/icons/hicolor/108x108/apps/aurora-rust-helloworld.png] File not found
WARNING [/usr/share/icons/hicolor/128x128/apps/aurora-rust-helloworld.png] File not found
WARNING [/usr/share/icons/hicolor/172x172/apps/aurora-rust-helloworld.png] File not found
ERROR [/usr/share/icons/hicolor/[0-9x]{5,9}/apps/aurora-rust-helloworld.png] No icons found! RPM must contain at least one icon, see: https://community.omprussia.ru/doc/software_development/guidelines/rpm_requirements
Libraries
=========
ERROR [/usr/bin/aurora-rust-helloworld] Cannot link to shared library: libutil.so.1
Symbols
=======
ERROR [/usr/bin/aurora-rust-helloworld] Binary does not link to 9__libc_start_main@GLIBC_2.4.
Requires
========
ERROR [libutil.so.1] Cannot require shared library: 'libutil.so.1'
Что ж, будем бороться с каждой ошибкой по списку.Добавляем недостающие файлыДобавим иконки и ярлык (файл с расширением desktop) в директорию .rpm..rpm/aurora-rust-helloworld.desktop:
[Desktop Entry]
Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=aurora-rust-helloworld
Exec=aurora-rust-helloworld
Name=Rust Hello-World
Для того, чтобы копировать нужные файлы на этапе сборки RPM-пакета, сделаем простенький Makefile:Makefile
.PHONY: all clean install prepare release rpm
all:
@cargo build --target=armv7-unknown-linux-gnueabihf
clean:
@rm -rvf target
install:
@scp ./target/armv7-unknown-linux-gnueabihf/release/aurora-rust-helloworld nemo@192.168.2.15:/home/nemo/
@scp ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/RPMS/armv7hl/*.rpm nemo@192.168.2.15:/home/nemo/
prepare:
@rustup target add armv7-unknown-linux-gnueabihf
@cargo install cargo-rpm
release:
@cargo build --release --target=armv7-unknown-linux-gnueabihf
rpm:
@mkdir -p ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES
@cp -vf .rpm/aurora-rust-helloworld.desktop ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES
@cp -rvf .rpm/icons ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES
@cargo rpm build -v --target=armv7-unknown-linux-gnueabihf
Обновим aurora-rust-helloworld.spec:.rpm/aurora-rust-helloworld.spec
%define __spec_install_post %{nil}
%define __os_install_post %{_dbpath}/brp-compress
%define debug_package %{nil}
Name: aurora-rust-helloworld
Summary: Rust example for Aurora OS
Version: @@VERSION@@
Release: @@RELEASE@@%{?dist}
License: MIT
Group: Applications/System
Source0: %{name}-%{version}.tar.gz
Source1: %{name}.desktop
Source2: icons
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
%{summary}
%prep
%setup -q
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}
cp -a * %{buildroot}
mkdir -p %{buildroot}%{_datadir}/applications
cp -a %{SOURCE1} %{buildroot}%{_datadir}/applications
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/86x86/apps
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/108x108/apps
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/128x128/apps
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/172x172/apps
cp -a %{SOURCE2}/86x86/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/86x86/apps
cp -a %{SOURCE2}/108x108/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/108x108/apps
cp -a %{SOURCE2}/128x128/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/128x128/apps
cp -a %{SOURCE2}/172x172/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/172x172/apps
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
%{_bindir}/*
%{_datadir}/applications/%{name}.desktop
%{_datadir}/icons/hicolor/*/apps/%{name}.png
Для сборки пакета теперь достаточно выполнить:
make rpm
Убираем зависимость от libutil.soЯ не нашёл способа, как убедить cargo при вызове команды линкера не передавать ключ -lutil. Вместо этого я решил создать скрипт-заглушку для линкера с какой-нибудь незначащей командой.lib/libutil.so:
/* GNU ld script
Dummy script to avoid dependency on libutil.so */
ASSERT(1, "Unreachable")
Да, не самый хороший способ. Если кто-нибудь знает, как сделать лучше, делитесь в комментариях. Добавляем символ __libc_start_mainПерепробовав несколько способов, остановился на том, чтобы добавить при линковке стандартный объектный файл crt1.o. Копируем его с планшета:
scp nemo@192.168.2.15:/usr/lib/crt1.o ./lib
И добавляем в команды линкера:.cargo/config.toml:
[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o"]
linker = "bin/armv7hl-meego-linux-gnueabi-ld"
Однако при попытке сборки получаем ошибки:
undefined reference to `__libc_csu_fini'
undefined reference to `__libc_csu_init'
Добавим заглушки этих функций в main.rs:src/main.rs:
#[no_mangle]
pub extern "C" fn __libc_csu_init() {}
#[no_mangle]
pub extern "C" fn __libc_csu_fini() {}
fn main() {
println!("Hello, world!");
}
Ещё один быстрый и грязный хак, зато теперь RPM-пакет проходит валидацию и устанавливается!Момент истины близок, запускаем на планшете и… получаем очередную ошибку:
$ aurora-rust-helloworld
-bash: /usr/bin/aurora-rust-helloworld: /usr/lib/ld.so.1: bad ELF
interpreter: No such file or directory
Смотрим зависимости:
$ ldd /usr/bin/aurora-rust-helloworld
linux-vdso.so.1 (0xbeff4000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xa707f000)
librt.so.1 => /lib/librt.so.1 (0xa7069000)
libpthread.so.0 => /lib/libpthread.so.0 (0xa7042000)
libm.so.6 => /lib/libm.so.6 (0xa6fc6000)
libdl.so.2 => /lib/libdl.so.2 (0xa6fb3000)
libc.so.6 => /lib/libc.so.6 (0xa6e95000)
/usr/lib/ld.so.1 => /lib/ld-linux-armhf.so.3 (0xa70e7000)
И видим динамическую линковку с библиотекой ld-linux-armhf.so.3. Если решать в лоб, то нужно создать символическую ссылку /usr/lib/ld.so.1 → /lib/ld-linux-armhf.so.3 (и это даже будет неплохо работать). Но, к сожалению, такое решение не подходит. Дело в том, что строгий RPM-валидатор не пропустит ни пред(пост)-установочные скрипты в .spec-файле, ни деплой в директорию /usr/lib. Вообще список того, что можно, приведён здесь.Долгое и разнообразное гугление подсказало, что у линкера GCC есть нужный нам ключ (dynamic-linker), который позволяет сослаться непосредственно на нужную зависимость. Правим config.toml:.cargo/config.toml:
[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o --dynamic-linker /lib/ld-linux-armhf.so.3"]
linker = "bin/armv7hl-meego-linux-gnueabi-ld"
Собираем RPM-пакет, подписываем, копируем на планшет, устанавливаем и с замиранием сердца запускаем:
$ aurora-rust-helloworld
Hello, world!
Часть 2. Запускаем приложение с GUITL;DR Исходники проекта можно найти в репозитории. В Авроре всё очень сильно завязано на Qt/QML, поэтому сначала я думал использовать крейтqmetaobject. Однако в “комплекте” с ОС идёт библиотека Qt версии 5.6.3, а qmetaobject, судя по описанию, требует минимум Qt 5.8. И действительно, попытка сборки крейта приводит к ошибкам.Поэтому я пошёл по пути точечных заимствований из исходников qmetaobject — благо, лицензия позволяет.Для начала копируем проект, созданный в предыдущей части, и переименовываем его в aurora-rust-gui.ПриступаемЧтобы не утомлять читателя, сразу скажу, что для сборки понадобится скопировать с планшета ещё множество разных библиотек:вот таких
scp nemo@192.168.2.15:/usr/lib/libstdc++.so ./lib
scp nemo@192.168.2.15:/usr/lib/libQt5Core.so.5 ./lib/libQt5Core.so
scp nemo@192.168.2.15:/usr/lib/libQt5Gui.so.5 ./lib/libQt5Gui.so
scp nemo@192.168.2.15:/usr/lib/libQt5Qml.so.5 ./lib/libQt5Qml.so
scp nemo@192.168.2.15:/usr/lib/libQt5Quick.so.5 ./lib/libQt5Quick.so
scp nemo@192.168.2.15:/usr/lib/libGLESv2.so.2 ./lib
scp nemo@192.168.2.15:/usr/lib/libpng16.so.16 ./lib
scp nemo@192.168.2.15:/usr/lib/libz.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/libicui18n.so.63 ./lib
scp nemo@192.168.2.15:/usr/lib/libicuuc.so.63 ./lib
scp nemo@192.168.2.15:/usr/lib/libpcre16.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libglib-2.0.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libsystemd.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libQt5Network.so.5 ./lib
scp nemo@192.168.2.15:/lib/libresolv.so.2 ./lib
scp nemo@192.168.2.15:/usr/lib/libhybris-common.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/libicudata.so.63 ./lib
scp nemo@192.168.2.15:/usr/lib/libpcre.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/libselinux.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/liblzma.so.5 ./lib
scp nemo@192.168.2.15:/usr/lib/libgcrypt.so.11 ./lib
scp nemo@192.168.2.15:/usr/lib/libgpg-error.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libcap.so.2 ./lib
scp nemo@192.168.2.15:/usr/lib/libsailfishapp.so.1 ./lib/libsailfishapp.so
scp nemo@192.168.2.15:/usr/lib/libmdeclarativecache5.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libmlite5.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/libgobject-2.0.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libQt5DBus.so.5 ./lib
scp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./lib
scp nemo@192.168.2.15:/usr/lib/libffi.so.6 ./lib
scp nemo@192.168.2.15:/usr/lib/libdbus-1.so.3 ./lib
scp nemo@192.168.2.15:/usr/lib/libgio-2.0.so.0 ./lib
scp nemo@192.168.2.15:/usr/lib/libgmodule-2.0.so.0 ./lib
А еще копируем заголовочные файлы, которые идут в составе Aurora SDK:
- AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/qt5 → include/qt5
- AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/sailfishapp → include/sailfishapp
- AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/GLES3 → include/GLES3
- AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/KHR → include/KHR
Для сборки проекта напишем скрипт build.rs и укажем его в Cargo.toml.build.rs:
fn main() {
let include_path = "include";
let qt_include_path = "include/qt5";
let sailfish_include_path = "include/sailfishapp";
let library_path = "lib";
let mut config = cpp_build::Config::new();
config
.include(include_path)
.include(qt_include_path)
.include(sailfish_include_path)
.opt_level(2)
.flag("-std=gnu++1y")
.flag("-mfloat-abi=hard")
.flag("-mfpu=neon")
.flag("-mthumb")
.build("src/main.rs");
println!("cargo:rustc-link-search={}", library_path);
println!("cargo:rustc-link-lib=sailfishapp");
println!("cargo:rustc-link-lib=Qt5Gui");
println!("cargo:rustc-link-lib=Qt5Core");
println!("cargo:rustc-link-lib=Qt5Quick");
println!("cargo:rustc-link-lib=Qt5Qml");
}
Cargo.toml:
[package]
# ...
build = "build.rs"
[dependencies]
cpp = "0.5.6"
[build-dependencies]
cpp_build = "0.5.6"
#...
Теперь возьмёмся за само приложение. За создание инстанса приложения у нас будет отвечать структура SailfishApp по аналогии с приложением для Авроры, написанном на C++.src/main.rs:
#[macro_use]
extern crate cpp;
mod qbytearray;
mod qstring;
mod qurl;
mod sailfishapp;
use sailfishapp::SailfishApp;
#[no_mangle]
pub extern "C" fn __libc_csu_init() {}
#[no_mangle]
pub extern "C" fn __libc_csu_fini() {}
fn main() {
let mut app = SailfishApp::new();
app.set_source("main.qml".into());
app.show();
app.exec();
}
SailfishApp — это по сути обвязка (биндинги) к соответствующему классу на C++. Берём за образец структуруQmlEngine из крейта qmetaobject.src/sailfishapp.rs
use crate::qstring::QString;
cpp! {{
#include <sailfishapp.h>
#include <QtCore/QDebug>
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>
#include <memory>
struct SailfishAppHolder {
std::unique_ptr<QGuiApplication> app;
std::unique_ptr<QQuickView> view;
SailfishAppHolder() {
qDebug() << "SailfishAppHolder::SailfishAppHolder()";
int argc = 1;
char *argv[] = { "aurora-rust-gui" };
app.reset(SailfishApp::application(argc, argv));
view.reset(SailfishApp::createView());
view->engine()->addImportPath("/usr/share/aurora-rust-gui/qml");
}
};
}}
cpp_class!(
pub unsafe struct SailfishApp as "SailfishAppHolder"
);
impl SailfishApp {
/// Creates a new SailfishApp.
pub fn new() -> Self {
cpp!(unsafe [] -> SailfishApp as "SailfishAppHolder" {
qDebug() << "SailfishApp::new()";
return SailfishAppHolder();
})
}
/// Sets the main QML (see QQuickView::setSource for details).
pub fn set_source(&mut self, url: QString) {
cpp!(unsafe [self as "SailfishAppHolder *", url as "QString"] {
const auto full_url = QString("/usr/share/aurora-rust-gui/qml/%1").arg(url);
qDebug() << "SailfishApp::set_source()" << full_url;
self->view->setSource(full_url);
});
}
/// Shows the main view.
pub fn show(&self) {
cpp!(unsafe [self as "SailfishAppHolder *"] {
qDebug() << "SailfishApp::show()";
self->view->showFullScreen();
})
}
/// Launches the application.
pub fn exec(&self) {
cpp!(unsafe [self as "SailfishAppHolder *"] {
qDebug() << "SailfishApp::exec()";
self->app->exec();
})
}
}
Биндинги для используемых классов QByteArray, QString, QUrl копируем из того же qmetaobject и расфасовываемым по отдельным файлам. Здесь приводить их не буду, если что, исходники можно посмотреть врепозитории на GitHub.Немного скорректируем заголовочный файл sailfishapp.h, чтобы он искал заголовочные файлы Qt в правильных местах:include/sailfishapp/sailfishapp.h:
// ...
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <QtCore/QtGlobal> // Было `#include <QtGlobal>`
#include <QtCore/QUrl> // Было `#include <QUrl>`
class QGuiApplication;
class QQuickView;
class QString;
// ...
Осталось только добавить файлы QML и положить их в дистрибутив RPM.все здесьqml/main.qml:
import QtQuick 2.6
import Sailfish.Silica 1.0
ApplicationWindow {
cover: Qt.resolvedUrl("cover.qml")
initialPage: Page {
allowedOrientations: Orientation.LandscapeMask
Label {
anchors.centerIn: parent
text: "Hello, Aurora!"
}
}
}
qml/cover.qml:
import QtQuick 2.6
import Sailfish.Silica 1.0
CoverBackground {
Rectangle {
id: background
anchors.fill: parent
color: "blue"
Label {
id: label
anchors.centerIn: parent
text: "Rust GUI"
color: "white"
}
}
CoverActionList {
id: coverAction
CoverAction {
iconSource: "image://theme/icon-cover-cancel"
onTriggered: Qt.quit()
}
}
}
.rpm/aurora-rust-gui.spec:
# ...
Source3: qml
# ...
%install
# ...
mkdir -p %{buildroot}%{_datadir}/%{name}
cp -ra %{SOURCE3} %{buildroot}%{_datadir}/%{name}/qml
%clean
rm -rf %{buildroot}
%files
# ...
%{_datadir}/%{name}/qml
Makefile:
# ...
rpm:
# ...
@cp -rvf qml ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES
# ...
Собираем:
make clean
make release
make rpm
Подписываем, копируем, устанавливаем, запускаем из командной строки и вуаля:
$ devel-su
Password:
# pkcon install-local ./aurora-rust-gui-0.1.0-1.armv7hl.rpm
Installing files
Testing changes
Finished
Installing files
Starting
Resolving dependencies
Installing packages
Downloading packages
Installing packages
Finished
Downloaded aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR)
Rust GUI example for Aurora OS
Installed aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR)
Rust GUI example for Aurora OS
# exit
$ aurora-rust-gui
[D] __cpp_closure_14219197022164792912_impl:33 - SailfishApp::new()
[D] SailfishAppHolder::SailfishAppHolder:15 - SailfishAppHolder::SailfishAppHolder()
[D] unknown:0 - Using Wayland-EGL
library "libpq_cust_base.so" not found
[D] __cpp_closure_16802020016530731597:42 - SailfishApp::set_source() "/usr/share/aurora-rust-gui/qml/main.qml"
[W] unknown:0 - Could not find any zN.M subdirs!
[W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/z1.0/" does not exist
[W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/" does not exist
[D] onCompleted:432 - Warning: specifying an object instance for initialPage is sub-optimal - prefer to use a Component
[D] __cpp_closure_12585295123509486988:50 - SailfishApp::show()
[D] __cpp_closure_15029454612933909268:59 - SailfishApp::exec()
Вот так выглядит наше приложение с разных ракурсов:
Рабочий стол с ярлыком
Главное окно приложения
Панель задачПоследние штрихиПриложение отлично стартует из командной строки при подключении по SSH, однако никак не реагирует при попытке запуска с помощью ярлыка. Путём некоторых экспериментов удалось установить, что для этого надо экспортировать символ main (RPM-валидатор выдавал предупреждение на этот счёт, но некритичное).Серия проб и ошибок показала, что надо добавить ещё один ключ линкера: -export-dynamic..cargo/config.toml:
[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o -rpath lib --dynamic-linker /lib/ld-linux-armhf.so.3 -export-dynamic"]
linker = "bin/armv7hl-meego-linux-gnueabi-ld"
После этого всё работает так, как и ожидается.ЗаключениеПонятно, что до того, как использовать Rust в проде, ещё надо решить немало вопросов. Как минимум, я предвижу сложности с дополнительными зависимостями при подключении новых крейтов, извечные танцы с бубном вокруг сегфолтов при FFI-вызовах, увязывание систем владения Qt и Rust. Некоторые интересные подробности можно почерпнуть из статьи от автора qmetaobject-rs. Наверняка, время от времени будут всплывать и другие проблемы.Плюс к этому, для того, чтобы использовать Qt-овские классы, к каждому из них необходимо писать биндинги.Однако всё это стоит того, чтобы иметь возможность писать на Rust, с его мощной системой типов, средствами обеспечения безопасности при работе с памятью, приятной реализацией многопоточности, самым лучшим подходом к обработке ошибок и всеми теми вещами за которые мы его так любим.Буду рад вопросам и замечаниям в комментариях. И ставьте лайк, подписывайтесь на канал :-)
===========
Источник:
habr.com
===========
Похожие новости:
- [Системное администрирование, Программирование, IT-инфраструктура, Apache] Как Apache Kafka поддерживает 200К партиций в кластере? (перевод)
- [Python, Программирование, Big Data, Визуализация данных, Звук] Популярность BPM в разных жанрах музыки. Анализ скорости исполнения 500 лучших песен
- [Программирование, Машинное обучение] Искусственный интеллект обновит устаревшее программное обеспечение за вас (перевод)
- [JavaScript, Программирование, HTML, TensorFlow] Отслеживание лиц в реальном времени в браузере с использованием TensorFlow.js. Часть 1 (перевод)
- [JavaScript, Программирование] Почему вы можете обойтись без Babel (перевод)
- [Разработка веб-сайтов, Разработка мобильных приложений] 10 инструментов для разработки, которые вам стоит попробовать (перевод)
- [Программирование, Assembler] Как писать на ассемблере в 2021 году
- [Разработка мобильных приложений, Интерфейсы, Дизайн мобильных приложений, Дизайн] Новая версия Яндекс.Заправок: с учётом (неожиданного) опыта водителей
- [Программирование, Совершенный код] Trace, Info, Warning, Error, Fatal — кто все эти люди..?
- [Программирование, Клиентская оптимизация, Разработка игр, Софт] Как я сократил время загрузки GTA Online на 70% (перевод)
Теги для поиска: #_programmirovanie (Программирование), #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_rust, #_rust, #_avrora_os (аврора ос), #_razrabotka_prilozhenij (разработка приложений), #_blog_kompanii_krok (
Блог компании КРОК
), #_programmirovanie (
Программирование
), #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_rust
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:25
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Всем привет! Меня зовут Шамиль, я ведущий инженер-разработчик в КРОК. Помимо всего прочего мы в компании занимаемся ещё и разработкой мобильных приложений для операционной системы Аврора, есть даже центр компетенций по ней. Для промышленной разработки мы, конечно же, пока используем связку C++ и QML, но однажды подсев на "ржавую" иглу Rust, я не мог не попробовать применить свой любимый язык программирования для написания мобильных приложений. В этой статье я опишу эксперимент по написанию простейшего приложения на Rust, предназначенного для запуска на мобильном устройстве под управлением вышеупомянутой ОС. Сразу оговорюсь, что легких путей я не искал — эксперименты проводил на сертифицированной версии Авроры, которая добавила огонька в этот процесс. Но, как говорится, только защищённая ОС, только хардкор.Пара выходных у меня ушла только на то, чтобы запустить минимальное консольное приложение (речь о нём пойдёт в первой части), ещё пара дней — на эксперименты с графическим интерфейсом, выбор оптимального подхода и запуск приложения с GUI (этому посвящена вторая часть повествования). В итоге получился минимальный “скелет” мобильного приложения, готового к сборке и запуску, на который при желании уже можно наращивать “мясо”.Готовим окружениеИтак, работа будет вестись из-под Ubuntu Linux с уже установленным Rust. В качестве подопытного планшета выступает Aquarius NS220 с сертифицированной ОС Аврора последней (на момент написания статьи) версии 3.2.2 с включённым режимом разработчика, который обеспечивает связь по SSH, а также привилегированный доступ с правами суперпользователя.Первым делом добавим средства кросскомпилятора для архитектуры ARM, так как на целевом планшете стоит именно такой процессор. sudo apt install -y g++-arm-linux-gnueabihf
rustup target add armv7-unknown-linux-gnueabihf cargo install cargo-rpm
cargo new aurora-rust-helloworld
cargo rpm init
[package]
name = "aurora-rust-helloworld" version = "0.1.0" authors = ["Shamil Yakupov <syakupov@croc.ru>"] edition = "2018" description = "Rust example for Aurora OS" license = "MIT" [target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc" cargo rpm init
cargo rpm build -v --target=armv7-unknown-linux-gnueabihf $ devel-su
Password: # pkcon install-local ./aurora-rust-helloworld-0.1.0-1.armv7hl.rpm Fatal error: nothing provides libc.so.6(GLIBC_2.32) needed by
aurora-rust-helloworld-0.1.0-1.armv7hl $ ldd --version
ldd (GNU libc) 2.28 [target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib"] linker = "bin/armv7hl-meego-linux-gnueabi-ld" cargo build --release --target=armv7-unknown-linux-gnueabihf
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lgcc_s
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutil aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lrt aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lpthread aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lm aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -ldl aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lc aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutil mkdir -p lib
scp nemo@192.168.2.15:/usr/lib/libgcc_s.so ./lib scp nemo@192.168.2.15:/usr/lib/libutil.so ./lib scp nemo@192.168.2.15:/usr/lib/librt.so ./lib scp nemo@192.168.2.15:/usr/lib/libpthread.so ./lib scp nemo@192.168.2.15:/usr/lib/libm.so ./lib scp nemo@192.168.2.15:/usr/lib/libdl.so ./lib scp nemo@192.168.2.15:/usr/lib/libc.so ./lib scp nemo@192.168.2.15:/usr/lib/libutil.so ./lib aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /lib/libc.so.6 when searching for /lib/libc.so.6
aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/libc.so.6 aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /usr/lib/libc_nonshared.a when searching for /usr/lib/libc_nonshared.a aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /usr/lib/libc_nonshared.a aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/ld-linux-armhf.so.3 scp nemo@192.168.2.15:/lib/libc.so.6 ./lib
scp nemo@192.168.2.15:/usr/lib/libc_nonshared.a ./lib scp nemo@192.168.2.15:/lib/ld-linux-armhf.so.3 ./lib /* GNU ld script
Use the shared library, but some functions are only in the static library, so try that secondarily. */ OUTPUT_FORMAT(elf32-littlearm) GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-armhf.so.3 ) ) Desktop file
============ ERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File is missing - cannot validate .desktop file Paths ===== WARNING [/usr/share/aurora-rust-helloworld] Directory not found ERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File not found WARNING [/usr/share/icons/hicolor/86x86/apps/aurora-rust-helloworld.png] File not found WARNING [/usr/share/icons/hicolor/108x108/apps/aurora-rust-helloworld.png] File not found WARNING [/usr/share/icons/hicolor/128x128/apps/aurora-rust-helloworld.png] File not found WARNING [/usr/share/icons/hicolor/172x172/apps/aurora-rust-helloworld.png] File not found ERROR [/usr/share/icons/hicolor/[0-9x]{5,9}/apps/aurora-rust-helloworld.png] No icons found! RPM must contain at least one icon, see: https://community.omprussia.ru/doc/software_development/guidelines/rpm_requirements Libraries ========= ERROR [/usr/bin/aurora-rust-helloworld] Cannot link to shared library: libutil.so.1 Symbols ======= ERROR [/usr/bin/aurora-rust-helloworld] Binary does not link to 9__libc_start_main@GLIBC_2.4. Requires ======== ERROR [libutil.so.1] Cannot require shared library: 'libutil.so.1' [Desktop Entry]
Type=Application X-Nemo-Application-Type=silica-qt5 Icon=aurora-rust-helloworld Exec=aurora-rust-helloworld Name=Rust Hello-World .PHONY: all clean install prepare release rpm
all: @cargo build --target=armv7-unknown-linux-gnueabihf clean: @rm -rvf target install: @scp ./target/armv7-unknown-linux-gnueabihf/release/aurora-rust-helloworld nemo@192.168.2.15:/home/nemo/ @scp ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/RPMS/armv7hl/*.rpm nemo@192.168.2.15:/home/nemo/ prepare: @rustup target add armv7-unknown-linux-gnueabihf @cargo install cargo-rpm release: @cargo build --release --target=armv7-unknown-linux-gnueabihf rpm: @mkdir -p ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES @cp -vf .rpm/aurora-rust-helloworld.desktop ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES @cp -rvf .rpm/icons ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES @cargo rpm build -v --target=armv7-unknown-linux-gnueabihf %define __spec_install_post %{nil}
%define __os_install_post %{_dbpath}/brp-compress %define debug_package %{nil} Name: aurora-rust-helloworld Summary: Rust example for Aurora OS Version: @@VERSION@@ Release: @@RELEASE@@%{?dist} License: MIT Group: Applications/System Source0: %{name}-%{version}.tar.gz Source1: %{name}.desktop Source2: icons BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %description %{summary} %prep %setup -q %install rm -rf %{buildroot} mkdir -p %{buildroot} cp -a * %{buildroot} mkdir -p %{buildroot}%{_datadir}/applications cp -a %{SOURCE1} %{buildroot}%{_datadir}/applications mkdir -p %{buildroot}%{_datadir}/icons/hicolor/86x86/apps mkdir -p %{buildroot}%{_datadir}/icons/hicolor/108x108/apps mkdir -p %{buildroot}%{_datadir}/icons/hicolor/128x128/apps mkdir -p %{buildroot}%{_datadir}/icons/hicolor/172x172/apps cp -a %{SOURCE2}/86x86/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/86x86/apps cp -a %{SOURCE2}/108x108/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/108x108/apps cp -a %{SOURCE2}/128x128/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/128x128/apps cp -a %{SOURCE2}/172x172/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/172x172/apps %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %{_bindir}/* %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/*/apps/%{name}.png make rpm
/* GNU ld script
Dummy script to avoid dependency on libutil.so */ ASSERT(1, "Unreachable") scp nemo@192.168.2.15:/usr/lib/crt1.o ./lib
[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o"] linker = "bin/armv7hl-meego-linux-gnueabi-ld" undefined reference to `__libc_csu_fini'
undefined reference to `__libc_csu_init' #[no_mangle]
pub extern "C" fn __libc_csu_init() {} #[no_mangle] pub extern "C" fn __libc_csu_fini() {} fn main() { println!("Hello, world!"); } $ aurora-rust-helloworld
-bash: /usr/bin/aurora-rust-helloworld: /usr/lib/ld.so.1: bad ELF interpreter: No such file or directory $ ldd /usr/bin/aurora-rust-helloworld
linux-vdso.so.1 (0xbeff4000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xa707f000) librt.so.1 => /lib/librt.so.1 (0xa7069000) libpthread.so.0 => /lib/libpthread.so.0 (0xa7042000) libm.so.6 => /lib/libm.so.6 (0xa6fc6000) libdl.so.2 => /lib/libdl.so.2 (0xa6fb3000) libc.so.6 => /lib/libc.so.6 (0xa6e95000) /usr/lib/ld.so.1 => /lib/ld-linux-armhf.so.3 (0xa70e7000) [target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o --dynamic-linker /lib/ld-linux-armhf.so.3"] linker = "bin/armv7hl-meego-linux-gnueabi-ld" $ aurora-rust-helloworld
Hello, world! scp nemo@192.168.2.15:/usr/lib/libstdc++.so ./lib
scp nemo@192.168.2.15:/usr/lib/libQt5Core.so.5 ./lib/libQt5Core.so scp nemo@192.168.2.15:/usr/lib/libQt5Gui.so.5 ./lib/libQt5Gui.so scp nemo@192.168.2.15:/usr/lib/libQt5Qml.so.5 ./lib/libQt5Qml.so scp nemo@192.168.2.15:/usr/lib/libQt5Quick.so.5 ./lib/libQt5Quick.so scp nemo@192.168.2.15:/usr/lib/libGLESv2.so.2 ./lib scp nemo@192.168.2.15:/usr/lib/libpng16.so.16 ./lib scp nemo@192.168.2.15:/usr/lib/libz.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/libicui18n.so.63 ./lib scp nemo@192.168.2.15:/usr/lib/libicuuc.so.63 ./lib scp nemo@192.168.2.15:/usr/lib/libpcre16.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libglib-2.0.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libsystemd.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libQt5Network.so.5 ./lib scp nemo@192.168.2.15:/lib/libresolv.so.2 ./lib scp nemo@192.168.2.15:/usr/lib/libhybris-common.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/libicudata.so.63 ./lib scp nemo@192.168.2.15:/usr/lib/libpcre.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/libselinux.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/liblzma.so.5 ./lib scp nemo@192.168.2.15:/usr/lib/libgcrypt.so.11 ./lib scp nemo@192.168.2.15:/usr/lib/libgpg-error.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libcap.so.2 ./lib scp nemo@192.168.2.15:/usr/lib/libsailfishapp.so.1 ./lib/libsailfishapp.so scp nemo@192.168.2.15:/usr/lib/libmdeclarativecache5.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libmlite5.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/libgobject-2.0.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libQt5DBus.so.5 ./lib scp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./lib scp nemo@192.168.2.15:/usr/lib/libffi.so.6 ./lib scp nemo@192.168.2.15:/usr/lib/libdbus-1.so.3 ./lib scp nemo@192.168.2.15:/usr/lib/libgio-2.0.so.0 ./lib scp nemo@192.168.2.15:/usr/lib/libgmodule-2.0.so.0 ./lib
fn main() {
let include_path = "include"; let qt_include_path = "include/qt5"; let sailfish_include_path = "include/sailfishapp"; let library_path = "lib"; let mut config = cpp_build::Config::new(); config .include(include_path) .include(qt_include_path) .include(sailfish_include_path) .opt_level(2) .flag("-std=gnu++1y") .flag("-mfloat-abi=hard") .flag("-mfpu=neon") .flag("-mthumb") .build("src/main.rs"); println!("cargo:rustc-link-search={}", library_path); println!("cargo:rustc-link-lib=sailfishapp"); println!("cargo:rustc-link-lib=Qt5Gui"); println!("cargo:rustc-link-lib=Qt5Core"); println!("cargo:rustc-link-lib=Qt5Quick"); println!("cargo:rustc-link-lib=Qt5Qml"); } [package]
# ... build = "build.rs" [dependencies] cpp = "0.5.6" [build-dependencies] cpp_build = "0.5.6" #... #[macro_use]
extern crate cpp; mod qbytearray; mod qstring; mod qurl; mod sailfishapp; use sailfishapp::SailfishApp; #[no_mangle] pub extern "C" fn __libc_csu_init() {} #[no_mangle] pub extern "C" fn __libc_csu_fini() {} fn main() { let mut app = SailfishApp::new(); app.set_source("main.qml".into()); app.show(); app.exec(); } use crate::qstring::QString;
cpp! {{ #include <sailfishapp.h> #include <QtCore/QDebug> #include <QtGui/QGuiApplication> #include <QtQuick/QQuickView> #include <QtQml/QQmlEngine> #include <memory> struct SailfishAppHolder { std::unique_ptr<QGuiApplication> app; std::unique_ptr<QQuickView> view; SailfishAppHolder() { qDebug() << "SailfishAppHolder::SailfishAppHolder()"; int argc = 1; char *argv[] = { "aurora-rust-gui" }; app.reset(SailfishApp::application(argc, argv)); view.reset(SailfishApp::createView()); view->engine()->addImportPath("/usr/share/aurora-rust-gui/qml"); } }; }} cpp_class!( pub unsafe struct SailfishApp as "SailfishAppHolder" ); impl SailfishApp { /// Creates a new SailfishApp. pub fn new() -> Self { cpp!(unsafe [] -> SailfishApp as "SailfishAppHolder" { qDebug() << "SailfishApp::new()"; return SailfishAppHolder(); }) } /// Sets the main QML (see QQuickView::setSource for details). pub fn set_source(&mut self, url: QString) { cpp!(unsafe [self as "SailfishAppHolder *", url as "QString"] { const auto full_url = QString("/usr/share/aurora-rust-gui/qml/%1").arg(url); qDebug() << "SailfishApp::set_source()" << full_url; self->view->setSource(full_url); }); } /// Shows the main view. pub fn show(&self) { cpp!(unsafe [self as "SailfishAppHolder *"] { qDebug() << "SailfishApp::show()"; self->view->showFullScreen(); }) } /// Launches the application. pub fn exec(&self) { cpp!(unsafe [self as "SailfishAppHolder *"] { qDebug() << "SailfishApp::exec()"; self->app->exec(); }) } } // ...
#ifdef QT_QML_DEBUG #include <QtQuick> #endif #include <QtCore/QtGlobal> // Было `#include <QtGlobal>` #include <QtCore/QUrl> // Было `#include <QUrl>` class QGuiApplication; class QQuickView; class QString; // ... import QtQuick 2.6
import Sailfish.Silica 1.0 ApplicationWindow { cover: Qt.resolvedUrl("cover.qml") initialPage: Page { allowedOrientations: Orientation.LandscapeMask Label { anchors.centerIn: parent text: "Hello, Aurora!" } } } import QtQuick 2.6
import Sailfish.Silica 1.0 CoverBackground { Rectangle { id: background anchors.fill: parent color: "blue" Label { id: label anchors.centerIn: parent text: "Rust GUI" color: "white" } } CoverActionList { id: coverAction CoverAction { iconSource: "image://theme/icon-cover-cancel" onTriggered: Qt.quit() } } } # ...
Source3: qml # ... %install # ... mkdir -p %{buildroot}%{_datadir}/%{name} cp -ra %{SOURCE3} %{buildroot}%{_datadir}/%{name}/qml %clean rm -rf %{buildroot} %files # ... %{_datadir}/%{name}/qml # ...
rpm: # ... @cp -rvf qml ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES # ... make clean
make release make rpm $ devel-su
Password: # pkcon install-local ./aurora-rust-gui-0.1.0-1.armv7hl.rpm Installing files Testing changes Finished Installing files Starting Resolving dependencies Installing packages Downloading packages Installing packages Finished Downloaded aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR) Rust GUI example for Aurora OS Installed aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR) Rust GUI example for Aurora OS # exit $ aurora-rust-gui [D] __cpp_closure_14219197022164792912_impl:33 - SailfishApp::new() [D] SailfishAppHolder::SailfishAppHolder:15 - SailfishAppHolder::SailfishAppHolder() [D] unknown:0 - Using Wayland-EGL library "libpq_cust_base.so" not found [D] __cpp_closure_16802020016530731597:42 - SailfishApp::set_source() "/usr/share/aurora-rust-gui/qml/main.qml" [W] unknown:0 - Could not find any zN.M subdirs! [W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/z1.0/" does not exist [W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/" does not exist [D] onCompleted:432 - Warning: specifying an object instance for initialPage is sub-optimal - prefer to use a Component [D] __cpp_closure_12585295123509486988:50 - SailfishApp::show() [D] __cpp_closure_15029454612933909268:59 - SailfishApp::exec() Рабочий стол с ярлыком Главное окно приложения Панель задачПоследние штрихиПриложение отлично стартует из командной строки при подключении по SSH, однако никак не реагирует при попытке запуска с помощью ярлыка. Путём некоторых экспериментов удалось установить, что для этого надо экспортировать символ main (RPM-валидатор выдавал предупреждение на этот счёт, но некритичное).Серия проб и ошибок показала, что надо добавить ещё один ключ линкера: -export-dynamic..cargo/config.toml: [target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-args=-L lib lib/crt1.o -rpath lib --dynamic-linker /lib/ld-linux-armhf.so.3 -export-dynamic"] linker = "bin/armv7hl-meego-linux-gnueabi-ld" =========== Источник: habr.com =========== Похожие новости:
Блог компании КРОК ), #_programmirovanie ( Программирование ), #_razrabotka_mobilnyh_prilozhenij ( Разработка мобильных приложений ), #_rust |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:25
Часовой пояс: UTC + 5