立创泰山派训练营学习笔记--Linux SDK编译环境搭建与验证(一)
夜魔009
编辑于 2024年03月17日 08:41
收录于文集
共4篇

本来准备录个视频来记录,后来一想,以后万一忘记了不好查。还是写文档吧。并且这个Linux SDK编译,如果没有服务器级别的硬件,速度实在是有些慢。台式机会好一些,自己用的笔记本,Buildroot大概用3个小时左右,Debian用了4个多小时,Ubuntu用了将近5个小时,Android大概是14个小时(编译了一夜,一天)。

、什么是SDK编译,为什么要编译SDK

PC可以安装操作系统,比如Windows、CentOS等等,这些操作系统由于PC的用户量很大,所以通常也做的兼容性很好,通常叫发行版系统,他们的特点就是适应IBM机兼容标准的硬件,和X86架构的cpu为主,通常硬件的设计、制造都很复杂,操作系统也是。

我们拿到立创泰山派这种单片机开发板,首先知道它是RK3566,瑞芯微的RK3566芯片,是ARM架构的就意味着上面说的那些公开发行的操作系统iso安装文件是用不了的,不仅硬件架构不兼容,即使兼容了,驱动层也不兼容。因为公版发行系统,通常它都遵守一些国际规范,比如IBM兼容机标准。

而立创泰山派这种单片机,通常就是尊崇瑞芯微的RK3566芯片使用手册的规范要求,讲硬件、通信总线、存储、外部I/O等进行了设计,这样才能足够小巧和简单,定制性变强了,同时的软件层面要想适配,就得专门针对性编译了。

根据目前查的资料看,编译也是分多层来适配的,比如内核的编译、引导区的编译、rootfs的编译,其实他们兼容和做的事儿都不太一样。boot引导区的编译,主要是为了按芯片厂商的规定,让RK3566能够顺利的加载到引导程序,然后再通过引导程序能顺利装载内核和rootfs。

编译的目的之二,就是架构适应。我们日常生活中接触到的Windows、linux环境,主要都是在X86架构下的,软件层面的工具都是在X86架构编译的,二进制文件通常是X86架构的CPU才能解析执行。为了让这些软件在ARM架构的RK3566上运行,那么就需要使用arm编译器来编译这些软件的源代码,这样出来的二进制机器执行文件,RK3566这类ARM的芯片才能解析执行。这就是编译。

所以编译,就是为了让我们把已经有的软件,能够移植到我们自己的单片机上,这次是RK3566,ARM64位的架构CPU,以后也许会有别的架构,比如RISC-V之类的架构,也许有一天中国也能推出自己的CPU架构体系,到时候就可以往那个架构上去迁移编译。

那么考虑个问题:我们能不能编译移植,Windows到ARM架构平台呢?

答案是,除非你找微软去合作,拿着硬件找他,谈好了商务,否则是没戏的,因为Windows是闭源的,源码不开放。

所以编译移植的条件是:

1、移植的目标是开源的,源代码开放,可以自己选择不同架构的编译器进行编译;

2、移植的目标机构,本身就会根据一些流行的硬件CPU架构,发行编译好的二进制结果文件。这种情况下,通常只是需要复制、安装、修修改改配置文件;

3、MCU或者CPU的制造商,必须提供了相应的编译套件,编译规范或者说明什么的,通常现在大部分的制造商也都有尊崇国际标准,然后编译框架一般都是buildroot之类,比较流行的,有规矩才成方圆,才是大家都能互惠互利,降低成本的方案呗。毕竟如果搞款CPU,各种都特例独行,与现有体系格格不入,学习成本太高,CPU除非显著的低于其它同行十倍甚至百倍的价格,估计才会有企业考虑成本因素去用用。不然肯定要考虑后续软件集成的市场欢迎度。

目前了解的就这么些,欢迎知道更多的网友纠正。

、为什么要搭建编译环境

知道了编译SDK的原因和必要性,以及编译SDK到底在干什么。那么接下来就是要怎么干的问题。编译自然是要搭建编译环境了。就像写C语言程序,需要搞个C语言的编译开发工具。scratch编程,需要安装一套scratch开发工具一样。

只是单片机开发板的编译环境要复杂一些,主要是因为平时我们学软件层面的开发的时候,所讲的编译都是同平台编译,关注的是软件里面实现的逻辑,比如游戏的情节、逻辑、子弹怎么飞出去,怎么判断击中了目标,代码的逻辑有没有问题。这些都是因为有庞大的x86平台基础硬件、操作系统、编译开发工具给我们支撑着底层的一切,我们才能在这些基础之上去只关心代码里的逻辑。

而硬件单片机的这个SDK编译,它关注的方向不同,主要是目标软件的环境异构的适配。就是我们如何在X86的硬件操作系统基座上,编译出来一套ARM芯片架构的操作系统、应用软件,给它装进去。这个就要搭建交叉编译环境,就是在x86系统基座基础上,通过交叉编译工具链(buildroot之类)把已经写好的 bootLoader源码、linux内核()kernel)源码, 编译到目标ARM架构的二进制格式。对一些已经有目标架构编译好的二进制打包软件的linux或者常用的软件通过虚拟化技术(docker容器、qemu、chroot、虚拟机等等)去通过一些文件复制类操作,将这些二进制文件打包成一个可运行的系统安装镜像img,供我们来烧入立创泰山派。

让立创泰山派能够运行它们。

目前了解情况是这样,以后有了更深的理解,再在后续的笔记里深入吧。希望同步了解后续笔记更新状态的,就加个关注~~~

三、VMware中Unbuntu18.04编译SDK文章的修正【重要!!】

这个之前有写过一篇CSDN的笔记,已经发了,这里要注意一下,当时低估了sdk编译的复杂度,在文章里给了错误的建议,建议省事儿直接用root做全部操作。目前看这个是非常糟糕的做法看的时候,请忽略这个建议。

https://blog.csdn.net/supperman_009/article/details/135963726

基于VMware和Unbuntu18.04编译 嘉立创·泰山派 Linux SDK

有关Linux的使用注意事项:

1、需要专门去学习一下linux的使用,这个不难光使用的话无非了解一些基本概念的差异和20来个日常常用命令就会了;小贴士:

        a、Linux的文件系统以 / 为根路径,像一颗树一样管理,用惯了windows的要习惯一下。

        b、Linux的文件系统中,也有分区但与windows的分区概念不太一样。如果启用了lvm卷管理,linux可以动态的伸缩挂载点的存储大小。

        c、操作系统不恐惧,别看到命令行就害怕。无非是window鼠标点一下,一堆图形化回应。而命令行是,你给它一个命令,它给你一些文本信息回应,没什么差别。都是信息交互的方式。另外命令除了下面这些常用的,用多了自然就记住了,一些不常用的命令,大概知道头几个字母,敲完之后可以按tab建补全,在我们进入文件夹,或者运行一些脚本的时候,都能tab键补全。

代码块
Shell
自动换行
复制代码
Linux必须掌握的常用命令,越靠前越重要
tab建命令补全
cd   目录跳转	
ls	  打当前目录文件
mkdir
rm [谨慎,没有回收站]
vi [or vim需熟练掌握]
find
cat
tail
cp
scp
mv
chmod
chown
ps 
sudo
yum
apt
grep
curl
wget
ssh
ftp
sftp
ping
su
awk
sed
nohup
lsof
kill
jps  需安装jdk
top
tcpdum
crontab
sar
top
rz
sz
netstat
ip
systemctl
more
iptables
source
env
echo
touch

管道 操作符 |、>、>>
例如 ps -ewf |grep java

#编写sh脚本,脚本的头,脚本调试参数,循环结构,选择判断结构
#!/bin/bash --login
set -e
set -x 

while()
do
...;
...(if)
done

复制成功

2、非必要不要使用root权限,linux的root用户是很特殊的用户。其用户id是0,对这个系统有非常高的权限。通常只有给系统进行yum安装、apt安装的时候,才必须要使用root权限。所以在以后操作linux的过程中,如无必要,不要轻易用root,sudo。

四、VMware的链接克隆的使用【重要!】

CSDN的基于VMware和Unbuntu18.04编译 嘉立创·泰山派 Linux SDK 这篇文章已经讲过了虚拟机的安装。最初没考虑太多,以为这事儿比较简单,所以直接就在虚机里搞SDK编译起来,结果弄得很狼狈。事实证明低估了这个事情的复杂度了,必须上工程手段。

说一下什么叫工程手段。工程手段就是工程思维模式形成的一种工作模式手段。旨在通过自己了解和已知的工具、知识体系手段,将目标任务拆解成大量子任务,并合适的管理协调,逐个搞定各子任务,从而解决整个工程目标的方式。这个其实是学习过程中,除知识本身,需要锻炼的最容易迁移到其他所有领域的能力。

说的抽象了,举个具体的例子。就我们现在这个事儿。就要用到VMware的链接克隆和快照。

安装虚拟机已经会了,通常我们的电脑都会有SSD固态盘,还有HDD机械硬盘,固态盘很贵,所以空间通常不能放不重要的东西,但放在固态盘的程序跑起来速度会比HDD机械盘快很多。HDD便宜一些,适合存储大量数据。我的笔记本也是这样。

所以工程手段第一步:

在SSD盘,安装一个最小化的Ubuntu18.04【这个版本是瑞芯微RK3566官方支撑的版本,没有做过这方面的编译,首次搞的话,严格按这个版本来!!】,并且创建个文件夹,命名为基础镜像。

vm虚机基础镜像

这个放在SSD的基础镜像,就是为了实验用的Ubuntu虚机,至少操作系统部分是在SSD承载的,运行会快。虚机数据盘设置500G以上,不要勾选预分配空间,反正你不放数据的话,它硬盘文件就只占几MB。

这个vm虚机在安装Ubuntu时:

1、选择最小安装模式;

2、启用lvm卷管理;

3、操作系统分区自动分区就可以;

4、创建好日后要用的普通用户;

5、安装完成后进入系统,给root用户设置密码

      #切换成root

      sudo  su -     

      #修改密码,记得修改完密码,exit 退出root用户状态

      passwd

6、关闭系统自动更新,千万不要升级更新到最新版,不然就变成22.04版本了!!!记住这是复现实验!先把人家旧版的支撑的系统编译搞定,确保sdk文件是对的正常编译的自己心里有底。再去改编译环境!!不要什么都不懂就直接上来挑战人家官方都不支撑的最新版系统的编译环境,因为出了问题,又是小白状态,大佬都要研究个几天,小白你能做什么?

7、apt源修改成国内镜像源,比如浙大的,比较快的zju

代码块
Shell
自动换行
复制代码
#养成好习惯,修改之前先备份
superx@tsp-pc:~$ cp /etc/apt/sources.list /etc/apt/sources.list.bak
#vi修改
superx@tsp-pc:~$ vi /etc/apt/sources.list

#内容如下
superx@tsp-pc:~$ cat /etc/apt/sources.list
#deb cdrom:[Ubuntu 18.04.6 LTS _Bionic Beaver_ - Release amd64 (20210915)]/ bionic main restricted

# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.zju.edu.cn/ubuntu/ bionic main restricted universe multiverse
# deb-src https://mirrors.zju.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.zju.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
# deb-src https://mirrors.zju.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.zju.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
# deb-src https://mirrors.zju.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.zju.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
# deb-src https://mirrors.zju.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
# 预发布软件源,不建议启用
# deb https://mirrors.zju.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
# deb-src https://mirrors.zju.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
复制成功

8、 最小化安装的Ubuntu有几个东西要修改,所谓欲行其事,必先利其器

      

代码块
Shell
自动换行
复制代码
不想找麻烦的话,按顺序来
# 安装VMware tools,这样鼠标复制粘贴就和透传虚机了
sudo apt install open-vm-tools-desktop -y

# 修正vi,Ubuntu默认安装的vi是个社区版的,默认配置贼难用,如果你发现vi进去用这不习惯,退格键不能删文字,方向键按了出来的是转义码,这步一定要做
#卸掉vim-common
sudo apt-get remove vim-common
#装上正式的vim搞定
sudo apt-get install vim


#sudo免密,自己普通用户,每次sudo的时候要输自己的密码,太麻烦了。干脆改成sudo免密
#visudo是个命令,进去以后用法基本和vi一样,Ubuntu的是在下面有一堆提示,^符号对应的是ctrl建,按键操作保存即可,保存的时候把visudoer.tmp改成visudoer,去掉tmp后缀,让修改直接生效。
sudo visudo 

找到root组和admin的记录
把最后的
ALL 
变: 
NOPASSWD:ALL
复制成功

按照CSDN的VMware设置内容,把网络配置的桥接设置设置好

桥接设置

打开虚拟机设置窗口的选项页,把时钟同步设置好

时钟同步设置

这样基础Ubuntu虚机就做好了,关机。以这台虚机为母版机,创建链接克隆主机,这才是我们后面要用的主角。

右键选择我们这台虚拟机,弹出菜单选择 管理-->克隆

克隆模板机

按向导下一页,选择虚拟机中当前状态

克隆源选择

下一页,选择链接克隆【重要!!这样才能借助SSD的系统加速,又享用HDD的大容量,最关键,后面你再创建N个虚机,操作系统也只占这1份空间】

克隆方法 链接克隆

下一页,给自己虚机起个名字,比如tsp_sdk:

新虚拟机的名字

完事之后,为了方便区分,可以创建个工作或者实验文件夹,放这个链接克隆的虚机。此后这个base基础虚机就再不要去动了,只要遇到Ubuntu18.04环境要求的实验,都可以从这个base虚机链接克隆。

比如我克隆之后的vm叫Ubuntu18_04_tsp_linux,如图:

克隆完成的虚机

克隆完成后的虚机,我们可以根据工程需要,把内存调大,把CPU调多,让它性能强一些,满足sdk编译的需要,尤其是Android的时候。

这里为了方便我们文件交互方便,可以在物理机的windows系统的HDD盘,找个空间大一点的地方,创建个共享文件夹。用来Windows和VMware虚机里文件互访。方便以后编译完的文件刷机,或者下载的百度网盘的文件,传入VMware虚机。

设置共享文件夹

这个共享文件夹,有时候Ubuntu不会自己mount,需要手动mount或者修改/etc/fstab来自动挂载。自动挂载点是“/mnt/hgfs”。挂载成功后,如图可以访问到:

挂载成功 设置的共享文件名字会在mnt/hgfs/下看见

就是挂载成功了。如果看不到hgfs是自动挂载没有挂载。就手动挂载一下(前提是机器之前操作的VMware Tools已经安装过)。

代码块
Shell
自动换行
复制代码
#手动挂载
sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other

#自动挂载
#打开/etc/fstab,添加
.host:/    /mnt/hgfs    fuse.vmhgfs-fuse    auto,allow_other    0    0
复制成功

这样虚拟机层面的设置就全部完成了!

五、VMware的快照使用【重要!】

接下来讲VMware最有用的快照功能,这能让我们之后的编译SDK的事情,变的能快速回退。节省很多时间。

如图,顺序点击,就可以进入快照管理器。

快照管理器

为了快照稳定可靠,第一个要点,凡是打快照,一定要vm虚机正常关机后再打,虽然开机状态也可以打快照,但是有时候不稳定,会有问题。关机打的快照最稳定。

快照管理器

打快照的原则,就看工程分解能力了。我们要将自己做的,探索或者重复别人的事情,分解成很多关键步骤。

比如我这个快照就分了很多阶段。

基础系统【无SDK】,就是刚克隆完创建好的初始状态。

然后我的考虑是,反正直接在vm里面编译,或者在vm里拉起docker编译,都得有linux sdk,所以先把linux sdk按照官方文档,放好,repo检出放好。打个快照。

这就是第二个快照。

然后装完docker,开始做实验之前再打快照。从实验到现在的情况看,docker之后快照形成的分支最多。

这样,我们可以在失败,或者觉得有问题的时候,回退到最近的一步。节省调试时间。

具体根据自己的工程分解习惯,折腾吧。

六、docker环境的搭建【已踩过坑均补充在这里】

不想用docker的看这里:

你可以像我一样也用docker环境。也可以直接把dockerfile里的操作在vm里执行一遍,其实环境就好了。这就是用docker先调试的原因。完善了dockerfile,其实初始化过程就是dockerfile里的步骤!!

这里写给不想用docker的,如果你不想用docker。就参考dockerfile里的步骤,把那些库都装了就行了。就是RUN后面的部分:

代码块
Shell
自动换行
复制代码
# 备份apt源列表文件 
cp -a /etc/apt/sources.list /etc/apt/sources.list.bak 

# 将apt源列表中的 http://.*ubuntu.com 替换为 http://repo.huaweicloud.com 
sed -i 's@http://.*ubuntu.com@http://repo.huaweicloud.com@g' /etc/apt/sources.list 

# 更新包列表 
apt update 

# 安装基本的编译工具和依赖 
apt install -y build-essential crossbuild-essential-arm64 \         
bash-completion vim sudo locales time rsync bc python 

# 安装其他依赖包,这里编译android11sdk需要的环境 
apt install -y repo git ssh libssl-dev liblz4-tool lib32stdc++6 \         
expect patchelf chrpath gawk texinfo diffstat binfmt-support \         
qemu-user-static live-build bison flex fakeroot cmake \         
unzip device-tree-compiler python-pip ncurses-dev python-pyelftools \
subversion asciidoc w3m dblatex graphviz python-matplotlib cpio \         
libparse-yapp-perl default-jre patchutils swig expect-dev u-boot-tools 

# 要出电压配置,需要安装这个工具whiptail 
apt install -y bear whiptail 

# 再次更新包列表并安装任何未安装的依赖 
apt update && apt install -y -f 

cd ~ 
复制成功

环境就初始化好了,直接去看第七部分。

希望也搞一套docker环境的看这里:

也可以直接用dockerfile创建容器,然后在容器里编译。

下面讲一下docker环境搭建,和dockerfile构建编译用容器环境:

代码块
Shell
自动换行
复制代码
#安装docker,先把系统默认自带的卸掉
sudo apt-get remove docker docker-engine docker.io containerd runc
#让apt支持https源
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
#添加Docker 的官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 

#添加apt源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list.d/docker.list > /dev/null

#更新源,并安装docker-ce
sudo apt-get update
sudo apt-get install docker-ce

#验证安装
sudo docker -v
复制成功

重启vm虚机后进入Ubuntu18环境中,当前用户可以直接执行docker ps输出信息如下,代表成功。

代码块
Shell
自动换行
复制代码
superx@tsp-pc:/mnt/hgfs$ docker ps
CONTAINER ID   IMAGE            COMMAND       CREATED      STATUS        PORTS     NAMES
复制成功

此时我们还没有启动任何镜像,所以这样显示是正常的。

编辑dockerfile开始准备做docker镜像:

找到自己习惯的工程路径,比如用户目录,或者/app这样的路径。

创建个比如 tsp_sdk_docker文件夹,在里面vi创建个dockerfile文件,注意文件名就叫dockerfile。如图:

dockerfile

内容如下:

代码块
YAML
自动换行
复制代码
# 设置基础镜像为Ubuntu 18.04
FROM ubuntu:18.04

# 设置作者信息,这个邮箱随便填的别当真
MAINTAINER superx "xxxxx@163.com"

# 设置环境变量,用于非交互式安装
ENV DEBIAN_FRONTEND=noninteractive

# 备份源列表文件
RUN cp -a /etc/apt/sources.list /etc/apt/sources.list.bak

# 将源列表中的 http://.*ubuntu.com 替换为 http://repo.huaweicloud.com
RUN sed -i 's@http://.*ubuntu.com@http://repo.huaweicloud.com@g' /etc/apt/sources.list

# 更新包列表
RUN apt update

# 安装基本的编译工具和依赖
RUN apt install -y build-essential crossbuild-essential-arm64 \
        bash-completion vim sudo locales time rsync bc python

# 安装其他依赖包,这里编译android11sdk需要的环境
RUN apt install -y repo git ssh libssl-dev liblz4-tool lib32stdc++6 \
        expect patchelf chrpath gawk texinfo diffstat binfmt-support \
        qemu-user-static live-build bison flex fakeroot cmake \
        unzip device-tree-compiler python-pip ncurses-dev python-pyelftools \
        subversion asciidoc w3m dblatex graphviz python-matplotlib cpio \
        libparse-yapp-perl default-jre patchutils swig expect-dev u-boot-tools

# 要出电压配置,需要安装这个工具whiptail
RUN apt install -y bear whiptail 

# 再次更新包列表并安装任何未安装的依赖
RUN apt update && apt install -y -f

# 生成本地化语言支持
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8

# 创建开发板用户
RUN groupadd -g 1000 lckfb && useradd -c 'lckfb user' -u 1000 -g 1000 -m -d /home/lckfb -s /bin/bash lckfb

# sudo免密登录
RUN sed -i -e '/\%sudo/ c \%sudo ALL=(ALL) NOPASSWD: ALL' /etc/sudoers
RUN usermod -a -G sudo lckfb

USER lckfb
#设置docker工作目录为/home/lckfb
WORKDIR /home/lckfb

ENTRYPOINT ["/bin/bash"]
复制成功

注意看注释,如果你的宿主机系统是老的系统。用户id不是1000,注意要修改这里:

容器普通用户和宿主机普通用户id组id最好保持一致

不会查看用户id和组id? id命令,不跟用户名是当前用户,跟用户名就是指定的用的id信息。你看看你的,用户名和组名叫什么不重要,重要的是容器里最好设置lckfb的uid、gid和外面一样。比如我这个都是1000。

用户的uid和gid

还是给个对应关系吧。就这么对应

这么做的原因是,一会儿我们启动容器的时候,会把本地宿主机的放sdk的文件夹映射到容器里去,linux在记录文件权限的时候,记录的是文件和用户id、组id,以及rwx权限信息。所以保证uid和gid一致,这样我们就可以即在容器里操作sdk文件夹里的文件,也能在宿主机里操作sdk文件夹里的文件。不会为了刷权限而搞的很狼狈。

至此dockerfile环境就准备好了。

接下来通过dockerfile生成镜像,切换到dockerfile所在路径。

代码块
Shell
自动换行
复制代码
#镜像构建,注意最后的那个.点儿别丢了。tsp_sdk_docker是镜像的名字,这个可以随意改,后面运行容器的时候要用到
docker build -t tsp_sdk_docker .
复制成功

构建完成

构建完成

docker images查看一下

镜像列表

如果想要删除做错的docker镜像,节省些硬盘空间

docker rmi  $IMAGE_ID

把你看到的IMAGE_ID列的字符串,替换到命令的$IMAGE_ID部分,就能删掉了。

用镜像启动容器,做编译准备:

source=/app             这里/app是sdk文件存放的路径,会映射到容器里的用户home路径

tsp_linux_sdk_build  是容器实例的名字,与docker build 创建镜像的时候的名字保持一致

-h  lckfb                     是容器实例的host名字,在网络上的名字,类似操作系统里的主机名      

tsp_sdk_docker        是镜像名字

代码块
Shell
自动换行
复制代码
# docker运行
docker run -d --privileged --mount type=bind,source=/app,target=/home/lckfb --name=
复制成功

这些名字可以自己改。以自己的来,没有影响。

这个docker run通常也只需执行这一次,除非容器实例损坏无法修复了,需要重新创建,不然一般不需要再运行。

运行之后,docker ps查看正在运行的容器实例,docker ps -a 可以查看所有容器实例:

正在运行的容器实例

docker常用的操作命令:

代码块
Shell
自动换行
复制代码
# docker ps 查看,容器正在运行。想要进入容器执行这个。tsp_linux_sdk_build这个是容器实例名称
docker exec -it tsp_linux_sdk_build /bin/bash

# docker run过了。关机了。又进来的时候,docker ps没有运行的容器实例。要把之前创建的容器实例运行起来:
docker start tsp_linux_sdk_build

# 活儿干完了,明天再战。容器实例先停掉。或者关机之前,最好先把容器实例正常停止了。这个相当于正常关机
docker stop tsp_linux_sdk_build


# 删除镜像
docker rmi 镜像ID

# 删除容器实例
docker rm 容器实例名,或实例ID【建议放容器实例id】
复制成功

docker环境最最重要的:

宿主机必须安装  qemu-user-static !!!

宿主机必须安装  qemu-user-static !!!

宿主机必须安装  qemu-user-static !!!

代码块
Shell
自动换行
复制代码
#在宿主机里执行,我知道你容器里已经安装过了!但是宿主机里必须也安装!!
sudo apt-get install qemu-user-static
复制成功

宿主机必须安装  qemu-user-static !!!

宿主机必须安装  qemu-user-static !!!

宿主机必须安装  qemu-user-static !!!

重要的事情多说几遍。不然Debian、Ubuntu等只要用了QEMU和chroot,来加工rootfs就会报错,各种EL无法识别啊,文件不存在啊,文件格式不正确啊,文件权限不正确之类。

Debian编译、Ubuntu编译的时候,都用到了qemu虚机,这个东西在docker容器里工作的时候,会借privileged权限的放开,透穿到宿主机里。宿主机里如果没有这个qemu-user-static,会导致编译报错。群里经典的,问的最多的异常就是这个。

Debian的话,异常是从这里抛出来的:./debian/mk-base-debian.sh

抛出异常的脚本

最经典和迷惑性的异常信息:

Failed to run livebuild,please check your network connection.

多么有误导性的提示啊!无数伙伴都载在了这句提示上,以为是网络有问题,或者什么链接不上。写这句提示的哥们,不确定的情况下,把咱脚本名字,路径位置,行号做个提示,说异常在这附近好么?这么误导很伤人。

其实不是网络问题。是cd之后那部分,有个环节去执行了qemu的chroot,导致的报错,异常捕获,归集到这里了。

真正报错的是这个

ERROR: exit code 255 from line 798: VERSION=debug ARCH=$ARCH ./mk-rootfs-$RK_DEBIAN_VERSION.sh

在mk-rootfs的时候,chroot时候发生的。异常信息类似:

注意 QEMU、chroot 的出现

代码块
Shell
自动换行
复制代码
P: Running debootstrap second stage under QEMU 
chroot: failed to run command '/usr/bin/env': Exec format error 
P: Begin unmounting filesystems...
复制成功

在宿主机安装qemu-user-static 后,容器里就正常了。

六、编译SDK

按照官方示例

https://lceda001.feishu.cn/wiki/Da5owUV4dipiqUkZycbcxckinvc

文档又多处讲sdk编译的,可以结合着看。其实我已经结合着都看完了。只要按上面的步骤把环境搞好了,编译就没问题了!主要就是那堆apt安装的包。

第一处文档位置

第二处文档位置

Android代码repo出来需要注意的地方

Android 代码编译前需要再按包以及编译命令

编译验证:

Buildroot进入sdk路径

buildroot

代码块
Shell
自动换行
复制代码
# 编译
./build.sh lunch
选3,泰山派那个

# 看配置对不对
./build.sh -h kernel


#编译环境变量
export RK_ROOTFS_SYSTEM=buildroot

# 只编译模块代码(u-Boot,kernel,Rootfs,Recovery)
./build.sh all         
#电压配置的时候,除了VCCIO4和6选1.8V其他都选3V3

# 需要再执⾏, 进⾏固件打包
./mkfirmware.sh

# 打包生成一体完整的镜像文件
#要先执行./mkfirmware.sh再执行./build.sh updateimg并且确保时间是最新的。
./build.sh updateimg
复制成功

这个一般都比较顺利。

加载板级配置

电压选择

buildroot编译正常完成

rockdev里的分区级镜像

Debian编译验证:

进入sdk路径

代码块
Shell
自动换行
复制代码
# 编译
./build.sh lunch
选3,泰山派那个

# 看配置对不对
./build.sh -h kernel


#编译环境变量
export RK_ROOTFS_SYSTEM=debian

cd debian
sudo dpkg -i ubuntu-build-service/packages/*
sudo apt-get install -f

cd ..

# 编译 debian
./build.sh debian         
#电压配置的时候,除了VCCIO4和6选1.8V其他都选3V3

# 需要再执⾏, 进⾏固件打包
./mkfirmware.sh

复制成功

debian编译的时候,会有一些提示信息

代码块
Shell
自动换行
复制代码
通过chroot进入到虚拟环境部署定制环境时,会有一些系统调用报错,这些报错并不影响命令的正确执行:
qemu: Unsupported syscall: 276 --->mv命令报错
qemu: Unsupported syscall: 439 ---> rpm -ivh报错
qemu: Unsupported syscall: 285 --->cp命令报错
qemu: Unsupported syscall: 439 --->systemctl命令报错
qemu: Unsupported syscall: 291---->ls命令报错
复制成功

Debian编译完成

Debian固件打包完成

Ubuntu 参考手动rootfs的官方文档。

Android编译注意事项:

android编译需要额外再往容器里安装包

代码块
Shell
自动换行
复制代码
sudo apt-get install -y  uuid uuid-dev zlib1g-dev liblz-dev liblzo2-2 liblzo2-dev lzop git-core curl u-boot-tools mtd-utils android-tools-fsutils openjdk-8-jdk device-tree-compiler gdisk m4 libz-dev git gnupg flex bison gperf libsdl1.2-dev libesd-java libwxgtk3.0-dev squashfs-tools build-essential zip curl libncurses5-dev zlib1g-dev pngcrush schedtool libxml2 libxml2-utils xsltproc lzop libc6-dev schedtool g++-multilib lib32z1-dev lib32ncurses5-dev lib32readline-dev gcc-multilib libswitch-perl libssl-dev unzip zip liblz4-tool repo ssh make gcc libssl-dev liblz4-tool vim expect g++ patchelf chrpath gawk texinfo chrpath diffstat binfmt-support qemu-user-static live-build bison flex fakeroot cmake gcc-multilib g++-multilib unzip device-tree-compiler python-pip libncurses5-dev rsync subversion sed make binutils  build-essential  gcc  g++  wget python libncurses5 bzr cvs mercurial patch gzip bzip2 perl tar cpio unzip rsync file bc wget qemu-user-static live-build python3.8 python3.8-dev ssh make gcc libssl-dev liblz4-tool expect g++ patchelf chrpath gawk texinfo chrpath diffstat binfmt-support qemu-user-static live-build bison flex fakeroot cmake gcc-multilib g++-multilib unzip device-tree-compiler ncurses-dev python2.7
复制成功

android的编译命令详细说明

代码块
Shell
自动换行
复制代码
#切换到 u-boot路径
cd u-boot 
# 编译boot
 ./make.sh rk3566
 # 进入内核路径
 cd ../kernel 
 # 清理编译环境
 make clean 
 make distclean
 #编译内核
 make ARCH=arm64 tspi_defconfig rk356x_evb.config android-11.config 
 make ARCH=arm64 tspi-rk3566-user-v10.img -j16
 
 #以上这几步一般都不会有问题,都可以正常生成
 
 #回到Android sdk路径,编译rootfs,如果rootfs编译报错,只需要关注这部分。只需要编译rootfs
 cd .. 
 # 加载环境变量,如果会话没有退出,编译rootfs不需要重新执行这个不分。如果会话窗口退出了,需要重新从这里执行
 source build/envsetup.sh
 # 加载环境信息,和上面env类似,会话窗口不关,不需要重新执行
 lunch rk3566_tspi-userdebug 
 # 清理编译环境,如果编译过程中报错,切会话没有退出,不需要执行这步
 make installclean -j16 
 # 开始编译,16个线程,这个内存大可以调高一些。如果是exit status 137报错,资源原因。只要窗口没退出,只需要重新执行这一步,把J改小。他会断点续编。如果是其他编译错误,要解决了才会继续往下。当然还是执行这个make。
 make -j16 
 # 打包
 ./mkimage.sh
复制成功

android 编译中报错的处理 

exit status 137

这个异常,问AI之后,确定是ninja的编译内存不足导致的。需要降低make jxx的xx数值,再直接编译。

资源不足的报错降低J线程值

机器性能有限,截止笔记当前,Android编译17个小时,98%进度了,刚开始j给了24,4个多小时之后,资源不足报错。J给成2,现在已经13个小时。即将成功……

make j2即将成功

你是不是在想,j24先跑,资源不足退出了。设置成J2跑,把那个大资源的编译通过之后。Ctrl+C中断,然后再搞成J24跑。我试过了,第2次编译就这么干的,结果到后面还有4万个文件的时候,有个编译错误,一直报错,无法过去,不是资源问题,无奈只能全部make clean,重新再编译,就是现在的第三遍。

最后再记录一些信息:

apt安装了一大堆工具包,都是干什么的呢?我想很多人和我一个想法吧。干脆都查了一遍

各工具包的作用

1. build-essential: 包含了编译和构建软件所需的基本工具,例如编译器等。

2. crossbuild-essential-arm64: 适用于 ARM64 架构的交叉编译工具集。

3. bash-completion: 用于增强 Bash shell 的自动补全功能。

4. vim: 文本编辑器,功能强大,适合程序员和系统管理员使用。

5. sudo: 允许特定用户以超级用户的身份运行命令。

6. locales: 用于设置系统的区域和语言环境。

7. time: 用于测量命令执行所需的时间。

8. rsync: 远程数据同步工具。

9. bc: 用于执行任意精度的数学运算。

10. python: Python 解释器。

11. repo: Google 开发的用于管理多个 Git 仓库的工具。

12. git: 分布式版本控制系统。

13. ssh: 安全 Shell 协议。

14. libssl-dev: SSL 加密库的开发文件。

15. liblz4-tool: LZ4 压缩算法的命令行工具。

16. lib32stdc++6: 用于 32 位程序兼容性的 C++ 标准库。

17. expect: 用于自动化交互式任务的工具。

18. patchelf: 用于修改 ELF 可执行文件属性的工具。

19. chrpath: 修改可执行程序中的运行时库路径。

20. gawk: 文本处理工具,类似于 AWK。

21. texinfo: GNU 项目下的文档格式和处理工具。

22. diffstat: 显示 diff 命令输出的统计信息。

23. binfmt-support: Linux 二进制格式支持。

24. qemu-user-static: QEMU 用户模式工具。

25. live-build: 用于创建 Debian Live 系统的工具。

26. bison: 生成语法分析器的工具。

27. flex: 用于生成词法分析器的工具。

28. fakeroot: 用于欺骗程序以为它在以根用户权限下执行。

29. cmake: 跨平台的构建工具。

30. unzip: 解压缩工具。

31. device-tree-compiler: 设备树编译器。

32. python-pip: Python 包管理工具。

33. ncurses-dev: 提供字符终端操作的库。

34. python-pyelftools: 用于处理 ELF 文件的 Python 库。

35. subversion: 版本控制系统。

36. asciidoc: 文本到文档格式转换器。

37. w3m: 文本模式的 Web 浏览器。

38. dblatex: DocBook 文档格式转换工具。

39. graphviz: 图形可视化工具。

40. python-matplotlib: Python 绘图库。

41. cpio: 归档工具。

42. libparse-yapp-perl: YACC 兼容的解析工具库。

43. default-jre: 默认的 Java 运行时环境。

44. patchutils: 用于管理和操作补丁文件的工具集。

45. swig: 生成不同编程语言之间接口的工具。

46. expect-dev: expect 工具的开发文件。

47. u-boot-tools: U-Boot 启动加载程序工具集。

48. bear: 生成编译数据库的工具。

49. whiptail: 创建用户友好的对话框接口的工具。这个必须要装,不装

QEMU(Quick Emulator)是一个开源的虚拟化和仿真软件。它提供了一种在不同的硬件架构之间进行模拟和转换的能力。QEMU可以模拟多个处理器架构(如x86、ARM、MIPS等)和设备,并能够在这些架构之间运行不同的操作系统。

QEMU的用户模式工具是其中的一部分,它允许在主机系统上运行来自不同架构的二进制可执行文件,而无需实际在目标架构上运行。这意味着你可以在一个主机系统上模拟另一个不同的处理器架构,并且能够运行针对该处理器架构编译的程序。 

qemu-user-static 作为 QEMU 的用户模式工具之一,通过提供与目标处理器架构兼容的系统调用接口来模拟目标处理器架构的环境,从而使得可以在主机系统上运行目标架构的可执行文件。

总结起来,QEMU 是一个虚拟化和仿真工具,而 qemu-user-static 则是 QEMU 的一部分,用于在主机系统上模拟并运行来自不同处理器架构的可执行文件。

Android编译环境扩展安装的库

这些工具包在Linux系统中都有各自的作用,以下是它们的一些主要用途:

1. uuid 和 uuid-dev: 用于生成和操作UUID(Universally Unique Identifier)。

2. zlib1g-dev: 用于数据压缩。

3. liblz-dev, liblzo2-2 和 liblzo2-dev: 提供数据压缩和解压缩的库。

4. git-core: 是版本控制系统Git的核心部分。

5. curl: 是一个命令行工具,用于获取或发送数据,支持多种协议。

6. u-boot-tools: 提供用于编译和开发U-Boot的工具。

7. mtd-utils: 提供对MTD(Memory Technology Devices)设备的操作工具。

8. android-tools-fsutils: 提供Android文件系统工具。

9. openjdk-8-jdk: OpenJDK 8 Java开发工具包。

10. device-tree-compiler: 用于编译设备树的工具。

11. gdisk: 用于操作磁盘分区的命令行工具。

12. m4: 是一个宏处理器,用于生成文本。

13. git: 是版本控制系统Git的客户端部分。

14. gnupg: 是GNU Privacy Guard,用于加密和签名电子邮件。

15. flex 和 bison: 用于创建词法分析器和语法分析器。

16. gperf: 是一个完美的哈希函数生成器。

17. libsdl1.2-dev: 是SDL(Simple DirectMedia Layer)的开发库,用于处理音频、键盘、鼠标、操纵杆和图形硬件。

18. libesd-java: ESD (Enlightened Sound Daemon) Java接口。

19. libwxgtk3.0-dev: 是wxWidgets库的GTK+版本的开发库,用于创建跨平台的应用程序。

20. squashfs-tools: 用于创建和管理SquashFS文件系统。

21. build-essential: 包含编译和安装软件所需的基本开发工具。

22. zip 和 unzip: 用于压缩和解压ZIP文件。

23. libncurses5-dev: 是ncurses库的开发版,提供了基于文本的用户界面。

24. pngcrush: 用于优化PNG图像文件的大小。

25. schedtool: 用于分析和改进实时调度行为的工具。

26. libxml2 和 xsltproc: 用于解析和转换XML文档。

27. libc6-dev: 是GNU C库的开发版,提供了POSIX和C标准的功能。

28. schedtool: 用于分析和改进实时调度行为的工具。

29. g++-multilib 和 lib32z1-dev 等: 用于编译和链接32位程序的工具和库。

30. libswitch-perl: Perl模块,用于管理网络交换机的配置。

31. libssl-dev: OpenSSL的开发版,提供了安全通信的加密工具。

32. repo: 是Android源码管理工具。

33. ssh: 是Secure Shell协议的实现,用于远程登录和其他网络服务。

34. make: 自动化编译工具。

35. gcc 和 g++: GNU编译器集合,用于编译C和C++程序。

36. libssl-dev: OpenSSL的开发版,提供了安全通信的加密工具。

37. liblz4-tool: 用于操作LZ4压缩格式的工具。

38. vim: 是一个强大的文本编辑器。

39. expect: 用于自动化控制交互式应用程序。

40. g++: GNU C++编译器。

41. patchelf 和 chrpath: 用于修改可执行文件和共享库的属性。

42. gawk: 是一个编程语言,用于处理文本和数据。

43. texinfo: 用于生成TeX信息文档的工具。

44. diffstat: 显示C程序代码的更改统计信息。

45. binfmt-support: 支持二进制格式的工具。

46. qemu-user-static 和 live-build: 用于模拟不同架构的系统和构建可启动的ISO镜像。

47. bison 和 flex: 用于创建词法分析器和语法分析器。

48. fakeroot: 用于模拟root权限,以便在不具有root权限的情况下构建软件包。

49. cmake: 是一个跨平台的构建工具。

50. gcc-multilib 和 g++-multilib: 用于编译多架构的程序。

51. device-tree-compiler: 用于编译设备树的工具。

52. python-pip: Python的包管理器。

53. libncurses5-dev: 是ncurses库的开发版,提供了基于文本的用户界面。

54. rsync: 用于同步文件和目录。

55. subversion: 是一个版本控制系统。

56. sed: 是一个流编辑器,用于对输入流(或文件)进行基本的文本转换。

57. make 和 binutils: 用于编译和链接程序。

58. build-essential: 包含编译和安装软件所需的基本开发工具。

59. gcc 和 g++: GNU编译器集合,用于编译C和C++程序。

60. wget: 是一个从网络上下载文件的自由软件。

61. python 和 python3.8-dev: Python解释器和开发工具。

62. bc: 是一个任意精度计算器语言。

63. qemu-user-static 和 live-build: 用于模拟不同架构的系统和构建可启动的ISO镜像。

64. bzip2: 是一个数据压缩程序。

65. perl: 是一种高级、通用、解释型、动态的编程语言。

66. tar: 用于打包和解包tar文件。

67. cpio: 用于复制文件和目录。

68. unzip: 用于解压ZIP文件。

69. rsync: 用于同步文件和目录。

70. file: 用于识别文件类型。

71. bc: 是一个任意精度计算器语言。

知道这些包的功能,在编译的时候,如果遇到问题,就可以联想一下,可能和哪个库有关系。这样有助于定位环境原因。目前验证看,sdk的编译,sdk的repo文件都是没什么问题的,只要是Ubuntu18.04的基础环境,编译如果报错通常都是环境问题,检查apt。检查该设置的环境变量设置了没有。

后期还会继续更新Ubuntu和Android的详细信息,以及驱动树等。因为板子收到的迟,所以以为很轻松的sdk编译,结果变得这么复杂,实属意外。这块儿基本快搞定了,该向驱动树,和点屏幕推进了。

和我一样在跟进泰山派学习的人,可以关注我。有什么问题可以留言,或者私信。学习笔记会持续更新。

上面内容有什么对之处,请在评论区指出,谢谢赐教。一起研究立创泰山派吧!

Ubuntu编译成功