X86上搭建交叉工具链,来给龙芯笔记本编译本地工具链(未完待续)

时间:2021-09-16 13:10:23

故事的背景是,我买了一台龙芯2F的笔记本来装B。

为什么说是装B呢?因为不但操作系统是Linux,而且CPU还是龙芯的。

一般人有这么酷的装备吗?简直是装B大圣啊。

这里一定要申明一点,本人不是IT技术控,只是年幼不懂事选择了不归路,现已是大叔的年龄,无力回头,只能善始善终。

买回来发现,这台笔记本上没法安装软件,因为既没有软件仓库,也没有GCC。真是神作啊。

还好这难不倒执意装B的技术小虾米(还没搞定呢,现在就吹是不是有点自信爆棚了)。

这不,我周末打算自己玩下构建交叉工具链和构建本地工具链。

下面是我从零(点一)开始研究如何搞定着一切的笔记和心得。

啥是工具链?一套组件,用于编译内核和应用程序。组件包含:

binutils: 用于操作二进制文件的实用程序集合。包括ar, as, objdummp, objcopy

gcc: 不解释,看不懂的别继续了,因为这篇文章不适合现在的你看。

glibc: 所有的应用程序都将链接到C库。还有一个流行的适合于嵌入式的精简libc是uclibc。

从头设置交叉工具链是一件很麻烦的任务,它包括:

  • 下载源码
  • 打补丁
  • 配置
  • 编译
  • 设置头文件
  • 安装
  • 等等等

还好这一切现在有很多大管家都能搞定,我打算使用这位管家buildroot。

下面就开始讲解buildroot的配置。

下载buildroot: http://www.buildroot.org/download.html

下载并安装cygwin,具体的自己百度吧,因为我很早以前就装好了,由于惰性使然,这里略过了。

Buildroot里面有一个很好的配置工具,与Linux内核中很类似。

第一步运行配置助手

yueew@FaceMachine /cygdrive/e/FaceProjs/buildroot-2015.05
$make menuconfig

百度里龙芯的细节资料较少,为求准确,

我只好到龙芯官方网站翻http://www.loongson.cn/product_info.php?id=23 ,

龙芯Loongson 2F的指令集(ISA: instruction set architecture,术语满天飞是装B招数之一)是MIPS III。

但是在menu里,Target Architecture里找不到MIPS III,这种老掉牙的架构估计已经被buildroot废弃了。

在百度里用标题搜索title:(mips III) buildroot也没有结果,这时候只能上英文搜索引擎了。

google由于GFW的*经常连不上,所以一般我用yahoo,要求不高,能用就行。

据说配置一下以下地方就可以了。但是配了之后还是没有MIPS III供选择。难道相关代码都删掉了?

Build options -> Show packages that are deprecated or obsolete

这是什么节奏,是龙芯太落伍?还是......?

这里大家可以深刻体会到古人总结的“眼高手低”、“光说不练假把式”等习语是多么地精辟啊!!

周六一上午就在反复查资料整Target Architecture相关配置,还没搞定。

这里也能看出小虾米就是小虾米,虽然没有小白那么白,但是还得继续“衣带渐紧终不悔,为伊消得人憔悴。”。

现代人吃得不差,又长期坐着不动研究技术,能不发福吗?

12点多了,老婆有事不在家,我只能煮面去了,吃完继续。吃完了,继续。

这时候我只能去buildroot官方网站去看每个版本的改动历史,打算找到一个能用的老版本。

http://www.buildroot.org/news.html

http://git.buildroot.net/buildroot/plain/CHANGES?id=2015.05

终于找到相关描述:

2015.02-rc1, Released February 8th, 2015
Architectures: Freescale E5500 and E6500 PowerPC support
added, deprecated MIPS 1/2/3/4 support removed.
最后,我下载了buildroot-2014.11.tar.bz2,这个是能用的最新版本了。

这里要吐槽一下,浏览器默认下载工具咋极慢无比,下了一半竟然停住了,

难道下个这么小的源码也要上迅雷这门高射炮?用迅雷果然较快搞定。匪夷所思。

绝不是在帮迅雷做广告啊,想,但是没机会,迅雷要是给我广告费该多好啊。

也许还有其他很多好的下载工具吧,这里不一一尝试了。

Target Architecture Variant里面终于可以选择MIPS III。

到这里,万里长征才走完了第一步。

问题又来了,虽然MIPS III是64位的,但是也可以运行在32位兼容模式啊。

广东歌手郑源是我喜爱的歌手之一,但是在这里我把酷我停了,因为思路有点乱了,怎么说清楚我现在想的问题呢?

我编出来的编译器或者应用程序的ABI要与龙芯笔记本上现在运行glibc动态库的ABI匹配啊。

ABI不一致的程序没法链接在一起运行,因为寄存器约定不一致,否则要出大乱子的。ABI知识自己百度吧,由于惰性使然,这里略过了。

这里又想到了大名鼎鼎的某本C语言教材,glibc不讲,abi不讲,只局限讲语法本身,我只能呵呵了。

没入门的程序员只知道谈我会什么什么语言,会的多少种多少种语言。

如果没有对计算机体系结构和软件架构的overview,会语言有何用武之地?

于是我在龙芯笔记本上运行which ls,找到系统实用程序ls的路径/bin/ls,然后又执行file /bin/ls。

这样可以看到ls程序(每个命令其实就是一个程序)的执行格式。

yee@Loong:~$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs),
for GNU/Linux 2.6.8, with unknown capability 0xf41 = 0x756e6700, stripped

这里又要分析了,每个字段是什么含义。

这里可以看到,32-bit LSB说明龙芯笔记本上的可执行程序是32位小端的。

因此,Target Architecture选MIPS (little endian),Target Architecture Variant选mips III。

然后是配置Toolchain:

Kernel Headers版本选择2.6.x,这个信息也是从刚才的file命令里看到的。

C library选什么呢?首先要知道龙芯笔记本上用的是哪种libc。这个怎么看呢?

首先,小虾米打算看龙芯笔记本上是否已经有libc相关的头文件。结果没有找到。

这里用了一个小技巧2>/dev/null来关闭标准错误。否则访问很多目录会报权限不够的错误,看着眼花。

yee@Loong:/$ find -name "*stdio.h*" 2>/dev/null
./usr/lib/perl/5.10.0/CORE/nostdio.h

然后百度查到使用ldd命令可以看到程序连接的动态库。通过readelf -d /bin/ls也能看到程序连接的动态库。

yee@Loong:/$ ldd /bin/ls
librt.so.1 => /lib/librt.so.1 (0x2aaec000)
libselinux.so.1 => /lib/libselinux.so.1 (0x2ab08000)
libacl.so.1 => /lib/libacl.so.1 (0x2ab38000)
libc.so.6 => /lib/libc.so.6 (0x2ab50000)
libpthread.so.0 => /lib/libpthread.so.0 (0x2acc8000)
/lib/ld.so.1 (0x2aaa8000)
libdl.so.2 => /lib/libdl.so.2 (0x2acf4000)
libattr.so.1 => /lib/libattr.so.1 (0x2ad08000)
直接在shell下运行libc.so.6可以看到龙芯笔记本用的是glibc,还可以得到libc library版本是2.7。
yee@Loong:/$ /lib/libc.so.6
GNU C Library stable release version 2.7, by Roland McGrath et al.    #这个很重要,因为不同版本的libc头文件定义不一样。
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.3.2.    #这个无所谓,反正编译出来的二进制都符合统一的ABI标准
Compiled on a Linux >>2.6.27.7<< system on 2009-05-31.    #这个应该无所谓,否则与cat /proc/version不一致怎么解释?有待研究
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
Support for some architectures added on, not maintained in glibc core.
BIND-8.2.3-T5B
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

yee@Loong:/$ cat /proc/version

#和编译glibc用的GCC版本不一致,这个无所谓,因为他们之间通信不需要链接,是通过系统调用。
Linux version 2.6.27.1 (huhb@debian) (gcc version 3.4.6) #643 Sun Jan 3 11:38:33 CST 2010 
yee@Loong:/$ file /lib/libc.so.6
/lib/libc.so.6: symbolic link to `libc-2.7.so'
yee@Loong:/$ file /lib/libc-2.7.so
/lib/libc-2.7.so: ELF 32-bit LSB shared object, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, with unknown capability 0xf41 = 0x756e6700, stripped

从这篇文章的一系列命令输出里,我们可以看到好几个不同的Linux版本号和GCC版本号。

剩下的自己去思考哪些要紧,哪些无所谓吧,我还没有这个功力把这里讲透彻。

一旦配置完成,配置工具将产生一个.config文件来存储你的配置。它将被Makefile所使用。

配置完毕后开始编译,这里使用tee命令记录编译日志。

make | tee -a loongson.log

通常,此命令将执行以下步骤:

  • 按照需要下载源文件;
  • 如果使用内部(internal)工具链则,配置、创建和安装交叉编译工具链;如果外部(external)工具链被用到则导入;
  • 创建和安装被选中的目标包;
  • 如果被选择的话,创内核镜像;
  • 如果被选择的话,创建bootloader;
  • 如果选中创建格式,创建根文件系统。

output/build/host-mpc-1.0.2编译通不过,查了一下config.log,貌似是什么动态库找不到。

半夜12点多了,睡了,明早继续。

百度之后的结果是,PATH设置中,buildroot-2013.05/output/host/usr/bin目录和/bin目录中有同名的动态库,

而buildroot-2013.05/output/host/usr/bin在前,gcc就链接到了错误的动态库。

具体修改方案是把buildroot-2014.11\Makefile里面的这一行

BR_PATH = "$(HOST_DIR)/bin:$(HOST_DIR)/sbin:$(HOST_DIR)/usr/bin:$(HOST_DIR)/usr/sbin:$(PATH)"

改为

BR_PATH = "$(PATH):$(HOST_DIR)/bin:$(HOST_DIR)/sbin:$(HOST_DIR)/usr/bin:$(HOST_DIR)/usr/sbin"

网上本来的说法是要改这个文件package\Makefile.in,但是buildroot代码也是不停演化的,

我也是折腾了好一会儿,才找到相应的代码行挪到了buildroot-2014.11\Makefile

搜索技巧也是一门手艺,弄不好搜出海量信息吓死人。这个话题改天再研究总结一下。

好,再次make | tee -a loongson.log,错误消失了。

大清早折腾到现在8:20了,哥饿了,煮麦片吃去了。吃早饭的时候顺便听听第一财经广播,财商是很重要滴。

buildroot下载软件包奇慢,40M的内核头文件我手动下载好放到buildroot-2014.11/dl目录,再执行make | tee -a loongson.log。

编译内核时又遇到问题了,Makefile:1601: *** mixed implicit and normal rules.  Stop.

1601行:/ %/: prepare scripts FORCE
改为 :%/: prepare scripts FORCE

刚编了一会儿,又遇到问题了

scripts/unifdef.c:209:25: error: conflicting types for ‘getline’

百度说修改scripts/unifdef.c把getline改为别的名字例如get_line,共3处的。

后来又遇到一堆编译问题。

然后,配置下载了glibc-2.20.tar.xz,可惜configure阶段提示

GNU libc 2.20 requires kernel header files from Linux 2.6.32 or later to be installed before configuring.

看来glibc-2.19.tar.xz已经是支持Linux 2.6.27.1的最新版本,但是有编译问题。

然后,下载了glibc-2.7.tar.bz2,解压,打包成xz,伪装(重命名)成glibc-2.20.tar.xz,sha256 hash检验通不过。

只要手动解压到output/build/glibc-2.20/,可以configure时还是遇到问题了,真不知道龙芯上原来的glibc是怎么编出来的。

checking sysdep dirs... configure: error: The mipsel is not supported.

从glibc2.17开始才支持mipsel。因此我只有2.17,2.18.2.19这3个版本可用。

eglibc是一个增加了可移植性的glibc分支,最后一个版本是2.19,后面就合并glibc里面了。因此这里我们选择eglibc2.19

这个周末就这样废了,没有时间再取得进展了。至此,一口吃个胖子的期望落空了。

要知道MIPS是第三大CPU架构,软件生态链的完善性还这么差,干点活遇到这么多问题。

以后要慢慢推进了,因为不能每个周末都这么度过吧。陪老婆逛街,健身,做家务,杂事多的很啊。

以后的计划如下,

  • glibc2.19编译问题暂时不打算细看,这么复杂和牛B的代码,仔细研究很伤脑经的。

打算从glibc2.8到glibc2.18一个个试过去,看哪个能编译通过,我就不信那么多版本个个都会遇到编译问题。

然后把编出来的glibc动态库拷到龙芯笔记本上。一个Linux里面,只要设置好相关环境变量,多个glibc是可以共存的,嘿嘿。

  • 然后的目标就是要在buildroot里面编一个龙芯上可运行的gcc,支持的编译语言嘛,至少C语言要支持吧。
  • 龙芯2F的性能有限,目前跑的桌面是QT,我打算替换成LXDE。当然,要自己编译和配置。
  • 玩下内核版本升级?

这里在闲扯几句,写文章总得有点人文味嘛,光扯技术多枯燥。所以我写文章的定位是技术人文类的。

本人之前的领导是双清,牛B得不行。

我有问题想不明白总去问他,后来他跳槽了,我一下子失去了靠山,压力很大,所有问题都要自己扛。

但是经过一段时间的煎熬,我发现自我求索的能力变强了,知识面也渐渐丰富起来,当然,还是小虾米,这是肯定的。

所以,在这世上,学人鱼不如学人渔,靠人不如靠自己啊。

所以,虽然公司里还有些大师,但是我们少去问他们问题,因为我觉得百度(搜狗)和Yahoo才是大师中的大师。