目录
前言-
一、裸机编译-
二、常见的交叉编译场景-
1、使用X86 Linux进行交叉编译-
2、使用Qemu和Docker进行仿真-
三、想法–使用性能较强的AArch64设备进行交叉编译
前言
X3在ROS和算法方面开发资料比较丰富的也提供了相应的工具,本系列文章探索脱离TROS外的应用开发,并尝试使用容器减少开发过程中的工作量。
脱离了TROS框架,不得不考虑依赖库与交叉编译过程中繁琐的配置问题。
嵌入式设备的开发中,交叉编译是开发软件不可或缺的过程。由于交叉编译的定义是编译环境与目标环境不同,在提到交叉编译之前先讨论一个特殊情况。编译环境与目标环境相同–裸机编译(本地编译)。-
一、裸机编译
裸机编译是各类开发板、Pi让用户体验demo的常用方式。在PC上直接编译程序并运行运行也属于此类情况。
优点
-
最大的优点无需配置环境,编译结束即可运行或调试
-
可以通过apt直接下载依赖包
以X3 Pi镜像中/app/cdev_demo/rtsp2display[RTSP参考示例]下的Makefile
文件为例:
demo所需的依赖库通常都集成在系统镜像中。
TARGET = rtsp2display
SRC_PATH := $(CURDIR)
SRCS := $(foreach cf, $(SRC_PATH), $(wildcard $(cf)/*.c))
OBJS := $(SRCS:.c=.o)
LDFLAGS := -lspcdev -lavformat -lavcodec -lavutil
.PHONY: all clean
all: ${TARGET}
%.o:%.c
@mkdir -p $(abspath $(dir $@))
$(CC) -o $@ $(INCDIR) -c $<
$(TARGET):$(OBJS)
@mkdir -p $(abspath $(dir $@))
$(CC) -O3 -o $@ $(OBJS) $(LDFLAGS)
clean:
rm -rf ${OBJS} ${TARGET}
在这段文件中:
LDFLAGS
=-l<libname>
:需要链接的库文件,此处没有使用--static
限定符,会链接库文件搜索路径下的.so文件。默认情况下以/lib
、/usr/lib
为搜索路径。
表面上看这个程序只使用了
ffmpeg: libavformat
、libavcodec
、libavutil
hobot-spdev【7.1.7. 编译hobot-xxx软件包】:libspcdev
对编译生成的rtsp2display使用ldd可以看到被链接的.so文件
sunrise@ubuntu:/app/cdev_demo/rtsp2display$ ldd rtsp2display
linux-vdso.so.1 (0x0000007fac89f000)
libspcdev.so => /usr/lib/libspcdev.so (0x0000007fac82f000)
libavformat.so.58 => /lib/aarch64-linux-gnu/libavformat.so.58 (0x0000007fac5b9000)
libavcodec.so.58 => /lib/aarch64-linux-gnu/libavcodec.so.58 (0x0000007fab270000)
libavutil.so.56 => /lib/aarch64-linux-gnu/libavutil.so.56 (0x0000007fab146000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007faafd3000)
/lib/ld-linux-aarch64.so.1 (0x0000007fac86f000)
libdnn.so => /usr/lib/hbbpu/libdnn.so (0x0000007faaab7000)
libhbspdev.so => /usr/lib/libhbspdev.so (0x0000007faaa77000)
libhbmedia.so => /usr/lib/hbmedia/libhbmedia.so (0x0000007faa955000)
libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007faa924000)
libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000007faa73f000)
libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000007faa694000)
libxml2.so.2 => /lib/aarch64-linux-gnu/libxml2.so.2 (0x0000007faa4de000)
libbz2.so.1.0 => /lib/aarch64-linux-gnu/libbz2.so.1.0 (0x0000007faa4bd000)
libgme.so.0 => /lib/aarch64-linux-gnu/libgme.so.0 (0x0000007faa469000)
libopenmpt.so.0 => /lib/aarch64-linux-gnu/libopenmpt.so.0 (0x0000007faa29a000)
libchromaprint.so.1 => /lib/aarch64-linux-gnu/libchromaprint.so.1 (0x0000007faa278000)
libbluray.so.2 => /lib/aarch64-linux-gnu/libbluray.so.2 (0x0000007faa21d000)
libz.so.1 => /lib/aarch64-linux-gnu/libz.so.1 (0x0000007faa1f3000)
libgnutls.so.30 => /lib/aarch64-linux-gnu/libgnutls.so.30 (0x0000007faa003000)
libssh-gcrypt.so.4 => /lib/aarch64-linux-gnu/libssh-gcrypt.so.4 (0x0000007fa9f6c000)
libdl.so.2 => /lib/aarch64-linux-gnu/libdl.so.2 (0x0000007fa9f58000)
libswresample.so.3 => /lib/aarch64-linux-gnu/libswresample.so.3 (0x0000007fa9f30000)
libvpx.so.6 => /lib/aarch64-linux-gnu/libvpx.so.6 (0x0000007fa9d5e000)
libwebpmux.so.3 => /lib/aarch64-linux-gnu/libwebpmux.so.3 (0x0000007fa9d45000)
libwebp.so.6 => /lib/aarch64-linux-gnu/libwebp.so.6 (0x0000007fa9ce4000)
liblzma.so.5 => /lib/aarch64-linux-gnu/liblzma.so.5 (0x0000007fa9cb0000)
librsvg-2.so.2 => /lib/aarch64-linux-gnu/librsvg-2.so.2 (0x0000007fa9484000)
libgobject-2.0.so.0 => /lib/aarch64-linux-gnu/libgobject-2.0.so.0 (0x0000007fa9412000)
libglib-2.0.so.0 => /lib/aarch64-linux-gnu/libglib-2.0.so.0 (0x0000007fa92d8000)
libcairo.so.2 => /lib/aarch64-linux-gnu/libcairo.so.2 (0x0000007fa91ba000)
libzvbi.so.0 => /lib/aarch64-linux-gnu/libzvbi.so.0 (0x0000007fa9122000)
libsnappy.so.1 => /lib/aarch64-linux-gnu/libsnappy.so.1 (0x0000007fa9109000)
libaom.so.0 => /lib/aarch64-linux-gnu/libaom.so.0 (0x0000007fa8df7000)
libcodec2.so.0.9 => /lib/aarch64-linux-gnu/libcodec2.so.0.9 (0x0000007fa800c000)
libgsm.so.1 => /lib/aarch64-linux-gnu/libgsm.so.1 (0x0000007fa7ff1000)
libmp3lame.so.0 => /lib/aarch64-linux-gnu/libmp3lame.so.0 (0x0000007fa7f71000)
libopenjp2.so.7 => /lib/aarch64-linux-gnu/libopenjp2.so.7 (0x0000007fa7f11000)
libopus.so.0 => /lib/aarch64-linux-gnu/libopus.so.0 (0x0000007fa7eb0000)
libshine.so.3 => /lib/aarch64-linux-gnu/libshine.so.3 (0x0000007fa7e96000)
libspeex.so.1 => /lib/aarch64-linux-gnu/libspeex.so.1 (0x0000007fa7e6e000)
libtheoraenc.so.1 => /lib/aarch64-linux-gnu/libtheoraenc.so.1 (0x0000007fa7e2d000)
libtheoradec.so.1 => /lib/aarch64-linux-gnu/libtheoradec.so.1 (0x0000007fa7e02000)
libtwolame.so.0 => /lib/aarch64-linux-gnu/libtwolame.so.0 (0x0000007fa7dd0000)
libvorbis.so.0 => /lib/aarch64-linux-gnu/libvorbis.so.0 (0x0000007fa7d97000)
libvorbisenc.so.2 => /lib/aarch64-linux-gnu/libvorbisenc.so.2 (0x0000007fa7ce7000)
libwavpack.so.1 => /lib/aarch64-linux-gnu/libwavpack.so.1 (0x0000007fa7cb2000)
libx264.so.155 => /lib/aarch64-linux-gnu/libx264.so.155 (0x0000007fa7a60000)
libx265.so.179 => /lib/aarch64-linux-gnu/libx265.so.179 (0x0000007fa77a1000)
libxvidcore.so.4 => /lib/aarch64-linux-gnu/libxvidcore.so.4 (0x0000007fa76b0000)
libva.so.2 => /lib/aarch64-linux-gnu/libva.so.2 (0x0000007fa767a000)
libva-drm.so.2 => /lib/aarch64-linux-gnu/libva-drm.so.2 (0x0000007fa7667000)
libva-x11.so.2 => /lib/aarch64-linux-gnu/libva-x11.so.2 (0x0000007fa7651000)
libvdpau.so.1 => /lib/aarch64-linux-gnu/libvdpau.so.1 (0x0000007fa763b000)
libX11.so.6 => /lib/aarch64-linux-gnu/libX11.so.6 (0x0000007fa74f6000)
libdrm.so.2 => /lib/aarch64-linux-gnu/libdrm.so.2 (0x0000007fa74d2000)
libOpenCL.so.1 => /lib/aarch64-linux-gnu/libOpenCL.so.1 (0x0000007fa74b9000)
libcnn_intf.so.1 => /usr/lib/hbbpu/libcnn_intf.so.1 (0x0000007fa748d000)
libhbrt_bernoulli_aarch64.so => /usr/lib/hbbpu/libhbrt_bernoulli_aarch64.so (0x0000007fa71bb000)
libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000007fa7197000)
libisp.so => /usr/lib/hbmedia/libisp.so (0x0000007fa716f000)
libiar.so => /usr/lib/hbmedia/libiar.so (0x0000007fa7141000)
libtinyalsa.so => /lib/aarch64-linux-gnu/libtinyalsa.so (0x0000007fa7129000)
libalog.so => /usr/lib/libalog.so (0x0000007fa7111000)
libcam.so => /usr/lib/libcam.so (0x0000007fa70bf000)
libvio.so => /usr/lib/hbmedia/libvio.so (0x0000007fa6f6d000)
libmultimedia.so => /usr/lib/hbmedia/libmultimedia.so (0x0000007fa600b000)
libion.so => /usr/lib/libion.so (0x0000007fa5ff8000)
libicuuc.so.66 => /lib/aarch64-linux-gnu/libicuuc.so.66 (0x0000007fa5e0b000)
libmpg123.so.0 => /lib/aarch64-linux-gnu/libmpg123.so.0 (0x0000007fa5da9000)
libvorbisfile.so.3 => /lib/aarch64-linux-gnu/libvorbisfile.so.3 (0x0000007fa5d90000)
libfontconfig.so.1 => /lib/aarch64-linux-gnu/libfontconfig.so.1 (0x0000007fa5d3b000)
libfreetype.so.6 => /lib/aarch64-linux-gnu/libfreetype.so.6 (0x0000007fa5c7c000)
libp11-kit.so.0 => /lib/aarch64-linux-gnu/libp11-kit.so.0 (0x0000007fa5b30000)
libidn2.so.0 => /lib/aarch64-linux-gnu/libidn2.so.0 (0x0000007fa5b00000)
libunistring.so.2 => /lib/aarch64-linux-gnu/libunistring.so.2 (0x0000007fa5977000)
libtasn1.so.6 => /lib/aarch64-linux-gnu/libtasn1.so.6 (0x0000007fa5954000)
libnettle.so.7 => /lib/aarch64-linux-gnu/libnettle.so.7 (0x0000007fa590e000)
libhogweed.so.5 => /lib/aarch64-linux-gnu/libhogweed.so.5 (0x0000007fa58c8000)
libgmp.so.10 => /lib/aarch64-linux-gnu/libgmp.so.10 (0x0000007fa5840000)
libgcrypt.so.20 => /lib/aarch64-linux-gnu/libgcrypt.so.20 (0x0000007fa5772000)
libgpg-error.so.0 => /lib/aarch64-linux-gnu/libgpg-error.so.0 (0x0000007fa5742000)
libgssapi_krb5.so.2 => /lib/aarch64-linux-gnu/libgssapi_krb5.so.2 (0x0000007fa56ea000)
libsoxr.so.0 => /lib/aarch64-linux-gnu/libsoxr.so.0 (0x0000007fa5684000)
libcairo-gobject.so.2 => /lib/aarch64-linux-gnu/libcairo-gobject.so.2 (0x0000007fa566a000)
libgdk_pixbuf-2.0.so.0 => /lib/aarch64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x0000007fa5633000)
libgio-2.0.so.0 => /lib/aarch64-linux-gnu/libgio-2.0.so.0 (0x0000007fa5436000)
libpangocairo-1.0.so.0 => /lib/aarch64-linux-gnu/libpangocairo-1.0.so.0 (0x0000007fa5418000)
libpango-1.0.so.0 => /lib/aarch64-linux-gnu/libpango-1.0.so.0 (0x0000007fa53bc000)
libffi.so.7 => /lib/aarch64-linux-gnu/libffi.so.7 (0x0000007fa53a3000)
libpcre.so.3 => /lib/aarch64-linux-gnu/libpcre.so.3 (0x0000007fa532f000)
libpixman-1.so.0 => /lib/aarch64-linux-gnu/libpixman-1.so.0 (0x0000007fa52c0000)
libpng16.so.16 => /lib/aarch64-linux-gnu/libpng16.so.16 (0x0000007fa527c000)
libxcb-shm.so.0 => /lib/aarch64-linux-gnu/libxcb-shm.so.0 (0x0000007fa5269000)
libxcb.so.1 => /lib/aarch64-linux-gnu/libxcb.so.1 (0x0000007fa5232000)
libxcb-render.so.0 => /lib/aarch64-linux-gnu/libxcb-render.so.0 (0x0000007fa5214000)
libXrender.so.1 => /lib/aarch64-linux-gnu/libXrender.so.1 (0x0000007fa51f9000)
libXext.so.6 => /lib/aarch64-linux-gnu/libXext.so.6 (0x0000007fa51d6000)
libogg.so.0 => /lib/aarch64-linux-gnu/libogg.so.0 (0x0000007fa51bc000)
libnuma.so.1 => /lib/aarch64-linux-gnu/libnuma.so.1 (0x0000007fa519d000)
libXfixes.so.3 => /lib/aarch64-linux-gnu/libXfixes.so.3 (0x0000007fa5185000)
librt.so.1 => /lib/aarch64-linux-gnu/librt.so.1 (0x0000007fa516d000)
libhbmem.so => /usr/lib/libhbmem.so (0x0000007fa5137000)
libcjson.so.1 => /lib/aarch64-linux-gnu/libcjson.so.1 (0x0000007fa511f000)
libdiag.so => /usr/lib/libdiag.so (0x0000007fa510c000)
libgdcbin.so => /usr/lib/libgdcbin.so (0x0000007fa50ea000)
libicudata.so.66 => /lib/aarch64-linux-gnu/libicudata.so.66 (0x0000007fa361b000)
libexpat.so.1 => /lib/aarch64-linux-gnu/libexpat.so.1 (0x0000007fa35e4000)
libuuid.so.1 => /lib/aarch64-linux-gnu/libuuid.so.1 (0x0000007fa35cd000)
libkrb5.so.3 => /lib/aarch64-linux-gnu/libkrb5.so.3 (0x0000007fa34e5000)
libk5crypto.so.3 => /lib/aarch64-linux-gnu/libk5crypto.so.3 (0x0000007fa34a8000)
libcom_err.so.2 => /lib/aarch64-linux-gnu/libcom_err.so.2 (0x0000007fa3494000)
libkrb5support.so.0 => /lib/aarch64-linux-gnu/libkrb5support.so.0 (0x0000007fa3477000)
libgomp.so.1 => /lib/aarch64-linux-gnu/libgomp.so.1 (0x0000007fa3429000)
libgmodule-2.0.so.0 => /lib/aarch64-linux-gnu/libgmodule-2.0.so.0 (0x0000007fa3413000)
libmount.so.1 => /lib/aarch64-linux-gnu/libmount.so.1 (0x0000007fa33a5000)
libselinux.so.1 => /lib/aarch64-linux-gnu/libselinux.so.1 (0x0000007fa336d000)
libresolv.so.2 => /lib/aarch64-linux-gnu/libresolv.so.2 (0x0000007fa3347000)
libpangoft2-1.0.so.0 => /lib/aarch64-linux-gnu/libpangoft2-1.0.so.0 (0x0000007fa3322000)
libfribidi.so.0 => /lib/aarch64-linux-gnu/libfribidi.so.0 (0x0000007fa32f5000)
libthai.so.0 => /lib/aarch64-linux-gnu/libthai.so.0 (0x0000007fa32dc000)
libharfbuzz.so.0 => /lib/aarch64-linux-gnu/libharfbuzz.so.0 (0x0000007fa31dd000)
libXau.so.6 => /lib/aarch64-linux-gnu/libXau.so.6 (0x0000007fa31c9000)
libXdmcp.so.6 => /lib/aarch64-linux-gnu/libXdmcp.so.6 (0x0000007fa31b3000)
libkeyutils.so.1 => /lib/aarch64-linux-gnu/libkeyutils.so.1 (0x0000007fa319c000)
libblkid.so.1 => /lib/aarch64-linux-gnu/libblkid.so.1 (0x0000007fa3135000)
libpcre2-8.so.0 => /lib/aarch64-linux-gnu/libpcre2-8.so.0 (0x0000007fa30a7000)
libdatrie.so.1 => /lib/aarch64-linux-gnu/libdatrie.so.1 (0x0000007fa308f000)
libgraphite2.so.3 => /lib/aarch64-linux-gnu/libgraphite2.so.3 (0x0000007fa305d000)
libbsd.so.0 => /lib/aarch64-linux-gnu/libbsd.so.0 (0x0000007fa3034000)
各debian包说明和关系如下所示:
包名称
内容说明或示例
hobot-sp-samples_xxx.deb
多媒体和算法的示例代码:包含vio的视频拉流和显示输出、编解码示例,图像分类、目标检测、分割等参考算法的示例
hobot-io-samples_xxx.deb
40Pin接口的使用示例代码:40Pin的Python语言的使用示例
hobot-spdev_xxx.deb
多媒体和算法的C/C++接口的封装库和头文件多媒体和算法的Python接口的封装库和头文件
hobot-multimedia-dev_xxx.deb
底层多媒体头文件
hobot-multimedia_xxx.deb
多媒体运行库文件:所有多媒体相关组件的运行库 so 文件,配置文件,固件等。
hobot-multimedia-samples_xxx.deb
基于底层多媒体接口的参考示例
hobot-camera_xxx.deb
适配的camera sensor的驱动和isp参数库
hobot-dnn_xxx.deb
所有与算法相关的 运行库和头文件
hobot-io_xxx.deb
40Pin管脚使用的接口和头文件(Python语言实现)
hobot-configs_xxx.deb
地平线的自定义系统配置内容:udev配置、apt source配置、网络、蓝牙、usb配置、自启动项配置等
hobot-utils_xxx.deb
地平线官方提供的常用命令集
hobot-display_xxx.deb
图像显示相关,Hdmi、LCD显示的配置
hobot-wifi_xxx.deb
Wi-Fi 和蓝牙模块的配置
hobot-kernel-headers_xxx.deb
内核编译后的配置文件和头文件,用于支持用户单独编译内核驱动
hobot-boot_xxx.deb
内核镜像文件Image和驱动模块文件
hobot-bpu-driver_xxx.deb
bpu驱动
hobot-dtb_xxx.deb
内核设备树
与这些数量庞大.so有关的软件包是X3镜像包中重要的组成部分,算法、多媒体、外设功能的实现与之相关。这些软件包可以通过apt源得到,裸机编译只需要确保这些软件包存在然后make即可。
缺点
-
大多数情况下目标平台的性能较低,裸板编译开发体验不佳
Cortex-A53的性能较低,编译时间长。
编译生成大量中间文件也会受到SD卡IO性能的影响。
有限的内存容量限制了远程开发工具的使用,例如Jetbrain 在arm上的代理至少需要4Gb Ram
X3PI与交叉编译主机的性能对比(编译速度差距可以参考Clang单核得分);
- 除了调试之外还需要占用一个硬件进行程序开发
二、常见的交叉编译场景
Arm平台早期并没有足够编译代码所需的算力和相关空间。不得不借助性能更高的平台来辅助进行编译,使arm平台仅负责运行程序。
交叉编译通常会面对两个比较大的问题:架构(ARCH)和软件环境不同;
架构:通过交叉编译工具链生成能够在目标平台上运行的二进制程序。
软件环境:不同架构的二进制软件包是不能链接的,glibc版本不同的依赖也不能随意链接
1、使用X86 Linux进行交叉编译
最常见的交叉编译场景是在PC的Linux环境下进行交叉编译,X3PI的交叉编译环境配置可以参考RDK套件手册7.1. 开发环境搭建及编译说明
优点
- PC能够提供足够的性能,交叉编译工具链构建速度与同代编译工具基本相同
- 开发调试工具丰富,远程调试需要在目标板上进行一些配置
缺点
-
需要进行额外的配置(环境变量、编译参数),大部分问题出现在这个阶段
-
架构不同导致使用依赖库比较麻烦
Linux自带的包管理器在裸机环境下能以比较轻松的方式管理软件包。然而交叉编译Arm架构的程序不能直接链接X86平台的二进制库。这种情况下:
程序包的体积比较小,可以获取源代码和程序一起编译[TinyXML2]
先对软件包进行交叉编译,作为库引入[QT、FFmepg、OpenCV]
从X3的根文件系统中提取[sysroot_docker]
从X3的软件源中下载deb包用
dpkg-deb -x
提取文件这些方法在易用性上不如直接使用系统自带的包管理器。
-
维护工作量较大
hobot等镜像中集成的软件包更新频繁,更新之后需要再次提取:
如果需要使用hobot多媒体组件、不幸需要使用封装层的hobot-spdev,意味着这种方法无法回避一项工作:
想办法提取需要的库文件,并维护一个依赖仓库。
2、使用Qemu和Docker进行仿真
Qemu可以对指令进行翻译,可以在X86设备上模拟其他架构的指令(此处是AArch64)。用Chroot挂载Arm设备rootfs时就会用到qemu-static
这个工具。
Docker能够很好地将应用程序环境隔离开来,隔离环境一直以来都是容器的强项。如果把X3的根文件系统制作成Docker镜像,这个镜像在系统与软件环境上和物理设备基本一致。
论坛问题帖中这个开发环境出现的次数比较少:
在ai模块arm64 docker内部编译成功,但是在J5上运行提示失败
注意:镜像自带的gcc9.3与交叉编译工具链一致,但软件源仓库中有gcc的9.4版本
优点
- 环境接近裸机开发,部署面临的风险较小
- 获取软件包方便,对于X86的CI主机而言不需要额外配置
缺点
- Qemu指令仿真的性能损失极大,单核情况下实际编译效率低于裸机
对于Armv7平台Qemu带来的损失尚可容忍,但基准测试结果显示模拟Armv8的编译效率很可能低于直接使用裸机设备。
X86 Qemu for Hobot X3 PI(AARCH64) vs Hobot X3 PI - Geekbench
COS电炉的构建主机(205W模拟20W):
三、想法–使用性能较强的AArch64设备进行交叉编译
Qemu仿真已经很接近裸机环境,最大的问题还是在性能上。但AArch64是一个性能差距很长的架构,从A53/A57到高性能的M2同属于AArch64只是微架构不同。
这种微小的架构差异对于一个基于A53制作的Docker容器来说无关紧要。这种开发方式能带来什么?
优点
- 与Qemu仿真类似,开发环境接近裸机
- 高性能Armv8平台在构建速度上与X86的差距在可以接受的范围
缺点
- 还需要一个的高性能的AArch64设备用于托管容器,可能需要进行部分环境配置
下一篇文章将尝试制作X3 根文件系统的docker镜像