交叉编译是一个行为 ,是在一个平台上生成另一个平台上的可执行代码。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。
我们vi test.c
/ gcc test.c
是编辑代码和编译代码,没有交叉
编译:是一个平台上生成在该平台上可执行的代码
交叉编译:是在一个平台上生成,在另一个平台上的可执行代码
交叉编译
例如: 我们在windows 上面编写C51代码,并编译成可执行代码,如xxx.hex ,是在C51上面运行,不是在windows上运行
我们在linux 上面编写树莓派代码,并编译成可执行代码,如a.out,是在树莓派上面运行,不是在ubuntu上运行
例如:C51 交叉编译的发生在keil (集成环境上面)
stm32开发
有时是因为目的平台上不允许或不能够安装我们所需要的编译器,比如C51
平台运行需要至少两样东西: bootloader(启动引导代码)以及操作系统核心
交叉编译是不得已而为之!与主机编译相比,交叉编译受的限制更多,虽然在理论上我们可以做任何形式的交叉编译,但事实上,由于受到专利、版权、技术的限制,并不总是能够进行交叉编译
交叉编译要用到的工具
交叉编译器、交叉编译工具链
明白了什么是交叉编译,那我们来看看什么是交叉编译链。
首先编译过程是按照不同的子功能,依照先后顺序组成的一个复杂的流程,如下图:
那么编译过程包括了预处理、编译、汇编、链接等功能。既然有不同的子功能,那每个子功能都是一个单独的工具来实现,它们合在一起形成了一个完整的工具集。
同时编译过程又是一个有先后顺序的流程,它必然牵涉到工具的使用顺序,每个工具按照先后关系串联在一起,这就形成了一个链式结构。
因此,交叉编译链就是为了编译跨平台体系结构的程序代码而形成的由多个子工具构成的一套完整的工具集。同时,它隐藏了预处理、编译、汇编、链接等细节,当我们指定了源文件(.c)时,它会自动按照编译流程调用不同的子工具,自动生成最终的二进制程序映像(.bin)。
注意:严格意义上来说,交叉编译器,只是指交叉编译的gcc,但是实际上为了方便,我们常说的交叉编译器就是交叉工具链。本文对这两个概念不加以区分,都是指编译链
我们使用交叉编译链时,常常会看到这样的名字:
arm-none-linux-gnueabi-gcc
arm-cortex_a8-linux-gnueabi-gcc
mips-malta-linux-gnu-gcc
其中,对应的前缀为:
arm-none-linux-gnueabi-
arm-cortex_a8-linux-gnueabi-
mips-malta-linux-gnu-
这些交叉编译链的命名规则似乎是通用的,有一定的规则:
arch-core-kernel-system
注意:这个规则是一个猜测,并没有在哪份官方资料上看到过。而且有些编译链的命名确实没有按照这个规则,也不清楚这是不是历史原因造成的。如果有谁在资料上见到过此规则的详细描述,欢迎指出错误。
一般由编译器、连接器、解释器和调试器组成,就是为了编译、链接、处理和调试跨平台体系结构的程序代码。
不同的平台用的交叉比编译器不同,就像我们在用keil编译51的代码时要选择对应的芯片,编译32的代码时也要选择对应的芯片,这其实都是在间接地选择了编译器。如果目标机是树莓派,那么我们将会用到树莓派的交叉编译工具链。
下载地址:https://github.com/raspberrypi/
交叉编译工具链的安装有两种方法: ①临时有效 ②永久有效
把压缩包导入到linux 下 文件里
导入后,用指令unzip tools-master.zip
进行解压
解压完成后
我们进入cd arm-bcm2708/
进 cd gcc-linaro-arm-linux-gnueabihf-raspbian-x64
cd bin/ , 我们能看到一堆可执行文件
我接下来会用到的工具,蓝色的是软链接
我们ls -l
看一下 ,软连接实际上是假的,它真正用到的是 -> 后面的东西
我们要编译时候,需要进很多目录后,会很麻烦。怎么办呢?
这就涉及到环境变量
临时有效:
将路径加入PATH环境变量(将命令加入终端,使命令使用更加方便,不用敲很长的路径),echo $PATH
显示当下的环境变量,然后使用指令:export PATH=设置新的环境变量
PATH (环境变量)
我们要想直接gcc编译,不敲前面的路径的话。我们需要进行环境变量设置。
我们echo $PATH
显示当前环境变量
我们修改环境变量(临时有效)
export PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/CLC/lessonPi/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
设置好后,我们回到根目录,就可以直接执行arm-linux-gnueabihf-gcc -v
永久有效:
vi .bashrc打开工作目录下的.bashrc(隐藏文件),用来配置命令终端的,每次启动终端都会执行这个脚本。将上面的配置命令添加在这个文件的最后一行即可。然后source
/home/CLC/.bashrc使用这个指令是设置立即生效
去修改工作目录下的.bashrc
隐藏文件,配置命令终端的
我们打开指令 vi /home/CLC/.bashrc
然后在脚本文件最后面写入 刚才的路径
保存并退出。执行一下 source /home/CLC/.bashrc
source 加载配置文件,马上生效指令
这样就配置好了,无论,多少个窗口都可以执行 arm-linux-gnueabihf-gcc -v
4.8.3 才是树莓派的交叉编译工具链
我们看到test_1 是只能运行到x86-64位的主机上,树莓派是不能运行test_1的
我们用交叉编译一下test.c
arm-linux-gnueabihf-gcc test.c -o test_2
我们看到test_2 是只能运行到ARM,这样树莓派就可以运行test_2了
我们传到树莓派上 ,输入指令: scp test_2 [email protected]:/home/pi
在输入树莓派的登录密码 ,在树莓派上就可以看到test_2 了
在树莓派上就看到了test_2,并且可以执行。
我们把之前在linux上的文件都可以发给树莓派上。
在树莓派上执行FTP客户端
交叉编译:
检测下交叉编译工具链对不对:
arm-linux-gnueabihf-gcc xxx.c -o xxx
如何把编译生成的可执行文件下载到开发板上:
scp xxx pi@192.168.0.100: /home/pi
指令 文件名 开发板用户名@ 开发板地址:开发板的绝对路径
需要先在宿主机上面(这里是ubuntu)安装wiringPi库
wiringPi库百度网盘:链接:https://pan.baidu.com/s/1cPIt-xZLye1DAQjq2yKzeg提取码:35vt
进入解压后的WiringPi文件夹,然后打开INSTALL这个文件夹,我们会查看如何下载,这里显示直接执行./build
文件即可,会在./build unistall 生成(编译wiringPi库生成动态库,编译时需要链接,但是它是使用的gcc编译器,编译出来库是只能运行在x86平台上的),然后将会下载到/usr/local/lib
这个目录下,起始是不容用的。
我们先用之前写的继电器组代码,试一下。从树莓派把demo2.c传到linux里
然后可以使用指令:arm-linux-gnueabihf-gcc demo2.c
但是会发现头文件不认识,因为我们之前学过了动态库,运用动态库的知识来解决。
首先我们要找到头文件
然后可以使用动态库 指令: arm-linux-gnueabihf-gcc demo2.c -I /home/CLC/lessonPi/WiringPi/wiringPi -lwiringPi
来找。
发现还是报错
是因为链接wiringPi库的时候是链的/usr/local/lib
这个目录下来链接 libwiringPi.so
的
但是file libwiringPi.so
去查看这个文件的属性,发现这个文件的属性是在x86上面运行的,然而我们需要在ARM上面运行,所以是不兼容的
链接库的格式不对,是宿主机的平台所以会报错:/home/fhn/arm-tool/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/…/lib/gcc/arm-linux-gnueabihf/4.8.3/…/…/…/…/arm-linux-gnueabihf/bin/ld: cannot find -lwiringPi collect2: error: ld returned 1 exit status
那怎么解决这个问题呢?
我们可以将树莓派的wiringPi库拿到虚拟机,libwiringPi.so
就这个动态库,但是这是个 软连接(相当于快捷方式)
使用指令:ls -l |grep libwiringPi.so
可以看出这个文件是指向libwiringPi.so.2.50这个动态库的。所以我们需要将这个动态库发送到ubuntu
里面,使用指令:scp libwiringPi.so.2.50 [email protected]:/home/fhn/wringPi/WiringPi
,就算将软连接发送到ubuntu也不会指向这个动态库,还需要我们自己创建动态库。
如果传输过程中出现错误:ssh: connect to host 192.168.43.112 port 22: Connection refused lost connection表示ubuntu没有安装ssh,在ubuntu里面下载ssh即可:sudo apt-get install ssh
使用指令:ln -s libwiringPi.so.2.50 libwiringPi.so
创建软连接,
在lessonPi目录下 (包含libwiringPi.so.2.50
的目录)
输入命令:ln -s libwiringPi.so.2.50 libwiringPi.so
创建一个软链接
我们ls -l 看到有->接过,说明创建成功
下面有详细的讲解软硬链接
创建软连接后使用指令:arm-linux-gnueabihf-gcc demo2.c -I /home/CLC/wringPi/WiringPi/wiringPi -L. -lwiringPi -o jidianqi
进行编译,其中:-I /home/CLC/wringPi/WiringPi/wiringPi
是链接的wiringPi库的头文件,-L
是指定动态库在当前目录下去查找库文件。
学习指令:
grep gcc * -nir
在所有文件里面查找gcc字眼,n表示显示行号、i表示不区分大小写、n表示递归查找、*表示在所有文件里面去查找。
硬盘:
在介绍硬链接和软链接之前,首先介绍下硬盘相关的知识,主要是了解下 inode 。
总结:
superBlock : 存储整个文件系统的信息。
inode : 存储文件的权限与属性。
data block : 真正存储文件内容。
软链接(symbolic link) :
等同于 Windows 系统下的快捷方式。仅仅包括所含链接文件的路径名字。因此能链接目录,也能跨文件系统链接。但是,当删除原始文件后,链接文件也将失效。
在 Windows 系统中,快捷方式是指向原始文件的一个链接文件。可以让用户从不同的位置来访问原始的文件;原文件一旦被删除或剪切到其他地方后,会导致链接文件失效。
但是在 Linux 系统中,"快捷方式"就不太一样 ,在 Linux 系统存在硬链接和软链接两种文件。
ln -s 是linux中一个非常重要命令,一定要熟悉。它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,
具体用法是:ln -s 源文件 目标文件
。
【软链接】(像windos的快捷方式):
另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
-s 是代号(symbolic)的意思。
这 里有两点要注意:
软链接概念总结
- 软链接文件有类似于Windows的快捷方式
- 在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息
- 它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间
如何生成:
ln -s libwiringPi.so.2.50 libwiringPi.so
指令 参数 要链接的文件 软链接文件名字
在lessonPi目录下 (包含libwiringPi.so.2.50
的目录)
输入命令:ln -s libwiringPi.so.2.50 libwiringPi.so
创建一个软链接
我们ls -l 看到有->接过,说明创建成功
硬链接(hard link) :
可以将它理解为一个 “指向原始文件 inode(储存原始文件信息) 的指针”,系统不为它分配独立的 inode 和 文件。所以,硬链接文件与原始文件其实是同一个文件,只是名字不同。我们每添加一个硬链接,该文件的 innode 连接数就会增加 1 ; 而且只有当该文件的 inode 连接数为 0 时,才算彻底将它删除。因此即便删除原始文件,依然可以通过硬链接文件来访问。需要注意的是,我们不能跨分区对文件进行链接。可以使用指令:ln fileName newFileName
为原文件fileName 创建硬链接newFileName
具体用法是:ln 源文件 目标文件
。
软链接概念总结
它会在你选定的位置上生成一个和源文件大小相同的文件,无论是软链接还 是硬链接,文件都保持同步变化。
硬连接指通过索引节点来进行连接
硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功
文件真正删除的条件是与之相关的所有硬连接文件均被删除。
【硬链接】
硬连接指通过索引节点来进行连接。
在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。
在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。 硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。
其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
如何生成:
ln libwiringPi.so.2.50 libwiringPi.so
指令 要链接的文件 软链接文件名字
总结:
硬链接是指向原始文件 inode的指针,而软连接则是仅仅包括所含链接文件的路径名字
软链接示例 :ln -s helloWorld sHelloWorld
硬链接示例 :ln helloWorld hardHelloWorld
问题:
硬链接占据空间吗 ?
比如我有一个 1G 的文件,现在我给这个文件建了一个硬链接。
那么会占据 2G 空间吗?
不会,之前我们说了硬链接是一个指针或者说是文件的引用,只占一点点空间,软连接不占用磁盘空间。
软硬连接参考博文、交叉编译参考博文