Yocto学习笔记1-下载与首次编译
- 1、基础环境介绍
- 2、注意点
- 3、安装依赖
- 3.1 yocto常规系统构建所需依赖库(较全)
- 3.2 龙芯适配时的最小依赖库(最小)
- 4、下载
- 4.1 通过git克隆
- 4.2 查看所有远程分支
- 4.3 签出一个长期支持的稳定版本
- 4.4 查看当前本地分支版本
- 5、使能编译环境
- 6、开始Yocto编译
- 7、编译中的遇到的问题
- 7.1 在编译bison(版本bison-3.0.4)时遇到gnulib版本不匹配问题
- 7.2 elfutils编译错误
- 7.3 glib编译错误:directive argument is null(2处)
- 7.4 qemu编译报错
1、基础环境介绍
操作系统:ubuntu 20.04
内存大小:12GB
磁盘空间:600GB
2、注意点
yocto poky下载和编译的整个环境(除了运行QMENU虚拟机外)不需要root权限,请尽可能不要在root环境下去操作。
3、安装依赖
3.1 yocto常规系统构建所需依赖库(较全)
sudo apt-get install -y gawk wget git diffstat unzip texinfo gcc build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev zstd liblz4-tool
3.2 龙芯适配时的最小依赖库(最小)
sudo apt-get install -y gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm
4、下载
4.1 通过git克隆
$ git clone git://git.yoctoproject.org/poky
$ cd poky
一般网速较慢,请耐心等待…
4.2 查看所有远程分支
$ git branch -r
执行如下图:
4.3 签出一个长期支持的稳定版本
如果构建针对龙芯的系统,可以签出sumo版本,因为龙芯官方主要是sumo版本的基础上进行构建。
$ git checkout sumo
或者使用完整命令
$ git checkout -t origin/sumo -b my-sumo
执行如下:
4.4 查看当前本地分支版本
$ git branch
5、使能编译环境
先进入poky目录,看一下poky目录下的内容,如下:
在poky目录下执行以下命令
$ source oe-init-build-env
执行结果如下图:
出现提示:
You can also run generated qemu images with a command like ‘runqemu qemux86’
说明使能编译操作成功,首次使能的时候会创建build目录,后面包括编译和输出的所有东西都在这个build目录下,所以build目录下的改动都是临时的,都是会变化的,所以不建议在build目录下去做代码的修改,也无法保存下来,当然也不要怕去修改build目录下的代码,为了快速和临时改动是可以接受的。
在执行 source oe-init-build-env时需要用到python2,且要求版本≥2.7.3,我的环境开始是python2和python3都安装了,默认/usr/bin/python软链接指向python3,就会出现以下错误。
解决此问题的方法, 可以先删除/usr/bin/python软链接,再建立一个指向/usr/bin/python3的软链接就可以了,如下:
6、开始Yocto编译
在build目录下执行以下命令开始编译:
$ bitbake core-image-sato
编译过程如下图:
因为要下载配方中的软件包并进行配置、编译、安装,第一次时间是很长的,需要耐心等待…
7、编译中的遇到的问题
7.1 在编译bison(版本bison-3.0.4)时遇到gnulib版本不匹配问题
问题描述如下:
Please port gnulib fseterr.c to your platform! Look at the definitions of ferror and cleareer on your system, then report this to bug-gnulib.
如下图:
问题分析:
网上查阅后是最新版本gnulib与bison不大兼容,一般正确做法是给要编译的软件包打补丁,包括以下2步。
- 1、补丁下载
补丁下载地址:
https://raw.githubusercontent.com/rdslw/openwrt/e5d47f32131849a69a9267de51a30d6be1f0d0ac/tools/bison/patches/110-glibc-change-work-around.patch
可以新开一个SSH终端,进入到软件包目录下直接通过wget下载,如下:
$ cd ~/Linux/yocto/poky/meta/recipes-devtools/bison/bison
$ wget https://raw.githubusercontent.com/rdslw/openwrt/e5d47f32131849a69a9267de51a30d6be1f0d0ac/tools/bison/patches/110-glibc-change-work-around.patch
下载后如下图:
- 2、把下载的补丁添加到.bb文件中
回到上一级目录,编辑bison_3.0.4.bb文件,添加110-glibc-change-work-around.patch补丁文件。
$ cd ..
$ ls
$ vim bison_3.0.4.bb
修改内容如下:
修改后保存退出,重新执行编译命令:
$ bitbake core-image-sato
7.2 elfutils编译错误
错误描述:
‘__elf64_msize’ specifies less restrictive attribute than its target ‘elf64_fsize’: ‘const’ [-Weeror=missing-attributes]
yocto官方patch可以参考如下:
https://docs.yoctoproject.org/pipermail/yocto/2019-June/045575.html
报错原因为warning被看作error,实质是elf中__elf64_msize变量为const,但是这里使用的时候没有标记,所以需要添加对应属性;
报错信息如下图:
进入到源码libelfP.h所在的目录:
$ cd ~/Linux/yocto/poky/build/tmp/work/x86_64-linux/elfutils-native/0.170-r0/libelf
$ vim libelfP.h
代码修改如下,增加2个__const_attribute__
7.3 glib编译错误:directive argument is null(2处)
错误描述:
…/…/glib-2.54.3/gio/gdbusauth.c:1305:11: error: ‘%’ directive argument is null [-Werror=format-overflow=]
报错信息如下图:
上图错误是在gdbusauth.c的1305行。
上图的错误是在gdbusmessage.c的2700行。
根据提示,%s的值可能为空,所以添加为空判断,如下:
gdbusauth.c修改如下:
首先进入到源码中gdbusauth.c所在的目录,然后编辑:
$ cd ~/Linux/yocto/poky/build/tmp/work/x86_64-linux/glib-2.0-native/1_2.54.3-r0/glib-2.54.3/gio
$ vim gdbusauth.c
gdbusmessage.c修改如下:
首先进入到源码中gdbusauth.c所在的目录,然后编辑:
$ cd ~/Linux/yocto/poky/build/tmp/work/x86_64-linux/glib-2.0-native/1_2.54.3-r0/glib-2.54.3/gio
$ vim gdbusauth.c
7.4 qemu编译报错
可以先通过以下命令查看一下单独编译qemu有那些可执行的任务task:
$ bitbake qemu -c listtasks
单独编译qemu
$ bitbake qemu
可以看到编译报错及警告如下:
1、手动处理方式:按以下思路进行修改:
1. gettid 需要rename 为 sys_gettid
2. stime 更新为 clock_settime
3. ‘SIOCGSTAMP’ undeclaration ,需要导入头文件<linux/sockios.h>
2、补丁处理方式:处理方式,网上能搜索到的的qemu-2.10.0版本补丁可以参考,参考一下补丁可以解决gettid与 ‘SIOCGSTAMP’ undeclaration问题。
由于我的qemu版本是2.11.1,因此下面补丁对应的行数是不太一样的。
--- qemu-2.10.0-clean/linux-user/syscall.c 2020-03-12 18:47:47.898592169 +0100
+++ qemu-2.10.0/linux-user/syscall.c 2020-03-12 19:16:41.563074307 +0100
@@ -34,6 +34,7 @@
#include <sys/resource.h>
#include <sys/swap.h>
#include <linux/capability.h>
+#include <linux/sockios.h> // https://lkml.org/lkml/2019/6/3/988
#include <sched.h>
#include <sys/timex.h>
#ifdef __ia64__
@@ -116,6 +117,8 @@ int __clone2(int (*fn)(void *), void *ch
#include "qemu.h"
+extern unsigned int afl_forksrv_pid;
+
#ifndef CLONE_IO
#define CLONE_IO 0x80000000 /* Clone io context */
#endif
@@ -256,7 +259,9 @@ static type name (type1 arg1,type2 arg2,
#endif
#ifdef __NR_gettid
-_syscall0(int, gettid)
+// taken from https://patchwork.kernel.org/patch/10862231/
+#define __NR_sys_gettid __NR_gettid
+_syscall0(int, sys_gettid)
#else
/* This is a replacement for the host gettid() and must return a host
errno. */
@@ -6219,7 +6224,8 @@ static void *clone_func(void *arg)
cpu = ENV_GET_CPU(env);
thread_cpu = cpu;
ts = (TaskState *)cpu->opaque;
- info->tid = gettid();
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ info->tid = sys_gettid();
task_settid(ts);
if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr);
@@ -6363,9 +6369,11 @@ static int do_fork(CPUArchState *env, un
mapping. We can't repeat the spinlock hack used above because
the child process gets its own copy of the lock. */
if (flags & CLONE_CHILD_SETTID)
- put_user_u32(gettid(), child_tidptr);
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ put_user_u32(sys_gettid(), child_tidptr);
if (flags & CLONE_PARENT_SETTID)
- put_user_u32(gettid(), parent_tidptr);
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ put_user_u32(sys_gettid(), parent_tidptr);
ts = (TaskState *)cpu->opaque;
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
@@ -11402,7 +11410,8 @@ abi_long do_syscall(void *cpu_env, int n
break;
#endif
case TARGET_NR_gettid:
- ret = get_errno(gettid());
+ // taken from https://patchwork.kernel.org/patch/10862231/
+ ret = get_errno(sys_gettid());
break;
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
关于stime的问题,按如下方式修改。
//ret = get_errno(stime(&host_time)); //注释使用stime的这一行,增加下面这一行改为clock_settime(CLOCK_REALTIME, &host_time)
ret = get_errno(clock_settime(CLOCK_REALTIME, &host_time));
修改完这些,qemu-2.11.1就可以编译过去了。