交叉编译工具链和使用,制作安装包

交叉编译工具链

  • 为什么要交叉编译
  • 下载交叉编译工具链
  • 怎样选择工具链版本
    • 工具链的架构类型
    • 工具链的版本
    • 工具链里都有啥
  • 怎样交叉编译
  • 发布并制作目标设备安装包
    • 设置release模式
    • 直接拷贝
    • 制作安装包

基于实践的一些粗浅理解,望大拿们不吝校正。

为什么要交叉编译

对于arm或riscv等终端或边缘设备,由于性能较低,难以直接编译较大的工程(非常耗时,以至于无法承受)。通常我们需要在x86服务器上,对这些设备的软件程序进行交叉编译,快速生成目标文件和可执行文件。

下载交叉编译工具链

交叉编译所需要的编译环境,就要用到交叉编译工具链。
由于是在宿主服务器上,编译目标设备系统的目标文件,就需要匹配目标系统内核和编译器,而GCC又依赖于其他的一些库,因此需要一个完整闭环的依赖链,把这些东西做到一起,就是交叉编译工具链。
工具链中给出了对应目标设备系统上匹配的相关工具。可以根据目标设备的芯片类型和系统要求,选择对应的工具链下载包,参考:
https://toolchains.bootlin.com/

怎样选择工具链版本

工具链的架构类型

在目标设备上查看uname -a,确认目标系统的类型,选择对应的工具链类型,比如:
uname -a

工具链的版本

以aarch64 glibc工具链(https://toolchains.bootlin.com/releases_aarch64.html)为例,我们从下载列表上,可以看到对应的工具链版本中,对应的GCC,GDB,Linux headers,glibc,binutils版本号,这些工具其实就是工具链里主要的东西。所选择的工具链版本,尽可能与目标设备系统的内核版本和编译器版本一致(如果不能精确一致,则选择比目标设备系统编译器版本略低的工具链版本,向后兼容;如果编译器版本选定后,header版本比目标设备系统的内核版本高,则只能要求开发工程内核态程序代码自身做到兼容,否则交叉编译成功的目标文件可能会在目标设备系统上运行时报错。)
比如,使用cat /proc/version查看:
cat /proc/version
最主要的GCC版本是6.3.0,那么我们要选择的工具链版本,最好对应GCC的版本是6.3.0的就好,GCC所依赖的其他库也将可以一致兼容,而对应GCC为6.3.0的工具链版本,所含linux header的版本都比目标设备系统的内核版本高,则要求开发工程内核态代码的时候进行适配和测试。

工具链里都有啥

工具链里,主要是gcc和gcc依赖的各种库,以形成一个可以交叉编译的闭环依赖环境(除此之外,编译过程不需要其他东西,该有的都有)。下载一个工具链版本并在当前目录解压:

tar -zxvf aarch64--glibc--bleeding-edge.tat.gz

之后,我们进入目录看到工具链目录里包含如下一些文件和内容:
交叉编译工具链和使用,制作安装包_第1张图片
查看README即可看到工具链里包含的详细内容:
交叉编译工具链和使用,制作安装包_第2张图片

怎样交叉编译

对于使用cmake组织的工程,一切设置尽在CMakeLists.txt文件里,将对应的头文件和链接文件指向工具链中的对应目录即可(如果所要生成的工程既要在目标设备系统上执行,又要在编译服务器对应的系统上执行,则增加一个开关进行控制即可):

option(ARM_CROSS_COMPILE "compile on arm platform" OFF)

if(ARM_CROSS_COMPILE)

set(CMAKE_SYSTEM_NAME linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(TOOL_CHAINS_DIR /......{tool chains path}....../aarch64--glibc--bleeding-edge)
set(CMAKE_C_COMPILER ${TOOL_CHAINS_DIR}/bin/aarch64-linux-gcc)
set(CMAKE_CXX_COMPILER ${TOOL_CHAINS_DIR}/bin/aarch64-linux-g++)

set(CMAKE_FIND_ROOT_PATH ${TOOL_CHAINS_DIR})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH _MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH _MODE_INCLUDE ONLY)
include_directories(${TOOL_CHAINS_DIR}/include)
link_directories(${TOOL_CHAINS_DIR}/lib)
link_directories(${TOOL_CHAINS_DIR}/aarch64-buildroot-linux-gnu/lib64)
link_directories(${TOOL_CHAINS_DIR}/aarch64-buildroot-linux-gnu/sysroot/lib)
endif()

project(XXX)
# others

在执行cmake的时候,-D参数打开开关,就是在交叉编译环境执行编译:

mkdir build
cd build
cmake .. -DARM_CROSS_COMPILE
make
make install         #这会安装在宿主编译机上

发布并制作目标设备安装包

设置release模式

我们通常也适合设置一个开关,来发布release模式,不同模式的编译放在不同的目标路径

option(RELEASE "release version" OFF)
if(RELEASE)
    set(INSTALL_DIR ${CMAKE_HOME_DIRECTORY}/build/release)
    set(CMAKE_BUILD_TYPE Release)
else()
    set(INSTALL_DIR ${CMAKE_HOME_DIRECTORY}/build/debug)
    set(CMAKE_BUILD_TYPE Debug)
enfif()
set(INCLUDE_INSTALL_DIR $(INSTALL_DIR)/include)
set(LIB_INSTALL_DIR $(INSTALL_DIR)/lib)
set(SCRIPT_INSTALL_DIR $(INSTALL_DIR)/script)
set(BINARY_INSTALL_DIR $(INSTALL_DIR)/bin)

直接拷贝

在交叉编译以后,我们事实上可以将make出来的文件,直接拷贝到目标设备系统上去执行。
假如我们在cmake的时候,打开Release开关进行编译:

cmake .. -DARM_CROSS_COMPILE=ON -DRELEASE=ON
make
make install

那么我们编译完了,就把这个release目录里的文件拷贝到目标设备系统上去运行就可以了。

制作安装包

首先写一个arm_install.sh脚本,将整个release目录进行安装到某个系统目录并配置环境变量的过程,进行自动化实现。
然后,使用makeself工具(),将arm_install.sh脚本和相关release下的文件打包为.run文件,这样,执行.run文件的时候,相当于自动执行了.sh脚本,就是一个安装包了。

makeself --gzip release XXX.run "Tips info..." ./arm_install.sh

(关于makeself的安装和制作安装包过程,可参考:https://blog.csdn.net/fan_hai_ping/article/details/41276661)

你可能感兴趣的:(工程实践总结)