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

news2024/11/26 10:43:23

目录

交叉编译的初认识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

 然后在树莓派尝试运行:

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

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(3)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

【C语言】【选择排序及其优化】

选择排序是指&#xff1a;第一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;然后再从剩余的未排序元素中寻找到最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序的序列的末尾&#xff0…

Golang 设置运行的cpu数与channel管道

介绍&#xff1a;为了充分了利用多cpu的优势&#xff0c;在Golang程序中&#xff0c;设置运行的cpu数目。 func main() {//获取系统当前cpu的数量num : runtime.NumCPU()//这里根据需求来设置整个go程序去使用几个cpuruntime.GOMAXPROCS(num)fmt.Println("num ", nu…

csgo/steam搬砖项目还能不能做,分享玩法思路

饰品市场持续下跌&#xff0c;CSGO搬砖还有搞头吗&#xff1f; CSGO是最具竞争力的第一人称射击游戏。玩这款游戏离不开里面的炫酷配件。Steam搬砖项目是基于CSGO游戏中的配件运动。蒸汽拆砖项目的原理是使用国外Steam平台的充值卡购买国际服务器的配件和设备&#xff0c;然后转…

quasar杂记

Windows下的奇怪错误 Unknown network error occurred 管理员运行powershell&#xff0c;运行&#xff1a; net stop winnat net start winnat

图书管理系统源码,图书管理系统开发,图书借阅系统源码四TuShuManager应用程序MVC控制器Controllers

Asp.net web应用程序MVC之Controllers控制器 Controller在ASP.NET MVC中负责控制所有客户端与服务器端的交互,并且负责协调Model与View之间的数据传递,是ASP.NET MVC的核心。 撰写Controller的基本要求: 1、Controller必须为公开类别; 2、Controller名称必须以Controller结…

如何在VS2022上的MFC项目中操作Excel(VS2010、VS2012、VS2015、VS2017、VS2019使用方法一样)

先决条件 本机安装office2003、2007、2010、2016及以后版本&#xff0c;总之必须安装office导入Excel库文件&#xff0c;导入方式可参考&#xff1a; 如何在vs2017及以前版本(vs2010、vs2015)上添加 添加类型库中的MFC类如何在vs2019及以后版本(如vs2022)上添加 添加ActiveX控…

【TinyALSA全解析(四)】扩展篇-从TinyALSA到底层音频驱动的全流程分析

扩展篇-从TinyALSA到底层音频驱动的全流程分析 第一节 本文说明第二节 声卡驱动统一入口进行ops替换过程2.1 tinyalsa到Linux kernel2.2 Linux Kernel中&#xff0c;由主设备号ops分流到次设备号ops 第三节 次设备中file_operations的open函数3.1 本节主要内容3.2 为何次设备的…

Python生成exe文件

Python如何生成exe文件 在终端执行 pip install pyinstaller 在终端执行pyinstaller E:\fund_data\GetFund.py&#xff0c;运行结束后会在D:\Python\Python311\Scripts\dist\目录下生成GetFund.exe文件 3.双击exe文件运行&#xff0c;如果未出现预期结果&#xff0c;可以把e…

深度学习之图像分类(十五)DINAT: Dilated Neighborhood Attention Transformer详解(一)

Dilated Neighborhood Attention Transformer Abstract Transformers 迅速成为跨模态、领域和任务中应用最广泛的深度学习架构之一。在视觉领域&#xff0c;除了对普通Transformer的持续努力外&#xff0c;分层Transformer也因其性能和易于集成到现有框架中而受到重视。这些模…

NAS-DIP: Learning Deep Image Prior with Neural Architecture Search

NAS-DIP: 用神经结构搜索学习深度图像先验 论文链接&#xff1a;https://arxiv.org/abs/2008.11713 项目链接&#xff1a;https://github.com/YunChunChen/NAS-DIP-pytorch Abstract 最近的研究表明&#xff0c;深度卷积神经网络的结构可以用作解决各种逆图像恢复任务的结构…

CGAN原理讲解与源码

1.CGAN原理 生成器&#xff0c;输入的是c和z&#xff0c;z是随机噪声&#xff0c;c是条件&#xff0c;对应MNIST数据集&#xff0c;要求规定生成数字是几。 输出是生成的虚假图片。 判别器的输入是 1.生成器输出的虚假图片x; 2.对应图片的标签c 来自真实数据集&#xff0c;且…

大模型下交互式数据挖掘的探索与发现

在这个数据驱动的时代&#xff0c;数据挖掘已成为解锁信息宝库的关键。过去&#xff0c;我们依赖传统的拖拉拽方式来建模&#xff0c;这种方式在早期的数据探索中起到了作用&#xff0c;但随着数据量的激增和需求的多样化&#xff0c;它的局限性逐渐显露。 >>>> 首…

selenium已知一个元素定位同级别的另一个元素

1.需求与实际情况 看下图来举例 &#xff08;1&#xff09;需求 想点击test22&#xff08;即序号-第9行&#xff09;这一行中右边的“复制”这一按钮 &#xff08;2&#xff09;实际情况 只能通过id或者class定位到文件名这一列的元素&#xff0c;而操作这一列的元素是不…

知识变现的未来:解析知识付费系统的核心

随着数字时代的发展&#xff0c;知识付费系统作为一种新兴的学习和知识分享模式&#xff0c;正逐渐引领着知识变现的未来。本文将深入解析知识付费系统的核心技术&#xff0c;揭示其在知识经济时代的重要性和潜力。 1. 知识付费系统的基本架构 知识付费系统的核心在于其灵活…

为什么要用 Redis 而不用 map/guava 做缓存? Redis为什么这么快 Redis有哪些数据类型 Redis的应用场景

文章目录 为什么要用 Redis 而不用 map/guava 做缓存?Redis为什么这么快Redis有哪些数据类型Redis的应用场景总结一计数器缓存会话缓存全页缓存&#xff08;FPC&#xff09;查找表消息队列(发布/订阅功能)分布式锁实现 总结二 简单的聊聊Redis常见的一些疑问点&#xff1a;具体…

预算削减与经济动荡:2024 年明智且经济地创新

如何在经济衰退周期中保持创新&#xff1f;这篇创新研究提供了实用建议。在经济下行压力下领导者往往会试图降低成本和维持生存。然而&#xff0c;这种二元对立的压力往往会导致领导者做出不够理想的决策&#xff0c;更多地关注生存而不是未来投资。本文提供了一系列实用的建议…

蓝桥杯-平方和(599)

【题目】平方和 【通过测试】代码 import java.util.Scanner; import java.util.ArrayList; import java.util.List; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在…

MATLAB中FFT频谱分析使用详解

文章目录 语法说明语法一&#xff1a;Y fft(X)fft(X)返回X长度的傅里叶变换 语法二&#xff1a;Y fft(X,N)如果 X的长度小于 N&#xff0c;则为 X补上尾零以达到长度 N(FFT插值)双边谱转换为单边谱 如果 X 的长度大于 N&#xff0c;则对 X 进行截断以达到长度 N。 语法三&…

根据密码构成规则检测密码字符串

从键盘输入密码字符串&#xff0c;程序根据给定密码构成规则检测并给出对应提示。 (笔记模板由python脚本于2023年11月27日 19:27:47创建&#xff0c;本篇笔记适合熟悉Python字符串str对象的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.…