内容

名称

perlandroid - Android 上的 Perl

概要

本文档的前半部分包含使用 Google 提供的二进制文件为 Android 2.0 及更高版本交叉编译 Perl 的说明。后半部分描述了如何使用 Play 商店中提供的工具链之一原生构建 perl。

描述

本文档介绍了在尝试为 Android 构建 Perl 时如何设置主机环境。

交叉编译

这些说明假设主机系统上有一个类 Unix 构建环境;它们已在 Linux 和 OS X 上测试过,可能在 Cygwin 和 MSYS 上也能正常工作。虽然 Google 也为 Windows 提供了 NDK,但这些步骤在 Windows 上无法原生运行,尽管可能可以通过其他方式进行交叉编译。

如果主机系统的架构是 32 位,请记住将下面的 x86_64 更改为 x86。类似地,下面的示例使用 4.8 工具链;如果您想使用更旧或更新的工具链(例如,NDK 第 8 版中包含的 4.4.3 工具链),只需将它们更改为相应的版本即可。

获取 Android 原生开发工具包 (NDK)

您可以从 https://android-docs.cn/tools/sdk/ndk/index.html 下载 NDK。您需要的是普通版本,而不是旧版本。

确定您将要交叉编译的目标架构

有三种可能的选择:arm-linux-androideabi 用于 ARM,mipsel-linux-android 用于 MIPS,以及 x86 用于 x86。截至 2014 年,大多数 Android 设备运行在 ARM 上,因此这通常是一个安全的选择。

有了这两个,您应该添加

$ANDROID_NDK/toolchains/$TARGETARCH-4.8/prebuilt/`uname | tr '[A-Z]' '[a-z]'`-x86_64/bin

到您的 PATH 中,其中 $ANDROID_NDK 是您解压缩 NDK 的位置,$TARGETARCH 是您目标的架构。

设置一个独立的工具链

这将创建一个可供我们稍后在 Configure 中使用的可工作的 sysroot。

$ export ANDROID_TOOLCHAIN=/tmp/my-toolchain-$TARGETARCH
$ export SYSROOT=$ANDROID_TOOLCHAIN/sysroot
$ $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \
        --platform=android-9 \
        --install-dir=$ANDROID_TOOLCHAIN \
        --system=`uname | tr '[A-Z]' '[a-z]'`-x86_64 \
        --toolchain=$TARGETARCH-4.8

adb 还是 ssh?

adb 是 Android 调试桥。就我们而言,它基本上是一种在没有在设备本身安装任何东西的情况下建立与 Android 设备的 ssh 连接的方法,只要设备与主机位于同一个本地网络中,或者通过 USB 连接到主机。

Perl 可以使用 adb 或普通的 ssh 连接进行交叉编译;一般来说,如果您能够使用 USB 端口将设备连接到主机,或者您不想在设备上安装 sshd 应用程序,您可能想要使用 adb,尽管您可能被迫切换到 ssh,如果您的设备没有 root 权限,而且您运气不好——稍后会详细介绍。或者,如果您正在交叉编译到模拟器,您将不得不使用 adb。

adb

要使用 adb,请从 https://android-docs.cn/sdk/index.html 下载 Android SDK。“仅 SDK 工具”版本就足够了——如果您下载了 ADT Bundle,您可以在 $ADT_BUNDLE/sdk/ 中找到 sdk。

$ANDROID_SDK/platform-tools 添加到您的 PATH 中,这应该可以让您访问 adb。您现在需要使用 adb devices 找到您的设备名称,然后通过 -Dtargethost=$DEVICE 将其传递给 Configure。

但是,在调用 Configure 之前,你需要先检查使用 adb 是否可行。因为 Android 没有 /tmp,也不允许在 sdcard 中执行可执行文件,我们需要在设备上找到一个地方让 Configure 放置一些文件,以及让测试运行。如果你的设备已经 root 了,那么你就没问题了。尝试运行以下命令:

$ export TARGETDIR=/mnt/asec/perl
$ adb -s $DEVICE shell "echo sh -c '\"mkdir $TARGETDIR\"' | su --"

这将创建我们需要的目录,你可以继续进行下一步。/mnt/asec 在 Android 中被挂载为 tmpfs,但它只对 root 可访问。

如果你的设备没有 root,你可能仍然有希望。尝试运行以下命令:

$ export TARGETDIR=/data/local/tmp/perl
$ adb -s $DEVICE shell "mkdir $TARGETDIR"

如果命令成功,你可以继续进行下一步,但要注意:你必须在完成后从设备中删除该目录!与 /mnt/asec 不同,/data/local/tmp 可能会在关机后不会被自动垃圾回收

如果以上两种方法都不起作用,那么你就无法使用 adb 交叉编译到你的设备。要么尝试 root 它,要么使用 ssh。

ssh

要使用 ssh,你需要安装并运行一个 sshd 应用并正确设置它。有很多付费和免费的应用可以轻松做到这一点,所以你应该能够在商店里找到一个。请记住,Perl 需要无密码连接,因此请设置一个公钥。

请注意,一些应用会在每次连接时向 stderr 输出垃圾信息,这可能会干扰 Configure。你可能需要修改 Configure 中创建 run-ssh 的部分,使其丢弃 stderr。

由于你使用的是 ssh,你需要向 Configure 传递一些额外的参数:

-Dtargetrun=ssh -Dtargethost=$TARGETHOST -Dtargetuser=$TARGETUSER -Dtargetport=$TARGETPORT

Configure 及其之后

完成以上所有步骤后,你就可以调用 Configure 了。

如果使用 adb,一个“基本”的 Configure 命令行将如下所示:

$ ./Configure -des -Dusedevel -Dusecrosscompile -Dtargetrun=adb \
    -Dcc=$TARGETARCH-gcc   \
    -Dsysroot=$SYSROOT     \
    -Dtargetdir=$TARGETDIR \
    -Dtargethost=$DEVICE

如果使用 ssh,它不会有太大区别——我们只需将 targetrun 更改为 ssh,并传入 targetuser 和 targetport。最终看起来像这样:

$ ./Configure -des -Dusedevel -Dusecrosscompile -Dtargetrun=ssh \
    -Dcc=$TARGETARCH-gcc        \
    -Dsysroot=$SYSROOT          \
    -Dtargetdir=$TARGETDIR      \
    -Dtargethost="$TARGETHOST"  \
    -Dtargetuser=$TARGETUSER    \
    -Dtargetport=$TARGETPORT

现在你就可以运行 makemake test 了!

最后提醒一下,如果你使用的是 adb,make test 可能会看起来卡住了;这是因为它在完成所有测试之前不会输出任何内容。你可以通过登录设备,移动到 $TARGETDIR,并查看 output.stdout 文件来检查其进度。

注意

原生构建

虽然 Google 没有为 Android 提供原生工具链,但您仍然可以从 Play 商店获取一个。

CCTools

您可能可以获得 CCTools 应用程序,它是免费的。请记住,您需要一个完整的工具链;一些应用程序倾向于默认只安装一个精简版本,而没有一些重要的实用程序,比如 ar 或 nm。

一旦您正确设置了工具链,剩下的唯一障碍就是实际找到它在设备中的安装位置。例如,CCTools 将其工具链安装在 /data/data/com.pdaxrom.cctools/root/cctools 中。有了路径,编译 perl 就很简单了

export SYSROOT=<location of the native toolchain>
export LD_LIBRARY_PATH="$SYSROOT/lib:`pwd`:`pwd`/lib:`pwd`/lib/auto:$LD_LIBRARY_PATH"
sh Configure -des -Dsysroot=$SYSROOT -Alibpth="/system/lib /vendor/lib"

Termux

Termux 提供 Android 终端模拟器和 Linux 环境。它预装了一个交叉编译的 perl。

原生编译 perl 5.30 或更高版本应该像这样简单

sh Configure -des -Alibpth="/system/lib /vendor/lib"

这至少在 Android 8.1 (Oreo) 上有效...

作者

Brian Fraser <[email protected]>