同步: 最近刚来平台, 计划将自己之前在其他当地发的文章搬运 (同步) 过来.
首发日期2024-02-27
, 以下为原文内容.
在 GNU/Linux 体系上运转 Android 应用比较容易 (比方 waydroid), 可是反过来就很麻烦了.
Android 尽管也运用 Linux 内核 (kernel), 可是体系环境和一般的 GNU/Linux 体系 (比方 ArchLinux, Debian, Ubuntu, Fedora, NixOS 等) 具有不可疏忽的明显差异, 所认为 GNU/Linux 编译的二进制可执行文件, 不能拿过来直接运转.
想要在 Android 体系运转这些应用, 有几种不同的办法. 功能最高的办法当然是重新编译, 编译后的二进制文件就能够直接在 Android 运转了, Termux 便是这么做的. 可是, 尽管终究一步很简略, 前面的为 Android 编译, 便是很麻烦乃至很困难的了.
假如能把为 GNU/Linux 编译的二进制文件直接拿来, 不加修改的运转, 在许多情况下会简略容易许多. proot 便是一种这样的技术. proot 通过运用 Linux 内核的 ptrace 功能, 对程序的内核调用 (syscall) 进行翻译, 然后完成一个很薄的兼容层, 功能只有很小的损失 (并不是虚拟机办法).
本文以应用程序 deno 举栗, 介绍在 Android 运转的办法. 本文不只介绍终究成果 (详细的完成计划), 还要点阐明探索的进程, 也便是这个成果是怎么获得的.
相关链接:
- proot-me.github.io/
- github.com/proot-me/pr…
- termux.dev/
- github.com/termux/term…
- wiki.termux.com/wiki/PRoot
- github.com/termux/proo…
- github.com/termux/proo…
- deno.com/
目录
- 1 获取所需文件
- 2 拼装运转环境
- 3 测验
- 4 总结与展望
- 附录 1 proot-distro 简介
1 获取所需文件
本文的目标是构建一个相对独立的, 最小的运转环境. 这个运转环境所需的各种文件, 需求从多个当地分别获取.
-
(1) proot (termux)
首先在手机上装置 Termux: termux.dev/
然后在 Termux 中装置 proot:
> pkg install proot
-
(2) GNU/Linux 体系文件包 (proot-distro)
这个需求从 proot-distro 的发布页面下载: github.com/termux/proo…
下载这个文件:
debian-bookworm-aarch64-pd-v4.7.0.tar.xz
-
(3) deno (aarch64 linux)
这个需求从 deno 的发布页面下载: github.com/denoland/de…
下载这个文件 (v1.41.0):
deno-aarch64-unknown-linux-gnu.zip
2 拼装运转环境
万事俱备, 能够开端拼凑运转环境了 !
-
(1) proot 运转所需文件.
先来看看 proot 软件包都有哪些文件 (在 termux 中操作):
> dpkg -L proot
其间 usr/bin/proot
是 proot 的可执行文件,
usr/libexec/proot/loader
这个也是 proot 的重要组成部分.
再来看看 proot 的依靠库:
> ldd /data/data/com.termux/files/usr/bin/proot
libtalloc.so.2
这个是 proot 运转所需求的库文件, 需求留意.
libc.so
, ld-android.so
, libdl.so
这些库是 Android 体系本身提供的,
不用管.
-
(2) deno 运转所需文件.
把压缩包
deno-aarch64-unknown-linux-gnu.zip
解压之后, 把里面的deno
文件拿出来, 放到 termux 中, 然后:> ldd deno
这儿能够看到一些依靠库文件:
libgcc_s.so.1
, libpthread.so.0
, libm.so.6
, libc.so.6
等.
deno 运用 rust 编程言语开发, 尽管 rust 号称是静态链接, 在终究生成的单个二进制可执行文件中打包一切依靠, 但实际上仍是有少数体系库是动态链接的 (比方 glibc).
把压缩包 debian-bookworm-aarch64-pd-v4.7.0.tar.xz
解压之后,
从里面获取此处所需的库文件.
-
(3) 开端拼装:
> find setup setup setup/proot setup/loader setup/libtalloc.so.2 setup/run.sh setup/setup.sh setup/debian12_aarch64 setup/debian12_aarch64/usr setup/debian12_aarch64/usr/bin setup/debian12_aarch64/usr/bin/env setup/debian12_aarch64/usr/bin/deno setup/debian12_aarch64/usr/lib setup/debian12_aarch64/usr/lib/aarch64-linux-gnu setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1 setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libc.so.6 setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libm.so.6 setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libpthread.so.0 setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libgcc_s.so.1 setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libdl.so.2
这是终究拼装好的运转环境的文件清单, 一切文件放在
setup
目录中. 其间proot
,loader
,libtalloc.so.2
是从 termux 中获取的.usr/bin/deno
是从压缩包deno-aarch64-unknown-linux-gnu.zip
中获取的.debian12_aarch64
目录中的文件是从压缩包debian-bookworm-aarch64-pd-v4.7.0.tar.xz
中获取的.
其间 setup.sh
文件:
#!/system/bin/sh
echo setup.sh $1
#cd $1
chmod +x run.sh
chmod +x proot
chmod +x loader
chmod +x debian12_aarch64/usr/bin/env
chmod +x debian12_aarch64/usr/bin/deno
mkdir -p tmp
mkdir -p debian12_aarch64/tmp
ln -s usr/lib debian12_aarch64/lib
ln -s aarch64-linux-gnu/ld-linux-aarch64.so.1 debian12_aarch64/usr/lib/ld-linux-aarch64.so.1
echo setup ok.
这个脚本用来做一些初始化的事情.
其间 run.sh
文件:
#!/system/bin/sh
export LD_LIBRARY_PATH=$(pwd)
export PROOT_TMP_DIR=$(pwd)/tmp
export PROOT_LOADER=$(pwd)/loader
./proot
--bind=debian12_aarch64/tmp:/dev/shm
--bind=/sys
--bind=/proc/self/fd/2:/dev/stderr
--bind=/proc/self/fd/1:/dev/stdout
--bind=/proc/self/fd/0:/dev/stdin
--bind=/proc/self/fd:/dev/fd
--bind=/proc
--bind=/dev/urandom:/dev/random
--bind=/dev
-L
--kernel-release=6.2.1-PRoot-Distro
--sysvipc
--link2symlink
--kill-on-exit
--cwd=/
--change-id=0:0
--rootfs=debian12_aarch64
/usr/bin/deno "$@"
这个脚本调用 proot 来运转 deno.
3 测验
测验设备: 手机 Android 11 (MIUI 12.5)
运用 USB 数据线连接 PC 和手机:
> adb devices
List of devices attached
643fa0f6 device
然后:
> adb push setup /data/local/tmp
setup/: 13 files pushed, 0 skipped. 62.6 MB/s (94798346 bytes in 1.444s)
> adb shell
raphael:/ $ cd /data/local/tmp/setup
raphael:/data/local/tmp/setup $ ls -l
total 288
drwxrwxr-x 3 shell shell 4096 2024-02-27 21:15 debian12_aarch64
-rw-rw-rw- 1 shell shell 30504 2024-02-26 19:39 libtalloc.so.2
-rw-rw-rw- 1 shell shell 5736 2024-02-27 01:59 loader
-rwxrwxrwx 1 shell shell 213976 2024-02-26 19:39 proot
-rwxrwxrwx 1 shell shell 590 2024-02-27 03:38 run.sh
-rw-rw-rw- 1 shell shell 356 2024-02-27 03:34 setup.sh
raphael:/data/local/tmp/setup $ chmod +x setup.sh
raphael:/data/local/tmp/setup $ ./setup.sh
setup.sh
setup ok.
raphael:/data/local/tmp/setup $ ls -l
total 296
drwxrwxr-x 4 shell shell 4096 2024-02-27 21:16 debian12_aarch64
-rw-rw-rw- 1 shell shell 30504 2024-02-26 19:39 libtalloc.so.2
-rwxrwxrwx 1 shell shell 5736 2024-02-27 01:59 loader
-rwxrwxrwx 1 shell shell 213976 2024-02-26 19:39 proot
-rwxrwxrwx 1 shell shell 590 2024-02-27 03:38 run.sh
-rwxrwxrwx 1 shell shell 356 2024-02-27 03:34 setup.sh
drwxrwxrwx 2 shell shell 4096 2024-02-27 21:16 tmp
raphael:/data/local/tmp/setup $ ./run.sh --version
deno 1.41.0 (release, aarch64-unknown-linux-gnu)
v8 12.1.285.27
typescript 5.3.3
raphael:/data/local/tmp/setup $ ./run.sh repl -A
Deno 1.41.0
exit using ctrl+d, ctrl+c, or close()
> 0.1 + 0.2
0.30000000000000004
>
成功运转了 GNU/Linux (aarch64) 版别的 deno.
4 总结与展望
在 proot, termux, proot-distro 的帮助下, 咱们总算成功在 Android 运转了最新版 deno. 这个小的运转环境是相对独立的, 能够单独拿出来放在一个当地就能运转.
尽管 proot 的作业原理很简略, 这个计划看起来也很简略, 窝之前认为不用费多大功夫就能轻松搞定. 实际上却是这也不可, 那也不可, 这儿有问题, 那里也有问题, 这儿是坑, 那里也是坑 .. . 折腾了好久, 遭遇了许多困难和挫折, 因为太笨气哭了好几次, 擦干眼睛周围的小小水滴之后, 才有了这个终究计划. 好在终究雨后初霁了, 努力没有白搭.
最好的办法仍是重新编译, 然后直接在 Android 运转. 可是为 Android 编译很麻烦乃至很困难的情况下, 本文的办法便是一个好的替代计划.
附录 1 proot-distro 简介
proot-distro 是 termux 团队开发的一个东西, 用来便利的在 Termux 中装置和运转 GNU/Linux 发行版 (比方 debian).
-
(1) 在 termux 中装置 proot-distro:
> pkg install proot-distro
-
(2) 查看有哪些发行版可用:
> proot-distro list
-
(3) 装置一个发行版 (比方 debian):
> proot-distro install debian
-
(4) 发动一个发行版 (比方 debian):
> proot-distro login debian
然后就获得了一个在 Android 运转的 GNU/Linux 体系环境.
假如拿到一个 GNU/Linux 的二进制程序, 首先在这个环境中测验一下, 能不能正常运转. 这是快速验证的办法.
假如能够运转, 那再用本文的办法. 假如不能运转, 那就不用考虑本文了, 早点洗洗睡吧.
本文之中构建的运转环境, 其实便是 proot-distro 的运转环境简化而来.
本文运用 CC-BY-SA 4.0 许可发布.