[X3容器应用开发探索-0]开篇:从裸机编译到交叉编译

目录

前言-
一、裸机编译-
二、常见的交叉编译场景-
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: libavformatlibavcodeclibavutil

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]

    先对软件包进行交叉编译,作为库引入[QTFFmepgOpenCV]

    从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的编译效率很可能低于直接使用裸机设备。

Qemu转译Armv8-a的性能损失

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镜像

老哥牛哇,这个帖子很有含金量。不过还是建议官方维护一个二进制仓库,能让基于X86 Linux开发的同学用的顺畅。