有了交叉编译环境,下一步就能在我的路由器和光猫上搞更多的事情了。我的目标是编译出能够在路由器上运行的二进制程序。
什么是交叉编译?
我们常用的路由器、光猫、电视盒等等都运行着一个系统,它们也像我们的电脑一样,通俗点的说是盒子系统吧,在盒子系统之上又运行着各种功能的软件(APP),比如路由器上的一些小软件,电视盒上的当贝等,给这些盒子装系统就叫作刷固件。其实这些盒子运行的系统就是裁剪过的linux系统,也叫作嵌入式操作系统。嵌入式linux系统是专门为一些硬件性能不高,并且要实现的功能相对单一的设备而定制的,比较常见的嵌入式linux有ARM架构的,MIPS架构的等。
拿C语言来说,程序员开发出来的程序在不同的硬件架构的机器上只要重新编译安装一下就能运行了,而源代码几乎不用改。然而程序的编译是一个很耗资源的过程,不仅需要运算更快的CPU,还需要大的内存,大的硬盘,快的网速,一些大型的软件即便是在配置很高的工作站上来编译也需要很长时间,如果把程序的编译工作放在电视盒上几乎是不可能的,另外程序只需要在第一次运行时进行编译,编译好的程序以后直接运行就可以了,因此如果把电视盒路由器等嵌入式设备的硬件搞的非常的高档,能够像工作站一样编译程序,仅仅是为了第一次的编译是不是太浪费了呢?
于是交叉编译就来了。把编译工作放在高性能的工作站上,利用工作站强劲的软硬件资源将源代码编译生成目标机器(路由器、光猫、电视盒等)能够运行的二进制可执行文件,然后将这些二进制文件上传(复制、烧录)到嵌入式的盒子系统上,程序就能愉快的运行了。
vim
相信每名程序员都不陌生,在我们的盒子系统中大多集成的是vi
,于是我决定自己编译生成一个能够在盒子上运行的vim
程序。
说干就干,有了前面配置交叉编译的基础那么我们基础的编译环境就具备了。打开github
查找vim
的相关信息,果然在他们的官方的readme
文档中有如下的描述。
INSTALLx.txt - cross-compiling Vim on Unix
Content:
1. Introduction
2. Necessary arguments for "configure"
3. Necessary environment variables for "configure"
4. Example
1. INTRODUCTION
===============
This document discusses cross-compiling VIM on Unix-like systems. We assume
you are already familiar with cross-compiling and have a working cross-compile
environment with at least the following components:
* a cross-compiler
* a libc to link against
* ncurses library to link against
//以下省略
// 原文地址 https://github.com/vim/vim/blob/master/src/INSTALLx.txt
在文末还给出了一个示例
4. EXAMPLE:
===========
Assuming the target system string is "armeb-xscale-linux-gnu" (a Intel XScale
system) with glibc and ncurses, the call to configure would look like this:
ac_cv_sizeof_int=4 \
vim_cv_getcwd_broken=no \
vim_cv_memmove_handles_overlap=yes \
vim_cv_stat_ignores_slash=yes \
vim_cv_tgetent=zero \
vim_cv_terminfo=yes \
vim_cv_toupper_broken=no \
./configure \
--build=i586-linux \
--host=armeb-xscale-linux-gnu \
--target=armeb-xscale-linux-gnu \
--with-tlib=ncurses
so easy!我心中暗想,原来如此简单,可哪知这才是噩梦的开始。
直接从github
上拉取源代码,将代码拉到/home
目录下我的家目录是/home/alfiy
,使用git clone git://github.com/vim/vim.git
替换git clone https://github.com/vim/vim.git
,据说速度能快一些
cd /home/alfiy/Downloads
git clone git://github.com/vim/vim.git
cd vim
认真研究github
上的文档。
其中特别需要注意的是以下几点
--build=... :
The build system (i.e. the platform name of the system you compile on
right now).
For example, "i586-linux".
--host=... :
The system on which VIM will be run. Quite often this the name of your
cross-compiler without the "-gcc".
For example, "powerpc-603-linux-gnu".
--target=... :
Only relevant for compiling compilers. Set this to the same value as
--host.
--with-tlib=... :
Which terminal library to use.
For example, "ncurses".
--build
交叉编译的主机,查看一下我的主机。
所以这里我填--build=x86_64-linux
--host
将来运行编译后程序的地方,查看一下我的路由器。
所以这里我填--host=mips-linux-gnu
--target
和--host
相同。
另外指定安装目录为--prefix=/home/alfiy/local/vim
关闭一些不需要的功能
--with-x=no --disable-gui --disable-netbeans --disable-pythoninterp --disable-python3interp --disable-rubyinterp --disable-luainterp
完成后的参数如下
acv_sizeof_int=4 vim_cv_getcwd_broken=no vim_cv_memmove_handles_overlap=yes vim_cv_stat_ignores_slash=yes vim_cv_tgetent=zero vim_cv_terminfo=yes vim_cv_toupper_broken=no ./configure --build=x86_64-linux --host=mips-linux-gnu --target=mips-linux-gnu --with-x=no --disable-gui --disable-netbeans --disable-pythoninterp --disable-python3interp --disable-rubyinterp --disable-luainterp --with-tlib=ncurses --prefix=/home/alfiy/local/vim
执行上面的命令,开始./configure
看起来一切正常,进入src
目录,执行
make
cd src
make install
看着满屏流水般丝滑的字符,我的心情无比的愉悦,成功正在一步步的走近我。
果然几分钟的时间,make
和install
都完成了,查看一下生成的二进制vim
文件吧.
file vim
仔细回想一下,我明明已经配置好交叉编译环境了啊,怎么没有生效?往上翻了几页编译时输出的日志,发现果然编译时还是使用的本机的gcc
我一拍大腿,对了,交叉编译配置成功后我有点得意忘行了,竟然忘记将交叉编译工具链添加到环境变量了。说干就干,不就是添加一个环境变量吗,至少有两种方法(打住莫学孔乙己)。
vim ~/.bashrc
在末尾添加工具链的地址(红框内换成你自己的工具链的地址不要照抄我的)。
source ~/.bashrc
让环境变量生效。
再次make
,make install
。
发现问题依旧,翻看make
的日志仍然如下图。
这就奇怪了,说好的已经加了环境变量了呢,怎么没有生效呢?我又是一阵百度,一直折腾到晚上10点多,其间在昏暗的灯光下查询了大量关于交叉编译的文章,写下了几十万字的读书笔记云云。。。(反正是很辛苦啦,看官,此处不应当点个赞关个注吗??)
最终在梦中遇到一位长须道长,告诉我应该在那段configure
配置命令中添加CC=mipsel-linux-gcc
,CC
变量的作用是告诉make
使用指定的编译命令,如此这般。
CC=mipsel-linux-gcc acv_sizeof_int=4 vim_cv_getcwd_broken=no vim_cv_memmove_handles_overlap=yes vim_cv_stat_ignores_slash=yes vim_cv_tgetent=zero vim_cv_terminfo=yes vim_cv_toupper_broken=no ./configure --build=x86_64-linux --host=mips-linux-gnu --target=mips-linux-gnu --with-tlib=ncurses --prefix=/home/alfiy/local/vim
重新configure
之前记得把前面的记录清除掉。
配置完configure
后再次make
.
make distclean
CC=mipsel-linux-gcc acv_sizeof_int=4 vim_cv_getcwd_broken=no vim_cv_memmove_handles_overlap=yes vim_cv_stat_ignores_slash=yes vim_cv_tgetent=zero vim_cv_terminfo=yes vim_cv_toupper_broken=no ./configure --build=x86_64-linux --host=mips-linux-gnu --target=mips-linux-gnu --with-tlib=ncurses --prefix=/home/alfiy/local/vim
make
如上图make
完成,一切都很正常的样子,接下来就是见证奇迹的最后一步了。
cd src
file vim
scp vim [email protected]:/tmp
ssh [email protected]
cd /tmp
运行vim
果然没有问题。
这篇博客本来到此就可以结束了,各位同学你们不是也看到结果了吗?我把过程一步步的写的也够清醒的了,可是如果你按照我上面的教程走,会出现一个非常严重的错误,也正是这个错误让我整整用了一天多的时间去排查。好了不卖关子了,最主要的是在configure
完成之后,make
的时候总会有一个找不到相关库报错,就是这个错误把我引向了歧路。
问题出在ncurses
上,我沿着报错信息找了很多资料都没有解决问题,最后,我意识到问题最大的可能是出在工具链上,在查找资料的时候,刚好看到有篇文章介绍crosstool-NG
说是要比buildroot
好用,我又用了半天多的时间从头到尾的把crosstool-NG
编译了几遍,最后也成功了,也生成了我所需要的二进制文件,可是在我的路由器上一运行提示内核太老,我只好放弃了,重新回到buildroot
上来。我感觉其实crosstool-NG
所谓的强大,是因为它提供了一系列的samples
模板,让用户可以不大用进入menuconfig
进行过多的配置就能实现想要的工具链了,但是不知我的版本不对还是什么原因,生成的文件运行时还是出错了。
重新编译工具链
cd /home/alfiy/Downloads/buildroot-2021.02.7
make distclean
make menuconfig
在meak menuconfig
时大部分配置都和我上篇博客中写的相似只是以下几处特别需要注意。
1.在Target packages
->Libraries
->Text and terminal handling
中选中ncurses
2.在Build options --->
->libraries
-> 中选中static only
3.重新编译工具链,只有这样生成的工具链编译出的二进制文件才是静态库,在网上找的很多通过在./confgure
时添加参数的方法都行不通。
好了这篇博文就到此为止了,我也有点累了,希望能给你有些帮助。
通过这两天多的折腾让我感受最深的是出现问题不可怕,最重要的是要有战胜困难的信心我勇气,说实在的对于交叉编译、嵌入式操作系统我真的是一点也不懂,可能在行家眼中我说了很多自以为是的外行话,但是我觉得学知识就是这样一步步成长起来的,不要怕别人的笑话,敢于失败100次,最后成功的一定是你。
还有我写博客的原因一是最近有时间了,二是我坚信只有你能说出来的知识才是你自己的知识。同学们和我一起努力吧,点个赞关个注,为我这位中年油腻大叔鼓个劲吧。
ps:仍需改进的地方
不知细心的朋友,或者正在执行编译的你发现没有,单个vim
已经有15M大小了,还有没有缩小体积的可能呢?当前有了,我们可以把vim
一些功能给阉割掉,但是主要的编辑文字的功能保留下来,这样体积就变小了。
要达到这个目的,只需执行如下的./configure
,然后再make
这样生成的vim
文件大概只有4~5M的样子了。
CC=mipsel-linux-gcc acv_sizeof_int=4 vim_cv_getcwd_broken=no vim_cv_memmove_handles_overlap=yes vim_cv_stat_ignores_slash=yes vim_cv_tgetent=zero vim_cv_terminfo=yes vim_cv_toupper_broken=no ./configure --build=x86_64-linux --host=mips-linux-gnu --target=mips-linux-gnu --with-x=no --disable-gui --disable-netbeans --disable-pythoninterp --disable-python3interp --disable-rubyinterp --disable-luainterp --with-tlib=ncurses --prefix=/home/alfiy/local/vim