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

目录

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

 然后在树莓派尝试运行:

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

 

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

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

相关文章

鸿蒙HarmonyOS 编辑器 下载 安装

好 各位 之前的文章 注册并实名认证华为开发者账号 我们基实名注册了华为的开发者账号 我们可以访问官网 https://developer.harmonyos.com/cn/develop/deveco-studio 在这里 直接就有我们编辑器的下载按钮 我们直接点击立即下载 这里 我们根据自己的系统选择要下载的系统 例…

Unsupervised MVS论文笔记(2019年)

Unsupervised MVS论文笔记&#xff08;2019年&#xff09; 摘要1 引言2 相关工作3 实现方法3.1 网络架构3.2 通过光度一致性学习3.3 MVS的鲁棒光度一致性3.4 学习设置和实施的细节3.5.预测每幅图像的深度图 4 实验4.1 在DTU上的结果4.2 消融实验4.3 在ETH3D数据集上的微调4.4 在…

电力感知边缘计算网关产品设计方案-网关软件设计方案

网关采用网络协议和软件技术在通信网络中针对工业协议、互联网通用协议进行分析和记录,提升工业控制系统环境的安全防护能力。A类和B类网关采用容器技术的软件架构,采用C/S架构软件客户端提供应用软件平台,为管理员提供功能丰富的图形管理控制界面。 因A类和B类网关在产品定…

按需引入 ElMessage,没有样式且类型检查失败

文章目录 ElMessage 弹框没有样式问题描述解决方案 ts 类型检查失败问题描述解决办法 eslint 检查失败问题描述解决办法 ElMessage 弹框没有样式 问题描述 Element-plus 在使用 ElMessage 消息弹框的时候没有样式&#xff0c;按照官方的按需加载的方式引入的 import { ElMes…

AIGC ChatGPT4总结Linux Shell命令集合

在Linux中,Shell命令的数量非常庞大,因为Linux提供了各种各样的命令来处理系统任务。这些命令包括GNU核心工具集、系统命令、shell内置命令以及通过安装获得的第三方应用程序命令。以下是一些常见的Linux命令分类及其示例,但请注意,这不是一个全面的列表,因为列出所有命令…

Dempster-Shafer(D-S)证据理论的基本定义和详细分析,优点,缺点,应用!!(系列1)

文章目录 前言一、D-S证据理论的应用&#xff1a;二、D-S证据理论的优点&#xff1a;三、D-S证据理论的缺陷&#xff1a;四、D-S组合规则&#xff1a;总结 前言 Dempster-Shafer&#xff08;D-S&#xff09;证据理论是一种不精确推理理论&#xff0c;也称为Dempster/Shafer证据…

【开源】基于Vue+SpringBoot的农家乐订餐系统

项目编号&#xff1a; S 043 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S043&#xff0c;文末获取源码。} 项目编号&#xff1a;S043&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户2.2 管理员 三、系统展示四、核…

spark数据倾斜的解决思路

数据倾斜是&#xff1a;多个分区中&#xff0c;某个分区的数据比其他分区的数据多的多 数据倾斜导致的问题&#xff1a; 导致某个spark任务耗时较长&#xff0c;导致整个任务耗时增加&#xff0c;甚至出现OOM运行速度慢&#xff1a;主要发生在shuffle阶段&#xff0c;同样的k…

大数据数据仓库,Sqoop--学习笔记

数据仓库介绍 1. 数据仓库概念 数据仓库概念创始人在《建立数据仓库》一书中对数据仓库的定义是&#xff1a;数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的&#xff08;Subject Oriented&#xff09;、数据集成的&#xff08;Integrated&#xff09;、相对…

一、深入简出串口(USRT)通信——基本概念。

一、前言 串口到底是什么&#xff1f;简单来说一句话就可以解释&#xff0c;串口就是一种通信协议。 看到这里可能大家会觉得你这不是放屁么&#xff0c;说了跟没说一样。所以这里做前言来描述&#xff0c;大家要先对通信协议有一个下意识地认识才能在学习串口的时候不至于迷茫…

【Flutter 常见问题系列 第 1 篇】Text组件 文字的对齐、数字和字母对齐中文

TextStyle中设置height参数即可 对齐的效果 Text的高度 是根据 height 乘于 fontSize 进行计算的、这里指定heiht即可、不指定的会出现 无法对齐的情况&#xff0c;如下&#xff1a; 这种就是无法对齐的情况

Qt4用子类化ProxyModel和子类化MainWindow实现全表筛选,中文排序和复制粘贴

目录 1 需求 2 子类化ProxyModel实现全表筛选 3 字符串列表实现中文排序 3.1 Qt5中文排序 3.2 Qt4排序 4 表格的复制粘贴 5 应用 1 需求 模型视图编程是Qt开发的基本功&#xff0c;其中有几个关键问题需要解决&#xff1a; 全表筛选&#xff0c;或者说多列搜索中文排序…

Linux服务器SSH客户端断开后保持程序继续运行的方法

目录 1. nohup 命令&#xff1a; 2. tmux 或 screen&#xff1a; 3 final shell 断开后服务器如何继续执行令&#xff1f; 方法一&#xff1a;使用 nohup 命令 方法二&#xff1a;将命令放在后台执行 4 你可以使用 jobs 命令查看当前终端中正在后台运行的任务 &#xff…

决策树(第四周)

一、决策树基本原理 如下图所示&#xff0c;是一个用来辨别是否是猫的二分类器。输入值有三个&#xff08;x1&#xff0c;x2&#xff0c;x3&#xff09;&#xff08;耳朵形状&#xff0c;脸形状&#xff0c;胡须&#xff09;&#xff0c;其中x1{尖的&#xff0c;圆的}&#xf…

叠加原理(superposition principle)、线性系统

叠加原理&#xff08;superposition principle&#xff09;&#xff1a;指对一个系统而言&#xff0c;两个或多个输入产生的输出&#xff0c;等于这几个输入单独引起的输出的和&#xff0c;即输入的叠加等于各输入单独引起的输出的叠加。 线性系统&#xff1a;一个系统&#x…

常用的Linux的指令

目录 常用指令 1、文件和目录操作&#xff1a; 2、文件查看和编辑 3、系统信息 4、进程管理 5、用户和权限 6、网络操作 7、压缩和解压 8、软件包管理 常用指令 1、文件和目录操作&#xff1a; ls&#xff1a;列出目录内容 cd&#xff1a; 切换目录 pwd&#xff1a;显…

十分钟让你搞懂JVM中的GC垃圾回收机制(分代回收)

文章目录 0. 为什么要有垃圾回收?1. 垃圾回收哪个内存区域?2. 如何找到垃圾(死亡对象的判断)2.1 引用计数法2.2 可达性分析法2.3 两种算法的差别 3. 如何清理垃圾(死亡对象的回收)3.1 标记-清楚法3.2 复制法3.3 标记-整理法 4. JVM使用的回收方法4.1 什么是分代回收4.2 哪些对…

JVM——几种常见的对象引用

目录 1. 软引用软引用的使用场景-缓存 2.弱引用3.虚引用和终结器引用 可达性算法中描述的对象引用&#xff0c;一般指的是强引用&#xff0c;即是GCRoot对象对普通对象有引用关系&#xff0c;只要这层关系存在&#xff0c; 普通对象就不会被回收。除了强引用之外&#xff0c;Ja…

C++局域网从服务器获取已连接用户的列表(linux to linux)

目录 服务器端 代码 客户端 代码解析 服务器端 原理 遇到的阻碍以及解决办法 客户端 原理 遇到的阻碍以及解决办法 运行结果截图 总结 服务器端 代码 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet…

深入了解 Pinia:现代 Vue 应用的状态管理利器

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…