Jasper Ji

开口不在舌头上

0%

为Pinephone Pro交叉编译Rust应用程序

主要参考官方的这篇文章cross-compiling,如果是没有动态库的简单Rust程序,基本没有问题。这里我主要使用GTK4的Rust绑定库gtk4-rs,来开发Pinephone Pro的应用程序,这有GTK相关的动态库依赖,所以导致问题比较麻烦。这里先说明一下我对GTK开发完全不熟,另外也对交叉编译不是很懂。

主要是在Linux发行版Manjaro系统上编译的,理论上Ubuntu这些也应该可以的。交叉编译GTK的最大问题,主要是GTK相关动态库的问题。这里面需要了解一些编译链接以及动态库方面的知识,笔者一开始以为自己了解,结果被狠狠的上了一课。建议读一下《高级C/C++编译技术》这本书,补充相关的知识。

库的位置

Pinephone Pro运行的程序属于ARM64的程序,交叉编译时需要安装aarch64-linux-gnu

sudo pacman -S aarch64-linux-gnu

安装完成后,会在系统usr目录下生成aarch64-linux-gnu的目录,在编译时遇到找不到库时,我们就需要将找到的库放置在/usr/aarch64-linux-gnu/lib/下。这里可以使用ld的命令验证是否找到了链接库。

sudo /aarch64-linux-gnu/bin/ld -lgtk-4 --verbose 

添加--verbose参数后可以打印出详细的查找路径,便于Debug,另外这个加上sudo,是因为这边不加的话,即使有库也无法找到,但是加上后就可以。

如何查找库

重点提示下缺失库,一定要找对应平台的库,比如这里我主要找aarch64的,一开始我使用archlinuxarm,查找我需要的库,但发现有些库也没有的,一种是自己编译对应版本的库。另一种就是从已安装的手机系统中找对应的库,因为我之前在PinePhone Pro上有编译成功过同样的程序,所以系统上自然也有了这些依赖库。可以使用ldd查看程序的依赖库。

ldd gtk-rs 

linux-vdso.so.1 (0x0000ffff806d8000)
libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x0000ffff80560000)
libgtk-4.so.1 => /usr/lib/libgtk-4.so.1 (0x0000ffff7fc00000)
libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x0000ffff7fb70000)
libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0x0000ffff7fb10000)
libcairo-gobject.so.2 => /usr/lib/libcairo-gobject.so.2 (0x0000ffff7faf0000)
libcairo.so.2 => /usr/lib/libcairo.so.2 (0x0000ffff7f9a0000)
libgraphene-1.0.so.0 => /usr/lib/libgraphene-1.0.so.0 (0x0000ffff7f970000)
libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x0000ffff7f710000)
libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x0000ffff7f590000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x0000ffff7f560000)
libc.so.6 => /usr/lib/libc.so.6 (0x0000ffff7f3a0000)
libffi.so.8 => /usr/lib/libffi.so.8 (0x0000ffff7f380000)
/lib/ld-linux-aarch64.so.1 => /usr/lib/ld-linux-aarch64.so.1 (0x0000ffff8069f000)
libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x0000ffff7f360000)
libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0x0000ffff7f340000)
libharfbuzz.so.0 => /usr/lib/libharfbuzz.so.0 (0x0000ffff7f210000)
libfribidi.so.0 => /usr/lib/libfribidi.so.0 (0x0000ffff7f1e0000)
libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x0000ffff7f180000)
...

这里会显示详细的库以及库的位置,然后我们就可以使用scp工具把库从手机端拷贝到电脑上。记得换成你自己的IP,比如:

scp manjaro@192.168.1.4:/usr/lib/libicudata.so.72 ./

解决了库的来源问题,还需要解决库的依赖问题,GTK库的依赖相当多,比如你找到了lgtk-4,结果接着给报另外一堆库找不到。这是因为lgtk-4本身又依赖了很多的动态库,这时我们可以使用readelf这个工具查看。

sudo readelf -d libgtk-4.so

 标记        类型                         名称/值
 0x0000000000000001 (NEEDED)             共享库:[libgmodule-2.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libglib-2.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libgobject-2.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libgio-2.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libpangocairo-1.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libharfbuzz.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libcairo.so.2]
 0x0000000000000001 (NEEDED)             共享库:[libfribidi.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libcairo-gobject.so.2]
 0x0000000000000001 (NEEDED)             共享库:[libfontconfig.so.1]
 0x0000000000000001 (NEEDED)             共享库:[libgdk_pixbuf-2.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libepoxy.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libm.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libgraphene-1.0.so.0]
 0x0000000000000001 (NEEDED)             共享库:[libXi.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libX11.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libpangoft2-1.0.so.0]
..

然后我们就从手机系统寻找对应的库,我的程序要主要依赖的是GTK,所以解决了库的问题后,程序就编译通过了,将编译好的成传输到手机后也可以顺利运行。

总结

目前看来交叉编译Pinephone Pro的程序的主要问题是动态库的问题,因为GTK库的庞大,导致问题也变得有点复杂。一开始我在Mac上编译,但因为没有经验的缘故,一时间把这个单一的动态库缺失的问题想的过于复杂了。甚至更换到Ubuntu上编译,但是也失败了,因为并没有认识到问题的根本,完全是瞎猫碰上死老鼠的心态。后来又换成在Manjaro上编译,这里说句题外话,Manjaro的桌面版也是头一次用,但是整个系统对于只是开发发需求的我而言比Ubuntu这种重型的要轻便很多,另外这个系统真的是开发者友好的系统,命令行是非常的人性化。因为库很多,在一次复制过程中直接把系统的依赖库给覆盖掉了,导致系统无法启动,只能重新安装Manjaro系统。

依赖库太多,直接把折腾到临晨3点才搞定。现在看来应该整理使用脚本把所有的库依赖给处理下,比手动的要快吧。想到了之前开发iOS其实也是交叉编译,只不过苹果提供的工具完全让我们忽略了这些复杂性,另外当时记得很少使用动态库,一般是以静态库的形式。