交叉编译 和 软硬链接 的初识(面试重点)

目录

交叉编译的初认识Q&A

Q1: 编译是什么?

Q2: 交叉编译是什么?

Q3: 为什么要交叉编译

Q3.1:树莓派相对于C51大得多,可以集成编译器比如gcc,那么树莓派就不需要交叉编译了吗?

Q4: 什么是宿主机和目标机?

Q5: 如何进行交叉编译?

交叉编译器/工具链 的安装

将交叉编译器/工具链添加到环境变量

临时有效的添加环境变量

永久有效的添加环境变量

交叉编译实战

使用以下指令交叉编译客户端的代码:

 使用以下指令将交叉编译生成的可执行文件发送到开发板:

实现效果 :

带wiringPi库的交叉编译实战

方法1:交叉编译wiringPi库

方法2:把树莓派的wiringPi库拿来

创建软链接 

软硬链接概念补充

交叉编译


交叉编译的初认识Q&A

Q1: 编译是什么?

A: 在一个平台上生成该平台的可执行代码


Q2: 交叉编译是什么?

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

其实在之前学习C51的时候就需要交叉编译。只不过对于C51,交叉编译的发生在keil(集成环境)上。其 实质就是在windows平台上编译C51平台的可执行代码


Q3: 为什么要交叉编译

A: 因为平台上不允许或不能够安装所需要的编译器(比如:C51很小,如果再集成编译器会浪费大量资源甚至根本就无法安装)。

Q3.1:树莓派相对于C51大得多,可以集成编译器比如gcc,那么树莓派就不需要交叉编译了吗?

A:并不是,树莓派也需要交叉编译。因为树莓派也是从无到有的,在树莓派的操作系统还不存在的时候,根本就无法运行什么编译器,但是操作系统的本质也是代码,所以操作系统也是需要通过编译才能在树莓派上运行的!这就不得不在另一个平台编译生成树莓派的可执行代码,而这就是交叉编译。(接下来的学习中我即将在Linux平台上编译可以在树莓派中执行的代码

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


Q4: 什么是宿主机和目标机?

A: 简单来说比如在UBUNTU-Linux平台交叉编译树莓派的可执行代码,那么UBUNTU就是宿主机,树莓派就是目标机。

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

Q5: 如何进行交叉编译?

A:  交叉编译需要用到工具,一般称作交叉编译器交叉编译工具链

交叉编译器/工具链 的安装

现在我的目的是在Ubuntu-Linux平台上交叉编译生成树莓派平台上的可执行代码:

  1. 由于树莓派是作为目标机的,所以安装树莓派相对应的交叉编译器/工具链
  2. 而安装的平台则应该是宿主机,也就是Linux虚拟机
  • 在这个网址下载工具链:GitHub - raspberrypi/tools

复制网址,然后打开虚拟机,使用以下命令用git clone来下载

git clone https://github.com/raspberrypi/tools.git

我尝试过直接“Download ZIP” ,但是下载下来的内容是缺少的,且windows会报同名文件的错,我猜测是因为windows系统下对大小写的文件名不敏感导致的,总之就是很麻烦,还是使用git clone省心。

 下载好之后,依次进入:tools -> arm-bcm2708 -> gcc-linaro-arm-linux-gnueabihf-raspbian-x64 -> bin:

图中,浅蓝色文件代表的是“软链接”,我们需要用到的交叉编译器就是浅蓝色的“arm-linux-gnueabihf-gcc”,通过“ls -l”:

可见,这个“arm-linux-gnueabihf-gcc”软链接是指向“arm-linux-gnueabihf-gcc-4.8.3”的,软链接是不占内存的,作用就是指向真正的可执行程序,在使用中,就可以直接使用软链接的名字来调用真正的可执行文件。

所以,“arm-linux-gnueabihf-gcc”就是交叉编译器/工具链,使用和gcc无异,比如编译XXX.C,编译语句就是:

./arm-linux-gnueabihf-gcc XXX.C //只不过把“gcc”替换成了“./arm-linux-gnueabihf-gcc”

将交叉编译器/工具链添加到环境变量

现在,已经拥有了交叉编译器并且知道了大概如何编译。

但是每次使用这个编译器都需要cd到“/home/mjm/ras_CrossCompile/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin”下,或在编译的时候就把这个路径加在编译器前面,非常的繁琐复杂,我希望在使用交叉编译器的时候能和使用gcc一样不管在什么路径都可以直接打出来,这就要使用到环境变量了

临时有效的添加环境变量

临时的添加环境变量,其实在前几节学习动态库的制作时就有提到过,那就是使用export,临时的意思就是“仅在添加完环境变量后的当前窗口有效”,也就是说如果再开一个窗口就又识别不到新添加的环境变量了。

  • 使用“echo $PATH”可以查看当前的环境变量:

这一长串中:前面的“/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:” 是不变的

  • 然后使用“export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:想要添加的路径”来临时添加环境变量:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/mjm/ras_CrossCompile/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

 运行后,退回工作目录,输入“arm-linux-gnueabihf-gcc -v”:(“-v”查看编译器信息

可见,此时在其他目录下,也可以暂时使用交叉编译器了!

此时,新开一个终端,再次输入“arm-linux-gnueabihf-gcc -v”:

可见无法识别,所以export确实只能临时有效。

永久有效的添加环境变量

临时有效虽然一句命令就能搞定,但是有风险,因为终端随时可能关闭,然后添加的临时环境变量就失效了,所以还是学习一下如何一劳永逸的修改环境变量:

  • 修改工作目录下的 .bashrc 隐藏文件(该文件用于配置命令终端的
vi /home/mjm/.bashrc

 然后在文件的最后一行加上刚刚的export指令:

其实,bashrc隐藏文件 就是一个脚本,永久有效的核心思路就是通过脚本自动运行export,和动态库写脚本写export的思路是一样的。

  • 然后运行“source /home/mjm/.bashrc” 加载配置文件,生效配置

  • 此时,再开一个新的终端并运行“arm-linux-gnueabihf-gcc -v”:

可见,这样就永久有效的将交叉编译器的目录添加到了环境变量中去了! 

交叉编译实战

现在,尝试将之前博文实现的服务器客户端聊天代码中的服务器端代码交叉编译到树莓派平台

Linux socket网络编程实战(tcp)实现双方聊天_linux网络编程 聊天_mjmmm的博客-CSDN博客

服务器和客户端的代码分别是“/home/mjm/NET”下的“server_final.c”和“client_final.c

  • 使用以下指令交叉编译客户端的代码:

arm-linux-gnueabihf-gcc server_final.c -o server_from_linux

 在一开始编译的时候报了巨量的错误:

  • 经过查证,我认为主要是头文件的重定义?在"server_final.c"中,将“netinet/in.h”和“linux/in.h”两个头文件注释掉就好了!

然后可以执行“file server_from_linux” 来查看文件属性:

可见,相比于原来ubuntu下的可执行文件,经过交叉编译后的可执行文件的属性发生了改变

 

  •  使用以下指令将交叉编译生成的可执行文件发送到开发板:

scp server_from_linux pi@192.168.2.26:/home/pi/mjm_code
//指令  文件名  开发板用户名@开发板地址:开发板的绝对路径

然后使用Moba连接到树莓派:

可见,文件成功发送到了树莓派

  • 实现效果 :

//在树莓派上
./server_from_linux 192.168.2.26 8888

//在ubuntu-linux虚拟机上
./client 192.168.2.26 8888

可见,经过交叉编译的可执行代码成功在树莓派平台运行!

但是,我发现如果把客户端交叉编译发送到树莓派,虽然也可以运行但是无法和虚拟机的服务端连接。也就是说树莓派只能做服务端不能做客户端,因为树莓派没法连接到虚拟机的IP。 所以我尝试了ping,发现:

  • 虚拟机可以ping通树莓派和主机
  • 树莓派可以ping通主机
  • 主机可以ping通树莓派和虚拟机
  • 唯独树莓派没法ping通虚拟机

解决办法:

  1. 断开电脑的宽带,连接局域网(能Ping通之后可以改回来)
  2. 将虚拟机的网络设置从NAT改为桥接
  3. 在VMWare左上的“编辑”里选择“虚拟网络编辑器”,然后修改“已桥接到”后的选项框,选择我电脑的网络“Media Tek WI-FI 6 MT7921 Wireless LAN Card

此时再次打开虚拟机,先输入ifconfig来查看IP(切换网络设置之后IP会变):

然后在树莓派尝试ping这个地址:

成功ping通!此时将虚拟机linux平台的client端代码交叉编译并上传到树莓派试运行:

  • 成功运行!此时树莓派成功作为客户端连接到了虚拟机的ubuntu-linux平台!!
  • 并且此时可以断开电脑的局域网换回宽带了!

带wiringPi库的交叉编译实战

在刚刚的交叉编译实例中,成功的将ubuntu-linux环境下的代码交叉编译成为了可以在树莓派上运行的arm-linux可执行文件。

但是,刚刚交叉编译的代码在编译时不需要链库,如果代码包含wiringPi或线程库里的函数,那么在gcc编译时就需要链库,对于这种需要链库的C代码进行交叉编译不能直接无脑的在“arm-linux-gnueabihf-gcc XXX.c”后加上“-lwiringPi”,其原因是库文件也是当前平台下的文件,并不能被树莓派平台所识别!

先将wiringPi库下载到/home/mjm下:

然后运行“./build”安装:

然后再“/usr/local/lib” 下就可以看到这个wiringPi的动态库:

通过“file /usr/local/lib/libwiringPi.so”查看文件属性:

发现是个软链接,指向“libwiringPi.so.2.46” ,那就对它再file一下:

可见,的确是当前平台下的格式,显然在树莓派上是无法运行的


方法1:交叉编译wiringPi库

既然这个库文件无法被树莓派平台识别,那就先交叉编译库文件,再链库并交叉编译代码。

但是对于动态库的交叉编译和之前的方法可能不同,所以这种方法暂时不展开。

方法2:把树莓派的wiringPi库拿来

直接把能在树莓派平台上使用的wiringPi库拿来也可以解决问题。

在树莓派中的依次从/lib-->/usr/lib-->/usr/local/libwiringPi库,然后在/usr/lib下找到了

有了刚刚的经验,这个估计也是个软链接,使用file看一下:

 

果然,是指向libwiringPi.so.2.52的软链接,所以应该发送到虚拟机的是这个库文件。

通过scp命令发送给虚拟机:

scp ./usr/lib/libwiringPi.so.2.52 mjm@192.168.2.27:/home/mjm/ras_CrossCompile

虚拟机要先“sudo apt-get install openssh-server”安装ssh服务才能支持scp文件传输!

 

  • 创建软链接 

在得到wiringPi的动态库后,我们也可以学着对其创建一个名称更加简洁的软链接:

软硬链接概念补充

参考:https://www.cnblogs.com/zhangna1998517/p/11347364.html

  • 软链接的创建通常使用“ln -s 被链接对象 软链接文件名”指令,会在选定的位置上生成一个被链接对象的镜像,且不会占用磁盘空间类似于Windows下的快捷方式。软链接也叫符号连接,在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息
  • 软链接相对应的就是硬链接,通常使用“ln 被链接对象 硬链接文件名”指令创建(没有参数-s),会在选定的位置上生成一个和被链接对象大小相同的文件
  • 不管是软链接还是硬链接,创建的镜像/文件都会随着链接对象的变化而同步变化

使用以下指令创建软链接: 

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

创建好之后可以file一下: 

 可见,软链接创建成功!

再使用file查看一下:

 确实是树莓派平台下的wiringPi动态库!

  • 交叉编译

现在有了树莓派平台下的wiringPi库,可以开始尝试交叉编译带有wiringPi库的C代码了!

先写一段符合要求的,即带wiringPi库的代码:

beep.c:

#include <stdio.h>
#include <wiringPi.h>

#define BEEP 7

int main (void)
{

	wiringPiSetup () ; //初始化wiringPi库

	pinMode (BEEP, OUTPUT); //配置输入输出模式

	while(1){
		digitalWrite (BEEP, LOW) ;	//蜂鸣器响
		delay (1000) ;		// mS

		digitalWrite (BEEP, HIGH) ;	//蜂鸣器不响
		delay (1000) ;
	}

	return 0;
}

然后使用以下指令交叉编译:

arm-linux-gnueabihf-gcc blink.c -L ./ -lwiringPi -I /home/mjm/WiringPi/wiringPi -o blink_from_linux
  • 使用“-L ”:指定动态库的优先查找目录为当前目录
  • 使用“-I”(大写i):指定头文件的优先查找目录为/home/mjm/WiringPi/wiringPi

编译时报错:

解决办法:

  • 重新向虚拟机导入版本2.50的wiringPi动态库:

  • 删除之前的软链接,然后重新设置软链接:

  • 再次尝试编译:

成功编译,没有报错!

最后使用scp发送到树莓派:

scp blink_from_linux pi@192.168.2.26:/home/pi/mjm_code

 然后在树莓派尝试运行:

成功运行,蜂鸣器以固定间隔开始发出声音。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/205112.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32---时钟树

写在前面&#xff1a;一个 MCU 越复杂&#xff0c;时钟系统也会相应地变得复杂&#xff0c;如 STM32F1 的时钟系统比较复杂&#xff0c;不像简单的 51 单片机一个系统时钟就 可以解决一切。对于 STM32F1 系列的芯片&#xff0c;其有多个时钟源&#xff0c;构成了一个庞大的是时…

一个软件测试练手项目——学生信息管理系统测试,卷起来啊

免费分享一个练手项目&#xff0c;学生信息管理系统&#xff0c;获取方式在文末 1.引言 1.1项目目的 软件测试是为了在软件投入生产性运行之前&#xff0c;尽可能多地发现软件的错误。该项目的目的是给学习软件测试的朋友练手用 1.2 项目背景 随着学校的规模不断扩大&…

技巧-GPU显存和利用率如何提高和batch_size/num_works等参数的实验测试

目录 简介实验测试显存占用问题GPU占用率波动问题num_work不是越大越好 总结 本专栏为深度学习的一些技巧,方法和实验测试,偏向于实际应用,后续不断更新,感兴趣童鞋可关,方便后续推送 简介 在PyTorch中使用多个GPU进行模型训练时&#xff0c;各个参数和指标之间存在一定的关系…

安防视频监控/磁盘阵列/集中云存储平台EasyCVR设备录像保活不生效原因是什么?该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

18、串口通信

串口介绍 串口是一种应用十分广泛的通讯接口&#xff0c;串口成本低、容易使用、通信线路简单&#xff0c;可实现两个设备的互相通信。 单片机的串口可以使单片机与单片机&#xff0c;单片机与电脑、单片机与各式各样的模块互相通信&#xff0c;极大的扩展了单片机的应用范围&…

Linux基础操作三:Linux操作命令-目录文件操作

1、关机和重启 关机shutdown -h now 立刻关机shutdown -h 5 5分钟后关机poweroff 立刻关机 重启shutdown -r now 立刻重启shutdown -r 5 5分钟后重启reboot 立刻重启 2、帮助 --help命令shutdown --help&#xff1a;…

MySQL表的查询、更新、删除

查询 全列查询 指定列查询 查询字段并添加自定义表达式 自定义表达式重命名 查询指定列并去重 select distinct 列名 from 表名 where条件 查询列数据为null的 null与 (空串)是不同的&#xff01; 附&#xff1a;一般null不参与查询。 查询列数据不为null的 查询某列数据指定…

【JUC】十九、volatile与内存屏障

文章目录 1、volatile的两大特性2、volatile的四大内存屏障3、分类4、happens-before之volatile变量重排规则5、读写屏障插入策略 1、volatile的两大特性 被volatile修饰的变量有两大特点&#xff1a; 可见性有序性 关于volatile的可见性&#xff0c;也即volatile的内存语义…

线性回归 调试方法

调试方法 特征缩放 对于某些不具有比较性的样本特征 x i x_i xi​ &#xff08;比如对其他的x来说 x i x_i xi​ 相当大或者相当小&#xff09;&#xff0c;梯度下降的过程可能会非常漫长&#xff0c;并且可能来回波动才能最后收敛到全局的最小值。 在这样的情况下&#xff…

8年经验之谈 —— Redis的性能测试与优化!

Redis作为一种高性能的Key-Value数据库&#xff0c;一直受到众多开发者和企业的青睐。然而&#xff0c;在高并发、大数据存储的应用场景中&#xff0c;如何测试并优化Redis的性能&#xff0c;成为了问题。本文将从测试与优化两个方面来讲解如何达到最优的Redis性能。 一、性能…

Android Studio Giraffe版本遇到的问题

背景 上周固态硬盘挂了&#xff0c;恢复数据之后&#xff0c;重新换了新的固态安装了Win11系统&#xff0c;之前安装的是Android Studio 4.x的版本&#xff0c;这次也是趁着新的系统安装新的Android开发工具。 版本如下&#xff1a; 但是打开以前的Android旧项目时&#xff…

Selenium定位元素的方法css和xpath的区别!

selenium是一种自动化测试工具&#xff0c;它可以通过不同的定位方式来识别网页上的元素&#xff0c;如id、name、class、tag、link text、partial link text、css和xpath。 css和xpath是两种常用的定位方式&#xff0c;它们都可以通过元素的属性或者层级关系来定位元素&#…

Python 自动化测试全攻略:五种自动化测试模型实战详解!

随着移动互联网的发展&#xff0c;软件研发模型逐步完善&#xff0c;软件交付质量越来越受到软件公司的重视&#xff0c;软件测试技术特别是自动化测试技术开始在软件系统研发过程中发挥着越来越重要的作用。 与传统的手工测试技术相比&#xff0c;自动化测试具备了良好的可操…

考试复习

选择20道 填空10道 判断10道 简答4-5道 编程题2道 一、选择题 1.js中更改一个input框的值&#xff1a; <input ida type"text" value"123456"> 通过a.value改变他的值 方法&#xff1a; 在script标签中通过id获得该输入框对象&#xff0c;然…

从0到字节跳动30W年薪,我在测试行业“混”的第5个年头····

一些碎碎念 什么都做了&#xff0c;和什么都没做其实是一样的&#xff0c;走出“瞎忙活”的安乐窝&#xff0c;才是避开弯路的最佳路径。希望我的经历能帮助到有需要的朋友。 在测试行业已经混了5个年头了&#xff0c;以前经常听到开发对我说&#xff0c;天天的点点点有意思没…

探索前端设计的新境界——介绍IVueUI工具助力Vue页面设计

在快速发展的前端领域&#xff0c;Vue.js作为一款渐进式JavaScript框架&#xff0c;一直备受开发者喜爱。然而&#xff0c;在Vue前端开发的旅程中&#xff0c;页面设计常常是一个不可避免的挑战。今天&#xff0c;我要向大家介绍一款令Vue前端开发者受益匪浅的工具——www.ivue…

Peter算法小课堂—高精度乘法

给大家看个小视频13 高精度算法 乘法_哔哩哔哩_bilibili 乘法竖式 大家觉得Plan A好&#xff0c;还是Plan B好呢&#xff08;对于计算机来说&#xff09;&#xff1f;那显然是B啦 x*y问题 mul思路&#xff1a;mul()函数返回x数组乘y数组的积&#xff0c;保存在z数组。根据上…

jupyter notebook 添加conda环境变量为内核(kenel)

第一步&#xff1a;安装ipykernel 在激活环境后&#xff0c;需要安装ipykernel包&#xff0c;以便将Conda环境添加到Jupyter Notebook中。使用以下命令安装&#xff1a; pip install ipykernel第二步&#xff1a;将Conda环境添加到Jupyter 需要将Conda环境添加到Jupyter Not…

python爬取robomaster论坛数据,作为后端数据

一. 内容简介 python爬取robomaster论坛数据&#xff0c;作为后端数据 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3代码 三.主要流程 3.1 接口分析 # 接口分析 # 全部数据 # https://bbs.robomaster.com/forum.php?modforumdisplay&fid63 2…

LeetCode(46)汇总区间【区间】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 汇总区间 1.题目 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某…