前言:
本文主要讲述软件的源码本地编译和交叉编译的基本概念,首先,是介绍什么是本地编译,什么是交叉编译,其次,本地编译和交叉编译到底是有什么用处,最后是交叉编译和本地编译的具体应用场景
一、
什么是编译?本地编译?交叉编译
在硅基世界里,也就是我们的计算机世界内,由于历史的原因,有非常多的繁杂的操作系统,比如debian,fedoras,redhat,windows,macos, VxWorks 和 QNX,FreeRTOS、 uC / OS,等等,在软件方面主要体现的是操作系统的种类非常多
以下是一些可以基于RISC-V架构的操作系统:
Linux:Linux内核已经适配了RISC-V架构,因此可以在RISC-V处理器上运行Linux操作系统。这意味着许多流行的Linux发行版(如Ubuntu、Debian和Fedora)也可以在RISC-V上使用。
FreeBSD:FreeBSD是另一个流行的开源操作系统,它也支持RISC-V架构。这意味着你可以在RISC-V处理器上运行FreeBSD操作系统。
OpenBSD:OpenBSD是一个注重安全性的操作系统,它也已经支持RISC-V架构。如果你关注系统安全性,OpenBSD可能是一个不错的选择。
Debian GNU/Linux:Debian GNU/Linux也适配了RISC-V架构,因此你可以在RISC-V处理器上使用Debian发行版。
而在硬件方面,主要的体现是繁杂的硬件种类,比如,cpu的架构就有很多种类
x86:是当前主流的处理器架构,常见于 intel 和 AMD 的处理器中,支持 32 位和 64 位操作系统。
ARM:常见于大部分移动设备和嵌入式系统,也有部分主流的服务器和个人电脑采用 ARM 处理器架构,支持 32 位和 64 位操作系统。
MIPS:常见于家用路由器、智能电视、智能家居等嵌入式设备,主要支持 32 位操作系统。
PowerPC:IBM 公司开发的处理器架构,主要在高性能计算机、服务器等领域使用,支持 32 位和 64 位操作系统。
SPARC:Oracle 公司开发的处理器架构,主要在服务器等领域使用,支持 32 位和 64 位操作系统。
RISC-V:开源 RISC-V 的处理器架构正在逐渐发展壮大,被认为是未来的处理器发展方向之一
硬件和软件操作系统搭配组合成了我们常用的各种电脑,比如,桌面服务器通常是x86_64架构的cpu+centos(redhat) 这样的组合,笔记本电脑通常是x86_64架构的cpu+Windows7,10,11这样的组合,手机端的通常是arm架构的cpu(RISC-V架构的cpu)+Android11这样的组合,ATM机则通常使用x86-64架构的cpu+winxp,还有非常多的嵌入式设备,使用的硬件cpu架构和操作系统也是种类非常多的,每一个都不尽然相同
面对如此复杂的局面,我们的软件就需要做各种各样的适配,例如,微信需要适配后,也就是重新编译后,才可以在鸿蒙系统顺利运行,同样的,有些基础软件只能通过编译来进行升级,例如openssl,但编译有一个明显的优点:一处编译,随处运行 也就是在一个服务器上成功编译后,编译产出物移植到其它的服务器上,并不需要再次编译,可以直接运行
欧克,这样的本地编译很显然是不能跨平台的,例如,win+arm架构,编译产出物并不能在win+x86架构下正常运行,那么,此时就需要交叉编译了,比如,在win+x86架构下编译产出win+arm架构可用的软件,此时的编译就是交叉编译。
交叉编译:
是指在一个平台上生成另一个平台上的可执行代码。具体来说,交叉编译是在一个平台上编译生成在另一个平台上运行的可执行程序。这种编译方式常见于嵌入式系统和跨平台开发中,因为不同的体系结构有不同的指令系统,不同的cpu需要相应的编译器。交叉编译的作用类似于翻译,将相同的程序代码翻译成不同CPU对应的可执行二进制文件。
为什么会需要使用交叉编译呢?
比如,一个很简单的场景:某品牌的手机需要更新某个常用app,很明显,开发和测试环境在手机内部并不容易实现本地的编译,而如果我们在一个任意的常用的架构平台下开发,编译并通过详细的测试,测试好可用在手机的app,并通过合适的渠道发布出去(比如手机应用商店),那么,一个手机app的更新周期就算完成了
这里很明显的,交叉编译是专为跨平台的软件部署安装或者升级而采用的技术
二、
一般编译的大体不变的流程
1、从官网下载需要编译的目标软件源码
比如,各种Linux的内核源码,或者比如openssl的源码,通常编译工作都是升级软件,因此,需要下载符合自身需求的源码的版本
2、确定编译方式
选择一种自己比较熟悉的编译方式,比如本地编译或者交叉编译。如果能本地编译,自然是最好的,因为本地编译效率高,不太容易出错,例如,某个软件需要在arm架构服务器运行,直接找一个arm架构的服务器,在其上按下面的步骤编译完成就可以立刻使用了;交叉编译也就是需要在arm架构服务器运行的软件,在x86_64 服务器上编译,然后编译产出物移植,不仅步骤繁琐,而且编译环境搭建十分困难,稍有不慎就会失败
3、编译环境的搭建
通常编译环境指的是能够是编译工作正常运行的环境,比如c语言的源码包,肯定是需要安装相应的c语言编译器,通常是gcc和gcc-c++,而go语言的源码包通常需要go语言编译器
4、开始预编译
通常源码包都会提供编译配置脚本文件,一般名称为configure或者Configure,基本上90%的源码包都是采用这种形式,但有些源码包是使用cmake编译器直接编译
直接执行预编译脚本,也就是 ./configure 就可以默认编译,该过程主要是检查编译环境,检查编译过程需要的C语言库,类,头文件等等,并模拟预测正式编译,按照一般惯例,预编译阶段需要完全通过才可以进行下一步,并且一般需要通过不断的试错法调试预编译,直至该阶段工作完全通过
5、正式编译
通常执行命令为make 或者make -j 内核数 多线程加速编译,和预编译的关系是承上启下的关系,但可能还会检查一些环境,如果预编译成功,90%概率会直接通过,但可能会由于环境检查,发现依赖缺少而失败
6、编译安装
通常执行命令为make install ,此步骤是编译产出物,也是最终阶段,如果预编译和正式编译都通过的话,此阶段必定能够成功完成
7、编译产出物移植
例如,有两台配置基本相同的两个服务器,在A服务器上编译完成,生成了编译产出物后,将所有编译产出物复制到B服务器上后,就可以直接运行了,此时,通常不需要重复安装部署A服务器的编译环境这些,至多可能会出现缺少依赖库的问题,简单的处理一下就可以正常运行了
一般 4 5 6 步骤也简称为编译三连,以上基本是本地编译的流程
三、
交叉编译的流程
交叉编译需要工具链,主要工作是配置目标服务器的编译环境,然后在编译的时候,选择使用工具链
工具链比较复杂,一般是有现成的工具链,比如,Linaro Releases 该公司专注于工具链的制作,或者可以自己制作工具链来进行交叉编译
什么是交叉编译工具链
内核不同就需要交叉编译,在一个平台上生成另一个平台上的可执行代码。
在进行嵌入式系统的开发时,运行程序的目标平台通常具有有限的存储空间和运算能力,在目标平台进行编译很难实现,因为编译工具链需要很大的存储空间,而且需要很强的CPU运算能力,为了解决这个问题,交叉编译工具就诞生了。
通过交叉编译工具,我们就可以在CPU能力很强、存储空间足够的主机平台上(比如PC上)编译出针对其他平台的可执行程序。
🆗,现在以编译个hello world为例,说明交叉编译
目标:在这个x86虚拟机上,编译hello world,最终hello world可以在arm平台下正常运行
1、交叉编译工具链下载
在Linaro Releases 这个网站下载
gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz,然后将此压缩包在x86服务器上解压待用
2、配置环境变量
我是在root目录下解压,因此环境变量配置如下:
export PATH=$PATH:gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/
这一行写在/etc/profile 这个文件的末尾就可以了,然后激活环境变量 ,source /etc/profile 即可
可以查看aarch64-gcc的版本来确认该环境变量是否正确:
[root@localhost ~]# aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/root/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../libexec/gcc/aarch64-linux-gnu/7.3.1/lto-wrapper
Target: aarch64-linux-gnu
Configured with: '/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/snapshots/gcc.git~linaro-7.3-2018.05/configure' SHELL=/bin/bash --with-mpc=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/builds/destdir/x86_64-unknown-linux-gnu --with-mpfr=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/builds/destdir/x86_64-unknown-linux-gnu --with-gmp=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/builds/destdir/x86_64-unknown-linux-gnu --with-gnu-as --with-gnu-ld --disable-libmudflap --enable-lto --enable-shared --without-included-gettext --enable-nls --with-system-zlib --disable-sjlj-exceptions --enable-gnu-unique-object --enable-linker-build-id --disable-libstdcxx-pch --enable-c99 --enable-clocale=gnu --enable-libstdcxx-debug --enable-long-long --with-cloog=no --with-ppl=no --with-isl=no --disable-multilib --enable-fix-cortex-a53-835769 --enable-fix-cortex-a53-843419 --with-arch=armv8-a --enable-threads=posix --enable-multiarch --enable-libstdcxx-time=yes --enable-gnu-indirect-function --with-build-sysroot=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/sysroots/aarch64-linux-gnu --with-sysroot=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/builds/destdir/x86_64-unknown-linux-gnu/aarch64-linux-gnu/libc --enable-checking=release --disable-bootstrap --enable-languages=c,c++,fortran,lto --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu --target=aarch64-linux-gnu --prefix=/home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/aarch64-linux-gnu/_build/builds/destdir/x86_64-unknown-linux-gnu
Thread model: posix
gcc version 7.3.1 20180425 [linaro-7.3-2018.05 revision d29120a424ecfbc167ef90065c0eeb7f91977701] (Linaro GCC 7.3-2018.05)
3、
hello world的源码
创建名为HelloWorld.c的c语言源码,内容如下
cat HelloWorld.c
#include<stdio.h>
int main()
{
printf("hello world!\n");
}
4、
在x86服务器下编译这个HelloWorld.c文件
aarch64-linux-gnu-gcc HelloWorld.c -o HelloWorld
以上编译执行完毕后,会看到一个名为HelloWorld的文件,查看该文件属性,可以看到是aarch64的
[root@localhost ~]# file HelloWorld
HelloWorld: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=f9542f0847727ed5d58bcd53799e405ee2941185, not stripped
在x86服务器上,该文件不可执行,因为是arm架构的程序嘛
[root@localhost ~]# ./HelloWorld
-bash: ./HelloWorld: cannot execute binary file
5、
测试
将HelloWorld 这个文件传送到arm架构服务器上就可以正常输出helloworld了
🆗,一个简单的交叉编译就完成了
后续将就如何在x86架构编译新版本的arm架构的openssl和openssh做一个实践记录