aboutsummaryrefslogtreecommitdiff
path: root/_posts/2023-05-01-rust-and-tl-mr3020.md
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-09-05 00:16:37 +0300
committerValentin Popov <valentin@popov.link>2024-09-05 00:16:37 +0300
commit7eff3fde5720eb23449e2f8c8ea0b8218efe4dde (patch)
treefbaedd693902c1a6d56a005b28b189ef76fe23f4 /_posts/2023-05-01-rust-and-tl-mr3020.md
parentecf9a15e77509d344ab4ee02ae0dbf8a116021f1 (diff)
downloadpopov.link-7eff3fde5720eb23449e2f8c8ea0b8218efe4dde.tar.xz
popov.link-7eff3fde5720eb23449e2f8c8ea0b8218efe4dde.zip
Initial Astro project
Diffstat (limited to '_posts/2023-05-01-rust-and-tl-mr3020.md')
-rw-r--r--_posts/2023-05-01-rust-and-tl-mr3020.md189
1 files changed, 0 insertions, 189 deletions
diff --git a/_posts/2023-05-01-rust-and-tl-mr3020.md b/_posts/2023-05-01-rust-and-tl-mr3020.md
deleted file mode 100644
index 0cf59dd..0000000
--- a/_posts/2023-05-01-rust-and-tl-mr3020.md
+++ /dev/null
@@ -1,189 +0,0 @@
----
-description: >-
- Как настроить и оптимизировать проект Rust для кросс-компиляции на TP-Link TL-MR3020 с использованием Fedora Linux 38 и OpenWrt 22.03.4. Шаг за шагом от базового "Hello, World!" до асинхронного TCP сервера.
-title: Компиляция Rust на TL-MR3020
-author: valentineus
-layout: post
----
-
-Информация в статье актуальна для дистрибутива [Fedora Linux 38](https://docs.fedoraproject.org/en-US/releases/f38/), прошивки [OpenWrt 22.03.4](https://openwrt.org/releases/22.03/notes-22.03.4) и устройства [TP-Link TL-MR3020](https://www.tp-link.com/en/home-networking/3g-4g-router/tl-mr3020/) ревизии v3.20.
-
-Потребуется:
-
-- Установленный [rustup](https://rustup.rs/) инструментарий.
-- Установленный пакет [cross-rs](https://github.com/cross-rs/cross) для кросс-компиляции.
-- Упаковщик исполняемых файлов [upx](https://github.com/upx/upx).
-- Контейнеризатор [Docker](https://docs.docker.com/engine/install/) (рекомендуется) или [Podman](https://podman.io/getting-started/installation).
-- SSH подключение к маршрутизатору.
-- Установленный [SFTP сервер](https://openwrt.org/docs/guide-user/services/nas/sftp.server) на TL-MR3020.
-
-> Требуется rustup инструментарий с официального сайта.
-Rust и Cargo из репозитория дистрибутива не подойдут.
-Пакет кросс-компиляции требует rustup, который в репозиториях дистрибутива отсутствует.
-
-## "Hello, World!" ver. 1
-
-Начнем с базы.
-Соберем и запустим "Hello, World" на маршрутизаторе.
-Инициализируем проект на Rust:
-
-```bash
-cargo init --bin ramips-rs
-```
-
-Далее, чтобы выполнить кросс-компиляцию, определим архитектуру процессора:
-
-```bash
-cat /proc/cpuinfo
-# system type : MediaTek MT7628AN ver:1 eco:2
-# machine : TP-Link TL-MR3020 v3
-# processor : 0
-# cpu model : MIPS 24KEc V5.5
-# BogoMIPS : 385.84
-# wait instruction : yes
-# microsecond timers : yes
-# tlb_entries : 32
-# extra interrupt vector : yes
-# hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
-# isa : mips1 mips2 mips32r1 mips32r2
-# ASEs implemented : mips16 dsp
-# Options implemented : tlb 4kex 4k_cache prefetch mcheck ejtag llsc pindexed_dcache userlocal vint perf_cntr_intr_bit perf
-# shadow register sets : 1
-# kscratch registers : 0
-# package : 0
-# core : 0
-# VCED exceptions : not available
-# VCEI exceptions : not available
-```
-
-Видим, что процессор архитектуры MIPS.
-Теперь определим целевую архитектуру для компиляции:
-
-```bash
-rustup target list | grep mips
-# mips-unknown-linux-gnu
-# mips-unknown-linux-musl
-# mips64-unknown-linux-gnuabi64
-# mips64-unknown-linux-muslabi64
-# mips64el-unknown-linux-gnuabi64
-# mips64el-unknown-linux-muslabi64
-# mipsel-unknown-linux-gnu
-# mipsel-unknown-linux-musl
-```
-
-Опытным путем определяем, что в случае с TL-MR3020 v3.20 подходит архитектура `mipsel-unknown-linux-musl`.
-Далее компилируем проект под целевую архитектуру:
-
-```bash
-cross build --release --target mipsel-unknown-linux-musl
-```
-
-Получаем исполняемый бинарный файл, который загружаем и запускаем на маршрутизаторе.
-Выгружаем в раздел `/tmp`, потому что доступной памяти на основном разделе меньше двух мегабайт.
-
-```bash
-scp ./target/mipsel-unknown-linux-musl/release/ramips-rs openwrt:/tmp/
-ssh openwrt /tmp/ramips-rs
-# Hello, world!
-```
-
-## Оптимизация размера бинарника
-
-После сборки и запуска "Hello, World" можно обратить внимание, что исполняемый файл весит __4.1 мегабайта__.
-Для устройства с 8 мегабайтами постоянной памяти это катастрофически много.
-
-Уменьшим размер исполняемого файла до приемлемого минимума.
-Для этого настроим release профиль сборки и компиляции проекта.
-Дополним Cargo.toml файл:
-
-```toml
-[profile.release]
-strip = true # Уменьшает бинарник до 383K
-lto = "fat" # Уменьшает бинарник до 334K
-opt-level = "z" # Уменьшает бинарник до 326K
-panic = "abort" # Уменьшает бинарник да 332K
-codegen-units = 1 # Включает дополнительные оптимизации кода
-```
-
-Получаем исполняемый файл размером в __332 килобайта__.
-Далее сжимаем исполняемый файл инструментом upx:
-
-```bash
-upx --best --lzma target/mipsel-unknown-linux-musl/release/ramips-rs
-```
-
-И получаем исходный файл размером в __118 килобайт__.
-Приемлемый результат.
-
-Сильнее уменьшить бинарник можно отказом от стандартной std библиотеки и другими экстремальными unsafe приемами, что не подходит в моем случае.
-
-## "Hello, World!" ver. 2
-
-Теперь сделаем пример посерьезней.
-Например, асинхронный TCP сервер.
-Подключаем зависимости:
-
-```toml
-[dependencies]
-hyper = { version = "1.0.0-rc.3", features = ["full"] }
-tokio = { version = "1", features = ["full"] }
-http-body-util = "0.1.0-rc.2"
-```
-
-Пишем код:
-
-```rust
-use std::convert::Infallible;
-use std::net::SocketAddr;
-
-use http_body_util::Full;
-use hyper::body::Bytes;
-use hyper::server::conn::http1;
-use hyper::service::service_fn;
-use hyper::{Request, Response};
-use tokio::net::TcpListener;
-
-async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
- Ok(Response::new(Full::new(Bytes::from("Hello, World!"))))
-}
-
-#[tokio::main]
-async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
- let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
- let listener = TcpListener::bind(addr).await?;
-
- loop {
- let (stream, _) = listener.accept().await?;
-
- tokio::task::spawn(async move {
- if let Err(err) = http1::Builder::new()
- .serve_connection(stream, service_fn(hello))
- .await
- {
- println!("Error serving connection: {:?}", err);
- }
- });
- }
-}
-```
-
-Проверяем, компилируем и сжимаем.
-Получаем бинарник размером в __236 килобайт__.
-Теперь загружаем в устройство, запускаем и проверяем:
-
-```bash
-scp ./target/mipsel-unknown-linux-musl/release/ramips-rs openwrt:/tmp/
-ssh openwrt /tmp/ramips-rs
-
-curl -L "http://10.0.0.2:3000"
-# Hello, World!
-```
-
-Работает как и задумано.
-
-## Полезные ссылки и источники
-
-- [Building Rust code for my OpenWrt Wi-Fi router](https://blog.dend.ro/building-rust-for-routers/)
-- [Cross Compile Rust For OpenWRT](https://www.kiloleaf.com/posts/cross-compile-rust-for-openwrt/)
-- [Minimizing Rust Binary Size](https://github.com/johnthagen/min-sized-rust)
-- [Кросс-компиляция программ Rust для запуска на маршрутизаторе](https://dzen.ru/media/nuancesprog.ru/krosskompiliaciia-programm-rust-dlia-zapuska-na-marshrutizatore-5f6457b8bdfa745d402cd1ec) \ No newline at end of file