一、首先我们来认清楚交叉编译是什么,为什么要进行交叉编译?
(1)什么是交叉编译?
答:交叉编译是在一个平台上生成另一个平台上的可执行代码。
例如:我们在Windows
平台上编写的C51
的代码,并编译成在C51
上可执行的代码,例xxx.hex
文件,这个文件是在C51
上运行的并不是在Windows
上运行的
什么是编译呢?
答:编译就是在一个平台上生成在该平台上的可执行代码
例如:C51和stm32 的交叉编译发生在keil(集成环境上面)
(2)为什么要进行交叉编译呢?
原因:平台上不允许或不能够安装我们所需要的编译器,比如C51
a.因为目的平台上的资源贫乏,无法运行我们所需要的编译器
b.既然树莓派有自己的操作系统(linux
),那么树莓派是不是不需要进行交叉编译呢?
答:这是错的,树莓派也要进行交叉编译
树莓派有时候也是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器,操作系统也是代码,也是需要进行编译的。
平台运行至少需要两样东西:BootLoader
(启动引导代码)以及操作系统核心
c.那么什么是宿主机(host
)和目标机(target
)呢?
答:宿主机:编辑和编译程序的平台,一般是基于X86
的PC
机,通常也被称为i而主机
目标机:用户开发的系统,通常都是非X86
平台,宿主机编译得到的可执行的代码在目标机上运行
d.交叉编译需要用到的 工具有哪些?
交叉编译器、交叉编译工具链
那么接下来我们就来讲一下交叉编译工具链
二、交叉编译工具链的安装
1.交叉编译工具链的安装网址
进入网址后选tools
选择tools
之后选右上角的Code
,再选择Code
底下的Download ZIP
,这样就能够将交叉编译工具链的压缩包下载回来了
2.交叉编译工具链的压缩包下载好了之后,我们就来解压一下压缩包(这些操作都是在linux
虚拟机下进行的)
a.记得在上面的交叉编译工具链压缩包的下载的时候尽量将压缩包下载回到windows
跟linux
的共享文件夹中,这样方便进行解压,用FileZilla
进行文件的传输也是可以的,无论是共享文件夹还是FileZilla
都只是文件传输的一种手段而已
b.在linux
的工作目录下新建一个新的目录lessonPi
(这个都是随意的啦,每个人都不一样的,到时候配置环境变量的时候能够找到这个路径即可)
1)进入新建的目录/home/CLC/lessonPi
从共享文件夹中拷贝交叉编译工具链的压缩包到当前目录
cp /mnt/hgfs/sharefromwindows/tools-master.zip .
千万别漏了这个.
,这个.
的意思是表示当前目录的意思(上面那个路径是我虚拟机上跟Windows的共享文件夹的路径,每个人的都不尽相同)
2)将压缩包拷贝过来了之后就是将压缩包进行解压了
用指令 unzip tools-master.zip
进行解压
3)解压完了之后进入到交叉编译工具链所在的路径
cd /home/CLC/lessonPi/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
进入到这个路径底下之后,用pwd
指令打印出这个路径,然后复制下来
我们看到很多可执行文件(绿色),和软链接(蓝色),红框内的那个软链接就是我们要用到的
用ls -l
来查看一下,软链接实际用的是它所指向的一个可执行文件,软链接不占内存只是一个符号指向了这个位置
4)在获得了交叉编译工具链的软链接之后就是,接下来就是环境变量的配置,其实它有两种方式进行配置,一是临时的环境变量的配置,二是永久有效的环境变量的配置
a.首先用echo $PATH
获得当前环境变量的值
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:
记得无论环境变量多长,只需要取到games:
这里即可
b.进行环境变量的配置
临时有效的环境变量的配置:
export PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/CLC/lessonPi/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
把a这个步骤取得的环境变量拿下来,然后再把(3)步骤取得的路径接着在games:
后面
这样就完成了临时环境变量的配置,这样有点不好的就是,这只是仅限这个终端窗口而已,在另一个终端这个环境变量就失效了
永久有效的环境变量的配置:
首先修改工作目录下的隐藏文件.bashrc
,配置命令终端的vi/home/CLC/.bashrc
进入该隐藏文件之后,在文件的末尾添加
export PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/CLC/lessonPi/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
然后保存把并退出文件
如何加载配置文件:
使用 source /home/CLC/.bashrc
命令加载配置文件,马上生效配置
5)我们来检查一下交叉编译工具对不对
我们查看交叉编译工具链的版本,出现了第二张图那样的4.8.3的版本号就是说明已经安装成功了
三、交叉编译工具链的使用
1.首先我们来简单对比一下gcc
和交叉编译工具arm-linux-gnueabihf-gcc
两者编译出来的可执行文件有什么不一样
那么现在我们就对ftptest1.c
这个文件进行编译出来的test1
,用file
来查看一下两者分别编译出来的可执行文件test1
有什么不同
gcc
:
我们可以看到这里显示的是X86-64
的属性,这就是表示能在Windows(linux虚拟机)下运行,但在树莓派上是跑不起来的
arm-linux-gnueabihf-gcc
:
用交叉编译的方式编译出来的可执行文件可看出是ARM
属性的,这就说明这只能是在树莓派上跑在windows(linux虚拟机)上是跑不起来的
2.经过上面的介绍,那么现在我们就来实地的实战一下
在虚拟机上利用交叉编译的方式编译出可执行的文件,再把可执行文件传送到树莓派上运行
arm-linux-gnueabihf-gcc xxx.c -o xxx
我们可看到编译出的test1
是可执行文件x
就是表示可执行的意思
如何把编译生成的可执行文件下载到开发板:
方式一:
通过scp
的方式
scp test1 pi@192.168.191.4:/home/pi
指令 文件名 开发板用户名@开发板地址:开发板的绝对路径
不幸的是我的出现了这个问题,连接请求超时,刚开始以为是ssh
还没开启,查看了一下虚拟机跟树莓派两边都已经开启了ssh
,但还是会出现这个情况,那么我们就先遗留一下这个问题在这里,我们到时候解决,其实有些人的是可以的
方式二:
通过FileZilla
的方式进行传输
这个方式有点冗余,为什么呢,因为要把文件移动到windows
底下,再从windows
移动到树莓派下,这样就显得有点麻烦了,但是上面那种办法暂时没解决,就先用这个先吧
像图片里的那样开多个窗口,先把文件移动到windows
下,再移动到树莓派下
我们发现通过这种方式移动的可执行文件到树莓派下,竟然是没有执行权限的
所以我们执行的时候就会出现权限被拒接的提示,那么出现这种情况该怎么办呢?
我们通过指令chmod +x
来为文件test1
赋予可执行的权限,x
就是可执行的意思
chmod +x test1
我们再来看一下现在test1
已经有了可执行的权限了
现在我们再来运行一下test1
,已经是可以跑起来的了
四、带WiringPi
库的交叉编译如何处理
(1)我们在上面对交叉编译工具链进行了安装并使用,那么现在我们就来学习一下带WiringPi
库的交叉编译该如何处理。
首先我们要明白在虚拟机上本来是没有wiringPi
库的,所以当我们要在虚拟机上使用这个库的时候,我们首先要对这个库进行安装
所以在下面我已经将wiringPi
库的压缩包上传到网盘上,直接提取即可
由于wiringPi
的那个官网已经失效,所以好好珍惜这个文件
wiringPi库提取
提取码:2j5k
(2)在下载完wiringPi
库的压缩包之后,我们斗胆来试一下在虚拟机上安装这个wiringPi
库
首先我们可以这个压缩包拿进虚拟机里(用unzip xxx
的方式进行解压),其次我们也可以在windows
下进行解压,将文件夹放进windows
与linux
的共享文件夹中
2.1 我们从共享文件夹中复制文件夹到当前路径
cp /mnt/hgfs/sharefromwindows/WiringPi -rf .
我的共享文件夹是/mnt/hgfs/sharefromwindows
,所以cp /mnt/hgfs/sharefromwindows/WiringPi
的意思就是将文件夹WiringPi
的所有内容都复制到当前目录来,.
在上面有提及过,是代表当前目录的意思。
-rf:强制递归复制
-r:若给出的源文件是一个目录文件,此时将复制该目录底下所有的子目录和文件
-f:覆盖已经存在的目标文件而不给出提示
没有则错误提示cp: omitting directory(删除目录)
2.2 拿到一个库后,我们习惯要看一下 README.TXT
和INSTALL
这两个文件
INSTALL
从上面内容中我们可以看出这个库是通过./build
的方式来进行安装,在安装完这个库之后,我们可以在/usr/local/lib
底下查看这个库的所有内容
安装出现一下黄框内的字符就是说明已经安装成功了
我们来/usr/local/lib
底下看一下确实是有这个库相关的东西在
即使这样,但是安装上的wiringPi库还是用不了的,原因是什么,我们继续往下看。
2.3 既然在上面我们库已经装上了,那么我们就斗胆的从树莓派下拿个文件过来进行交叉编译看一下
能不能跑起来
linux
虚拟机与树莓派之间怎么进行文件的传输在上面已经讲过了,所以在这里就不再进行讲解了
a. 对文件进行编译 arm-linux-gnueabihf-gcc demo1.c
在上图中我们可以看到提示不认识wiringPi.h
这个头文件,这个问题还是好解决的,在之前linux
动态库那里有说过怎么让它找头文件的位置,那么接下来我们就来解决一下这个问题
b. 我们通过指定头文件的路径去再编译一遍看看会再出现什么问题
arm-linux-gnueabihf-gcc demo1.c -I /home/CLC/lessonPi/WiringPi/WiringPi/wiringPi
-I(大写i):指定头文件的路径
-L(大写l):指定库的路径
这个意思是指定从 /home/CLC/lessonPi/WiringPi/WiringPi/wiringPi 这个路径底下去找头文件<wiringPi.h>
我们从上图中可以看到,指定了头文件的路径之后就不再是第一次的错误了,现在是提示对这些函数没定义,也就是不认识的意思,那么这个跟在树莓派下没指定库名的错误是一样的
在树莓派下
在linux虚拟机中的错误跟在树莓派下的错误是一样的,从下面的图中我们可以看出,在后面链接上wiringPi这个库之后就不再会提示错误了,那么我们在虚拟机下也来指定一下这个库
c.再上面我们发现了不仅要指定头文件的路径还要指定库的名字,那么现在我们就来指定一下库名看看能不能编译通过
arm-linux-gnueabihf-gcc demo1.c -I /home/CLC/lessonPi/WiringPi/WiringPi/wiringPi -lwiringPi
-l(小写的L):指定要用的库的名字
这里的意思就是指定要用wiringPi这个库
我们从上图中依然看到还是出现错误,那么到底是什么回事呢?
d. 接着上面的问题继续探究下去
既然出现以上的问题,那么我们就要来考虑一下是不是库本身的问题了,我们来看一下库的内容
ls /usr/local/lib/ ls -l 查看库的内容
我们从上图中可以看出软链接真正指向的库是libwiringPi.so.2.46
,那么我们来看一下这个库的属性
file libwiringPi.so.2.46
来到这,原因已经找到了,这个库的是x86平台的,即在windows下可使用,在arm下是不可以使用的。
问题总结:我们不要忘记,我们使用的是一个交叉编译的工具链,在进行交叉编译的时候所要链接的库也应该是对应平台的,即我们在
windows
虚拟机上交叉编译在ARM
平台上运行的可执行程序,所以我们链接的库也应该是ARM
平台的,否则这个工具不认识这个库,正常的我们是应该先要交叉编译wiringPi
库,编译出的库适合树莓派,在这个时候交叉编译可执行程序的时候,链接的库的格式也是正确的
来到这里,我们问题已经找到了,关于如何解决这个问题,请关注下一篇博文软链接与硬链接
学习笔记,仅供参考