自学内容网 自学内容网

【树莓派系列】交叉编译工具、交叉编译链的安装使用

交叉编译工具、交叉编译链的安装使用

一、交叉编译

1.1什么是交叉编译

(1)编译:是在一个平台上生成在该平台上的可执行代码

(2)交叉编译:是在一个平台上生成另一个平台上的可执行代码。

玩过51单片机的应该都知道,我们是在Windows上面编译,生成.hex文件,烧录到单片机上面,在51单片机上面运行,这其实就是最早的交叉编译。那为什么不在单片机上面运行编译,要在Windows上面,因为单片机安装不下配置环境,内存很小。

现在我们要做的就是不在树莓派什么进行编译了,在ubantu(本篇文章在虚拟机下\宿主机,进行编译代码,然后跑到树莓派上面运行)

● 我们在windows上面编写C51代码,并编译成可执行代码,如xx.hex,是在c51上面运行,不是在windows上面运行;

● 我们在ubuntu上面编写树莓派的代码,并编译成可执行代码,如a.out,是在树莓派上面运行,不是在ubuntu linux上面运行

1.2为什么要交叉编译

  1. 平台上不允许或不能够安装我们所需要的编译器比如C51;
  2. 因为目的平台上的资源贫乏,无法运行我们所需要编译器;
  3. 树莓派作为一款强大的开发板,同样也需要用到交叉编译。树莓派有时因为目的平台还没有建立,暂无操作系统,所以根本不能运行编译器。
  4. 操作系统也是代码,也要编译!

1.3宿主机和目标机

平台运行需要两样至少东西:bootloader(启动引导代码)以及操作系统核心。

● 宿主机(host) :编辑和编译程序的平台,一般是基于X86的PC机,通常也被称为主机(电脑X86)。
● 目标机(target):用户开发的系统,通常都是非X86平台。host编译得到的可执行代码在target上运行(树莓派ARM)。

二、搭建交叉编译工作环境

2.1安装工具链

树莓派官方下载网址:https://github.com/raspberrypi/

交叉工具链下载链接:https://github.com/raspberrypi/tools.git

1.下载工具链

两种方法下载工具链:
    方法一:直接去官网下载,具体步骤看下图
    方法二:输入命令 git clone https://github.com/raspberrypi/tools.git

方法一

image-20240828102857840
搜索tools,找到tools工具

image-20240828102930383

之后下载完成之后导入到ubantu系统之中即可

image-20240828103029074

下载完之后,自己找一个文件夹,解压出来。

(如果是使用git命令下载下来的,默认就是一个tools文件,无需再解压)

unzip tools-master.zip

2.进入文件目录中,依次进入如下目录直到bin目录(64位计算机就如下选择)

进入bin目录里,找到 arm-linux-gnueabihf-gcc

cd tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

image-20240828105607064

3.ls -l 查看bin目录底下各文件权限,arm-linux-gnueabihf-gcc作为软连接,实际用到的可执行程序是它后面的arm-linux-gnueabihf-gcc-4.8.3

ls -l

image-20240828105832860

2.2配置环境变量

临时:只在当前页面有效,风险性高,离开当前页面又需要重新配置;

永久:任何页面或路径下都有效,安全可靠

(1)Linux环境变量的作用和配置方法其实和Windows的环境变量一样,不一样的只有界面而已;

(2)在上面操作交叉编译工具链可以看到,要使用工具链就必须进入层层目录,繁琐且麻烦,降低开发效率;

(3)配置环境变量就能很好的解决这一问题;

● 配置临时环境变量

(1)echo $PATH :显示当前的环境变量;

image-20240828193243667

(2)pwd :找到tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin,并复制;

(3)export PATH=$PATH:自定义路径

(4)arm-linux-gnueabihf-gcc -v :检查是否找到,如果不配置的话只能在工具链的目录找到,配置完之后在任何目录下都可找到

export PATH=$PATH:/home/a/tools/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

临时变量重启之后就没了。

● 配置永久环境变量

(1)修改工作目录下的.bashrc 隐藏文件,配置命令终端的vi /home/你的用户名/.bashrc 打开后在文本最后一行加入以下内容:

export PATH=$PATH:你的工具链存放的路径

(2)source /home/用户名/.bashrc 加载配置文件,马上生效配置。

export PATH=$PATH:/home/a/tools/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

指令arm-linux-gnueabihf-gcc -v 检查交叉工具链是否是4.8.3版本

arm-linux-gnueabihf-gcc -v

image-20240828111006436

三、交叉编译宿主机和目标机

3.1交叉编译出可执行文件

检查交叉编译工具链arm-linux-gnueabihf-gcc -v

在Ubuntu上编写一个简单的程序:程序的文件名为:hello.c

#include <stdio.h>

int main()
{
    printf("hello,world");
    return 0;
}

我们分别查看一下常规编译与交叉编译生成的可执行程序的区别。

常规编译(使用gcc编译器编译):gcc hello.c -o a

交叉编译(使用树莓派的交叉编译器arm-linux-gnueabihf-gcc编译):arm-linux-gnueabihf-gcc hello.c -o b

file命令查看可程序a和b的属性:

● a在x86-64位计算机上面运行(宿主机-电脑),无法在ARM平台上运行

● b在ARM平台上运行(目标机-树莓派),无法在X86平台上运行(这是一个二进制文件)

image-20240828161334211

3.2宿主机编译生成的可执行文件下载到目标机(开发板)

使用scp命令,可通过网络IP实现文件的互传。

scp b pi@192.168.x.xxx:/home/pi

指令 文件名 开发板用户名@开发板地址:开发板的绝对路径

此方法也可以将目标机文件传至宿主机

四、交叉编译带wiringPi库的程序

说明:在树莓派中编写带wiringPi库的程序时(比如IO口),直接在程序中加头文件#include <wiringPi.h>,在编译的时候-l链接wiringPi库即可,因为树莓派自带有wiringPi库,在/usr/lib目录下。在Ubuntu中或者宿主机中没有自带wiringPi的库,那么很明显无法顺利完成带wiringPi库程序的交叉编译。

git clone git://git.drogon.net/wiringPi

出现的问题:

1.现在写一个wiringPi.h的程序。

//demo.c
#include <stdio.h>
#include <wiringPi.h>
#include <stdlib.h>

#define PIN 7  //#define宏定义控制引脚为GPIO.7

int main()
{
 int cmd;

 if(wiringPiSetup() == -1){  //初始化wiringPi库
     printf("init error\n");
     return -1;
 }

 pinMode(PIN,OUTPUT); //设置为输出io口
 digitalWrite(PIN,HIGH);//默认断电状态
 while(1){
     printf("please input 0 or 1:0-close,1-open\n");//输入0或1,0关闭,1打开
     scanf("%d",&cmd);

     if(cmd == 1){
         digitalWrite(PIN,LOW);//输入的是1,就给低电平,供电     
     }else if(cmd == 0){
         digitalWrite(PIN,HIGH);//输入的是0,就给高电平,断电 
     }else{
         printf("OUTPUT error\n");//如果输入的不是1或0
         digitalWrite(PIN,HIGH);//就自动断电
         exit(-1);            //并退出
     }
 }
 return 0;
}

2.交叉编译这个文件,我们发现找不到这个头文件

arm-linux-gnueabihf-gcc demo.c

image-20240831205347929

3.OK好,那我去找到这个头文件,直接链接到目录下就可以了吧

我们找到他在目录:/home/a/raspberrypi/WiringPi/wiringPi下。

image-20240831205523912

4.我们之间链接到头文件目录下,发现报错又变了

arm-linux-gnueabihf-gcc demo.c -I /home/a/raspberrypi/WiringPi/wiringPi

image-20240831205741249

5.这个报错其实是跟树莓派一样的,如果不链接到库

//这个代码如果在树莓派底下运行同样会报相同的错误,gcc demo.c -lwiringPi 就可以解决
gcc demo.c

6.那我们再试一下,发现报错又变了,这个**-l**是去哪里链接了呢?他找不到这个库

arm-linux-gnueabihf-gcc demo.c -I /home/a/raspberrypi/WiringPi/wiringPi -lwiringPi

image-20240831210134339

7.-l,一般都会跑到**/usr/local/lib**下面去链接库

ls /usr/local/lib

image-20240831210306195

8.接下来我们怎么做?直接去树莓派主机上面,把他的wiringpi库拿来用。

● 将树莓派中自带的wiringPi库下载到Ubuntu或宿主机中
cd /usr/lib :树莓派wiringPi库的文件路径;

image-20240831214144106

ls -l |grep wiringPi :过滤出只有wiringPi库的相关文件

->表示软链接的意思

image-20240831214204260

③ 将软链接libwiringPi.so指向的libwiringPi.so.2.52下载到Ubuntu或宿主机中:

scp libwiringPi.so.2.52 a@192.168.x.x:/home/a/raspberrypi
指令 需要拷贝的文件名    目标用户名  ip     拷贝的目标路径
    scp libwiringPi.so.2.52 a@192.168.237.130:/home/a/raspberrypi

注意:这里要拷贝软连接指向的文件,如果直接拷贝软链接到Ubuntu,Ubuntu里并不会生成我们要的软链接。

需要我们自己生成软链接

五、软链接和硬链接

5.1 软链接

● 软链接文件有类似于Windows的快捷方式;

● 在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息;

● 在选定的位置上生成一个文件的镜像,不会占用磁盘空间。

生成方法:

还记得我们之前学的生成动态库的过程吗,就是以.so结尾的

ln -s libwiringPi.so.2.52 libwiringPi.so
指令 参数 要被链接的文件    要生成的软链接文件名字

image-20240901164332340

5.2 硬链接

● 在选定的位置上生成一个和源文件大小相同的文件;

● 硬链接通过索引节点来进行链接;在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接

允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要文件,以防止“误删”的功能。因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放,也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。

生成方法:

ln libwiringPi.so.2.50 libwiringPi.so 
没有参数 -s

无论是软链接还是硬链接,文件都保持同步变化

六、带有wiringPi库进行交叉编译

编译时通过-I -L来指定相关库的路径

● -I (注意是大写的i) 给gcc添加自定义的头文件的路径

● -L 给gcc添加额外的搜索库的路径

**说明:**demo.c是带有wiringPi.h的一个文件,是需要连接wiringPi库使用的程序;-I的wiringPi库的头文件是自行网上下载的wiringPi库的包;-L的wiringPi库是树莓拷贝到Ubuntu中的 。

arm-linux-gnueabihf-gcc demo.c -I /home/a/raspberrypi/WiringPi/wiringPi -L. -lwiringPi -o test
交叉编译工具链     树莓关于IO口文件   -I wiringPi库头文件路径             -L .在当前目录下 wiringPi库

附录

检索目录下所有带有gcc的命令

grep gcc -nir 

注意:踩坑1

查看一下工具链下的readme文档,安装了工具链

sudo apt-get install gcc-arm-linux-gnueabihf -y

image-20240828110519931

sudo apt-get install gcc-arm-linux-gnueabihf -y,安装完之后已经无需再配置环境变量了,配置环境变量这一部分可以直接跳过,如果无法使用再跳回来配置。

最新补充:最新版的软链接指向变了

变成了9.4.0的版本,这个时候,交叉编译是可以通过的,但是在后面进行wiringPi库链接时,就会出现一大堆问题,报错代码如下。解决办法就是将下载的交叉工具编译链全部卸载,严格按照上面的步骤进行下来。

image-20240901201416243

a@ubuntu:~/raspberrypi$ arm-linux-gnueabihf-gcc demo.c -I /home/a/raspberrypi/WiringPi/wiringPi -L. -lwiringPi -o test
    
/usr/lib/gcc-cross/arm-linux-gnueabihf/9/../../../../arm-linux-gnueabihf/bin/ld: warning: libcrypt.so.1, needed by ./libwiringPi.so, not found (try using -rpath or -rpath-link)
/usr/lib/gcc-cross/arm-linux-gnueabihf/9/../../../../arm-linux-gnueabihf/bin/ld: ./libwiringPi.so: undefined reference to `crypt@GLIBC_2.4'
collect2: error: ld returned 1 exit status

踩坑2:

报错:/libwiringPi.so: undefined reference to fcntl@GLlBC 2.28’交叉编译wiringPi库遇到了这个错误

因为要链接到动态库:-lwiringPi。

但是因为宿主机与目标机的glibc的版本不一样,你可以理解为gcc的编译版本不一致。

宿主机x86的为:2.31版本,而目标机ARM上面的为2.28版本

这个错误通常是由于交叉编译时使用的 gjlibc 版本与目标系统上的 glibc 版本不兼容导致的。GLIBC 2.28 是在较新的 glibc 版本中引入的函数,如果您的目标系统上的 glibc 版本低于 2.28,则会出现该错误。
解决这个问题的一种方法是更新目标系统上的 glibc 版本,以便与编译时使用的版本匹配。如果您无法更新目标系统上的 glibc 版本,可以尝试降低编译时使用的 glibc 版本。

博主做了哪些尝试呢?

第一个:在宿主机上面自己做一个wiringPi动态库,之前有讲过如何制作,找到官方的wiringPi库,进行制作。

但是后面由于不知道具体包含哪些源文件,所以制作出来的会报一些错误,用不了。

在这里我们要注意一下,-lwiringPi,链接的这个库libwiringPi.so必须是ARM架构的,也就是制作动态库时要用交叉编译arm-linux-gnueabihf-gcc,来编译这些文件

image-20240902111348966

第二个:把官方wiringPi下载下来之后可以自己配置,但是他们默认是使用的gcc工具进行编译,编译完成之后这个.so文件是x86架构的,所以导致与目标机的架构不匹配,也无法运行。

image-20240902111554445

解决办法:输入命令,我们发现好多都是gcc来编译的,在宿主机上面gcc编译出来的东西肯定是X86架构的,想要编译出来ARM架构的就需要arm-linux-gnueabihf-gcc来进行交叉编译。那么我们将gcc换成arm-linux-gnueabihf-gcc不就可以了吗

grep gcc -nir 

image-20240902115039675

你可以使用 sed 命令或文本编辑器来批量替换 Makefile 中的 gcc。以下是使用 sed 命令的示例

find . -name 'Makefile' -exec sed -i 's/gcc/arm-linux-gnueabihf-gcc/g' {} +

这个命令会在当前目录及其子目录下查找所有名为 Makefile 的文件,并将其中的 gcc 替换为 arm-linux-gnueabihf-gcc

image-20240902115556848

2.确保替换操作成功执行。你可以使用 grep 命令确认 gcc 是否已被替换:

grep -r 'arm-linux-gnueabihf-gcc' .

3.将所有gcc的换成arm-linux-gnueabihf-gcc之后,我们就可以回到wiringPi库底下重新进行安装。

./bulid

image-20240902115637609

4.这时我们再查看这个.so文件时,已经变成ARM架构的了

image-20240902115737616

5.交叉编译运行wiringPi库

已经可以编译成功了,比较纳闷的就是,指定在/usr/local/lib目录下去找wiringPi库找不到,我把他复制到当前目录下,并创建好软链接之后便可以生成可执行文件且可以运行了。不过好歹也是能够交叉编译wiringPi库了。

image-20240902120018636


原文地址:https://blog.csdn.net/v13111329954/article/details/142673904

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!