交叉编译 和 软硬链接 的初识(面试重点)
目录
交叉编译的初认识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语句,将对…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
Java中栈的多种实现类详解
Java中栈的多种实现类详解:Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...