CMake 交叉编译
本文通过一个简单的示例,演示如何在 CMake 工程中添加交叉编译的配置,实现编译不同硬件平台的可执行文件。所有代码均可在 getiot/linux-c 仓库找到。
搭建工程
首先,编写一个最简单的 hello.c 文件:
hello.c
#include <stdio.h>
int main(void)
{
printf("Hello, GetIoT\n");
return 0;
}
创建一个 CMakeLists.txt 文件用于编译 hello.c 程序:
cmake_minimum_required(VERSION 3.1.3)
project(hello)
set( HELLO_SRCS hello.c)
add_executable(${PROJECT_NAME} ${HELLO_SRCS})
执行下面命令编译 x86-64 平台的可执行文件:
$ mkdir build
$ cd build
$ cmake .. && make
查看可执行文件描述:
$ file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5f92608723d5b497b773b56b366f4dada31c2318, for GNU/Linux 3.2.0, not stripped
方法一:增加选项
在 CMakeLists.txt 中通过 option
指令增加一个 CROSSCOMPILE_ENABLED
编译选项,默认为 OFF
,当设置为 ON
时将进行交叉编译。以 aarch64 作为目标平台为例,修改后的 CMakeLists.txt 文件如下。
cmake_minimum_required(VERSION 3.1.3)
project(hello)
set( HELLO_SRCS
hello.c
)
option( CROSSCOMPILE_ENABLED "Whether to build for arm" OFF)
if (CROSSCOMPILE_ENABLED)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(target_arch aarch64-linux-gnu)
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
set(CMAKE_LIBRARY_ARCHITECTURE ${target_arch} CACHE STRING "" FORCE)
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)
endif()
add_executable(${PROJECT_NAME} ${HELLO_SRCS})
编译时添加 CROSSCOMPILE_ENABLED
选项配置,如下:
$ cmake -DCROSSCOMPILE_ENABLED=ON ..
$ make
查看可执行文件描述:
$ file hello
hello: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=cc40eabf8479fde33c1d87e49431047dfdaee240, for GNU/Linux 3.7.0, not stripped
方法二:指定文件
在不修改 CMakeLists.txt 文件的情况下,可 以新增一个 arm_linux_setup.cmake 文件,将交叉编译的相关配置写在这里。例如:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(target_arch aarch64-linux-gnu)
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
set(CMAKE_LIBRARY_ARCHITECTURE ${target_arch} CACHE STRING "" FORCE)
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 的变量 CMAKE_TOOLCHAIN_FILE
来指定工具链文件,命令如下。
$ cmake -DCMAKE_TOOLCHAIN_FILE=../arm_linux_setup.cmake ..
$ make
查看可执行文件描述:
$ file hello
hello: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=cc40eabf8479fde33c1d87e49431047dfdaee240, for GNU/Linux 3.7.0, not stripped
配置说明
对于交叉编译,CMake 并不知道目标系统是什么,所以我们需要设置一些 CMake 变量来告诉 CMake。
CMAKE_SYSTEM_NAME
:即目标系统名,这里是 LinuxCMAKE_SYSTEM_PROCESSOR
:目标系统的处理器名,这里是 aarch64
对于工具链,则是通过下面两个变量来定位:
CMAKE_C_COMPILER
:C 编译器的可执行文件的路径CMAKE_CXX_COMPILER
:C++ 编译器的可执行文件的路径
实际上,上述这些变量可以在调用 CMake 时通过命令行传递,不过这样做很容易出错,而且用起来不方便。所以我们前面通过 option 选项和指定工具链文件的方式,将相关的变量传递给 CMake,这样用起来就方便很多。