DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1614万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

交叉编译指的在一个平台上生成另一个平台上的可执行代码。很多时候,开发的代码可能并不只是在开发主机的平台上执行,比如在Windows下开发的程序,希望能够在Linux、或者MacOS下执行;或者有时候目标平台根本就没有操作系统,没有对应的编译器,所以必然需要进行交叉编译。

交叉编译笔者在工作中经常会遇到。笔者开发使用的宿主机一般都是Linux(Ubuntu),交叉编译的目的基本都是为了将程序代码编译成目标嵌入式平台的库文件,然后再在目标系统上调用集成,一般都是ARM系列的CPU。而对于不同操作系统(Windows、Linux、MacOS)之间的交叉编译,则主要是为了编译示例程序,方便在不同操作系统上进行展示或者调试。

一 编译和CMake工具链

就像在前面的文章GCC编译过程概述中说的一样,目标文件的编译构建,其实是有很多个阶段的,每个阶段会使用不同的工具,比如特定语言的编译器、链接器、库文件操作工具等等,这也是GCC被称为编译工具套件的原因。

一般情况下,对于GCC来说,只需要使用命令行工具gcc或者g++就可以完成大部分工作,很多步骤都是被封装好的,套件内的不同工具会被适时地自动调用。

在CMake中,也是类似的概念,这些编译构建工具统称为工具链(toolchain),工具链基于不同的语言有不同配置,一般情况下,CMake会根据宿主机自动选择应该使用的工具链。

在进行交叉编译时,需要显式指定一个工具链文件,指明要使用的编译器、编译器的配置选项以及其他必要工具的路径

1 工具链文件

工具链文件(toolchain file)习惯上一般以.toolchain.cmake结尾。工具链文件的编写并不复杂,一般只需要指定以下这些CMake内置变量:

  1. CMAKE_SYSTEM_NAME:表明目标系统名称,比如LinuxQNXAndroid等;如果目标平台并没有系统,则应该指定为Generic;默认值为CMAKE_HOST_SYSTEM_NAME

  2. CMAKE_SYSTEM_PROCESSOR:表明目标平台架构,比如最常见的arm

  3. CMAKE_<LANG>_COMPILER:表明特定语言的要采用的编译器,需要使用完整路径,一般需要设置C语言编译器变量CMAKE_C_COMPILERC++编译器变量CMAKE_CXX_COMPILER

  4. CMAKE_<LANG>_FLAGS:设置特定编译器对应的编译选项,也可以使用add_compile_options为所有编译器设置相同的一些编译选项。

还有一些是可选的参数,根据目标平台的不同按需设置即可,大多数时候,cmake执行的时候会报错提示的~

下面是一个使用arm-none-eabi-gcc编译器的工具链文件示例:

 
 
set(CMAKE_SYSTEM_NAME Linux)
 
set(CMAKE_SYSTEM_PROCESSOR arm)
 
 
 
set(TOOLS /home/farmer/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux)
 
set(CMAKE_C_COMPILER "${TOOLS}/bin/arm-none-eabi-gcc")
 
set(CMAKE_CXX_COMPILER "${TOOLS}/bin/arm-none-eabi-g++")
 
set(CMAKE_AR "${TOOLS}/bin/arm-none-eabi-gcc-ar")
 
 
 
add_compile_options(-mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -g -Os -MMD -MP -Wall)
 
 

对于编译选项,需要结合项目实际开发情况。对于arm平台,比较重要的几个选项包括:

  1. -mcpu

  2. -mfpu

  3. -mfloat-abi

其他更多参数可以在GCC官网或者对应编译器官方查看。

这里是假定知道了arm-none-eabi-gcc所在路径,对于团队协作可能并不是很友好,写死的路径在不同开发者的机器上可能不一样。当然,对于编译都只在服务器进行的情况就没有关系了。

如果开发者将编译套件对应可执行文件目录添加到系统环境变量,那么也可以直接设置对应的编译器可执行文件名称,比如:

 
 
set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
 
set(CMAKE_CXX_COMPILER "arm-none-eabi-g++")

 

 

也可以通过find_program在系统路径下查找及指定的路径下查找对应的编译器可执行文件,再进行设置:

 
 
find_program(C_COMPILER "arm-none-eabi-gcc" ${SEARCH_PATHS})
 
find_program(CXX_COMPILER "arm-none-eabi-g++" ${SEARCH_PATHS})
 
set(CMAKE_C_COMPILER ${C_COMPILER})
 
set(CMAKE_CXX_COMPILER ${CXX_COMPILER})
 
 

二 CMake交叉编译

在需要进行交叉编译的时候,先编写一个适用于目标平台的工具链文件,然后在执行cmake命令开始构建时,可以使用参数--toolchain或者-DCMAKE_TOOLCHAIN_FILE=指定工具链文件的路径即可:

 
 
cmake ... --toolchain <path/to/toolchain-file>
 
or
 
cmake ... -DCMAKE_TOOLCHAIN_FILE=<path/to/toolchain-file>
 
 

所以交叉编译是比较简单的,一般只需要知道使用什么编译套件以及对应的配置

如果是交叉编译给Android平台使用的库,直接使用Android官方NDK中提供的toolchain就好。

使用Android toolchain路径一定要通过NDK所在目录指定:<NDK>/build/cmake/android.toolchain.cmake,因为它会使用相对路径访问NDK内部其他的资源,否则会出错。

 
posted on   DoubleLi  阅读(492)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2018-09-05 Socket调用Close后如何终止套接口的问题
2018-09-05 linux下recv 、send阻塞、非阻塞区别和用法
2018-09-05 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值---部分内容可能不确切,待讨论
2014-09-05 cmake手册详解----转
2012-09-05 基于Winsock API的VC网络编程实战
点击右上角即可分享
微信分享提示