# 交叉编译

作为一个嵌入式应用工程师，大部分程序都运行在目标设备上，虽然有各类SSH工具可以让开发者远程访问到开发板上进行快速开发，但交叉编译也是不可避免的一部分。[CMake官方文档](https://cmake.org/cmake/help/v3.6/manual/cmake-toolchains.7.html#cross-compiling-for-linux)给出了一个简单的例子，例子以树莓派为目标设备完成交叉编译链的配置，以下内容为补充说明。

```
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
​
set(CMAKE_SYSROOT /home/devel/rasp-pi-rootfs)
set(CMAKE_STAGING_PREFIX /home/devel/stage)
​
set(tools /home/devel/gcc-4.7-linaro-rpi-gnueabihf)
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)
​
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
```

* `CMAKE_SYSTEM_NAME`：CMake的标识符，表明目标设备的操作系统
* `CMAKE_SYSTEM_PROCESSOR`：CMake的标识符，表明目标设备的CPU架构
* `CMAKE_SYSROOT`：可选项，目标设备系统的根目录（系统源码？）
* `CMAKE_STAGING_PREFIX`：可选项，可能被用来指定项目在编译主机上的安装目录。和`CMAKE_INSTALL_PREFIX`不同，即使在交叉编译时，`CMAKE_INSTALL_PREFIX`始终是运行时安装路径。

  查到的一种解释是：

  * 当`CMAKE_STAGING_PREFIX`和`CMAKE_INSTALL_PREFIX`都设置了的时候，`CMAKE_STAGING_PREFIX`将覆盖`CMAKE_INSTALL_PREFIX`以免重置地址。
  * 开发者使用`CMAKE_STAGING_PREFIX`作为路径前缀将项目安装到host设备之后再使用其他方式将文件传入target设备中。
* `CMAKE_C_COMPILER`：目标设备的C编译器路径
* `CMAKE_CXX_COMPILER`：目标设备的C++编译器路径
* `CMAKE_FIND_ROOT_PATH`：CMake使用这个列表中的路径替代默认路径来查找包，库，头文件
* `CMAKE_FIND_ROOT_PATH_MODE_PROGRAM`：对应`find_program`，寻找可执行程序。通常而言调用可执行程序都是调用编译主机上的可执行程序，因此不需要从`CMAKE_FIND_ROOT_PATH`去找，一般都设置成`NEVER`
* `CMAKE_FIND_ROOT_PATH_MODE_LIBRARY`、`CMAKE_FIND_ROOT_PATH_MODE_INCLUDE`、`CMAKE_FIND_ROOT_PATH_MODE_PACKAGE`由于在进行交叉编译，所以需要使用目标设备平台下的库、头文件和包，因此一般都设置为`ONLY`

{% hint style="info" %}
为了方便跨平台构建编译，通常会将上述交叉编译工具链作为CMake的一个选项，即将对应平台下的交叉编译链分别保存在各自的`.cmake`配置文件中，CMake提供了一个`CMAKE_TOLLCHAIN_FILE`变量用于选择对应的目标平台。
{% endhint %}

例如，将上例指令保存为`arm.cmake`，在需要交叉编译时运行：

```
cmake -DCMAKE_TOOLCHAIN_FILE=./arm.cmake -H. -Bbuild
```
