交叉编译 和 软硬链接 的初识(面试重点)
目录
交叉编译的初认识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平台上交叉编译生成树莓派平台上的可执行代码:
- 由于树莓派是作为目标机的,所以安装树莓派相对应的交叉编译器/工具链
- 而安装的平台则应该是宿主机,也就是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通虚拟机
解决办法:
- 断开电脑的宽带,连接局域网(能Ping通之后可以改回来)
- 将虚拟机的网络设置从NAT改为桥接
- 在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/lib找wiringPi库,然后在/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 7int main (void)
{wiringPiSetup () ; //初始化wiringPi库pinMode (BEEP, OUTPUT); //配置输入输出模式while(1){digitalWrite (BEEP, LOW) ; //蜂鸣器响delay (1000) ; // mSdigitalWrite (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

然后在树莓派尝试运行:
成功运行,蜂鸣器以固定间隔开始发出声音。
相关文章:
交叉编译 和 软硬链接 的初识(面试重点)
目录 交叉编译的初认识Q&A Q1: 编译是什么? Q2: 交叉编译是什么? Q3: 为什么要交叉编译 Q3.1:树莓派相对于C51大得多,可以集成编译器比如gcc,那么树莓派就不需要交叉编译了吗? Q4: 什么是宿主机和…...
Docker attach 命令
docker attach:连接到正在运行中的容器。 语法 docker attach [OPTIONS] CONTAINER要attach上去的容器必须正在运行,可以同时连接上同一个container来共享屏幕(与screen命令的attach类似)。 官方文档中说attach后可以通过CTRL-…...
Keil5个性化设置及常用快捷键
Keil5个性化设置及常用快捷键 1.概述 这篇文章是Keil工具介绍的第三篇文章,主要介绍下Keil5优化配置,以及工作中常用的快捷键提高开发效率。 第一篇:《安装嵌入式单片机开发环境Keil5MDK以及整合C51开发环境》https://blog.csdn.net/m0_380…...
rtsp点播异常出现‘circluar_buffer_size‘ option was set but it is xx
先说现象: 我使用potplay播放器来点播rtsp码流的时候可以点播成功,同事使用vlc和FFplay来点播rtsp码流的时候异常。 排查思路: 1.开始怀疑是oss账号问题,因为ts切片数据是保存在oss中的,我使用的是自己的oss账号,同事使用的是公司…...
C++ Qt QString用法详解与代码演示
作者:令狐掌门 技术交流QQ群:675120140 csdn博客:https://mingshiqiang.blog.csdn.net/ 文章目录 创建和初始化长度和容量修改字符串字符串比较查找和提取数值转换arg格式化`arg` 的基本用法精确控制占位符多占位符的复杂替换使用大括号占位符注意事项迭代Unicode 和编码QSt…...
安全攻击及防范手册
目录 1 概述 1.1 简介 1.2 参考资料 2 安全隐患及预防措施 <...
Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线(实例分析)
Visual Studio 使用MFC 单文档工程从创建到实现绘制单一颜色直线和绘制渐变颜色的直线 本文主要从零开始创建一个MFC单文档工程然后逐步实现添加按键(事件响应函数),最后实现单一颜色直线的绘制与渐变色直线的绘制o( ̄▽࿾…...
一起学docker系列之八使用 Docker 安装配置 MySQL
目录 前言步骤 1:拉取 MySQL 镜像步骤 2:运行 MySQL 容器步骤 3:检查容器状态步骤 4:进入 MySQL 容器步骤 5:配置 MySQL 字符编码步骤 6:重启 MySQL 容器步骤 7:测试字符编码步骤 8:…...
4G执法记录仪在大型安保集团,保安集团、蓝天救援队中的 应用,行为规范化,人员定位,考勤打卡,应急指挥调度
【智能化升级】揭秘4G/5G执法记录仪在安保与救援领域如何重塑行业标准与效率 在快速发展的社会当中,大型安保集团、保安集团和蓝天救援队所肩负的任务日益繁重与复杂。无论是在平时的治安巡查、安保执勤,还是在突发公共事件的应急响应中,如何…...
分布式事务,一致性理论, 两阶段提交(2PC), 三阶段提交(3PC),Seata分布式事务方案
文章目录 分布式事务:1、一致性理论2、两阶段提交(2PC)3、三阶段提交(3PC)4、Seata分布式事务方案 上一篇降到了 分布式锁,先来和大家聊一聊分布式事务, 分布式锁的链接如下: http…...
摆脱无用代码的负担:TreeShaking 的魔力
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
A-莲子的软件工程学【算法必会题目】(JavaPythonC++实现)
文章目录 A-莲子的软件工程学题目背景解题思路Python题解代码Java题解代码C++题解代码代码OJ评判结果代码讲解Python 代码解释:Java 代码解释:C++ 代码解释:寄语A-莲子的软件工程学 题目背景 在宇宙射线的轰击下,莲子电脑里的一些她自己预定义的函数被损坏了。 对于一名…...
STM32-SPI1控制AD7705(Sigma-Delta-ADC芯片)
STM32-SPI1控制AD7705(Sigma-Delta-ADC芯片) 原理图手册说明功能方框图引脚功能 片内寄存器通信寄存器(RS2、RS1、RS00、0、0)设置寄存器时钟寄存器数据寄存器(RS2、RS1、RS00、1、1)测试寄存器(…...
13年老鸟总结,性能测试方法汇总+性能响应很慢排查方法(详全)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、性能测试包含哪…...
[网络] 3. HTTP 3 与 HTTP 2 有什么区别
协议不同 HTTP2 是基于 TCP 协议实现的 HTTP3 是基于 UDP 协议实现的QUIC HTTP3 新增了 QUIC 协议来实现可靠性的传输握手次数 HTTP2 是基于 HTTPS 实现的,建立连接需要先进行 TCP 3次握手,然后再进行 TLS 3次握手,总共6次握手。 HTTP3 只需要…...
IDEA中的Postman?完全免费!
Postman是大家最常用的API调试工具,那么有没有一种方法可以不用手动写入接口到Postman,即可进行接口调试操作?今天给大家推荐一款IDEA插件:Apipost Helper,写完代码就可以调试接口并一键生成接口文档!而且还…...
用JAVA编程解决数位和相等问题
如果一个正整数转化成二进制与转换成八进制后所有数位的数字之和相等,则称为数位和相等的数。 前几个数位和相等的正整数为 1, 8, 9, 64, …… 请问第 23 个数位和相等的正整数是多少?用JAVA编程解决 可以通过编程计算第 23 个数位和相等的正整…...
Kotlin学习——kt中的类,数据类 枚举类 密封类,以及对象
Kotlin 是一门现代但已成熟的编程语言,旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作,并提供了多种方式在多个平台间复用代码,以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…...
XUbuntu22.04之解决gpg keyserver receive failed no data(一百九十三)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
Hibernate 脏检查和刷新缓存机制
刷新缓存: Session是Hibernate向应用程序提供的操作数据库的主要接口,它提供了基本的保存,更新,删除和加载java对象的方法,Session具有一个缓存,可以管理和追踪所有持久化对象,对象和数据库中的相关记录对应,在某些时间点,Session会根据缓存中对象的变化来执行相关SQL语句,将对…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...







