要开始使用嵌入式系统,我们需要设置一个环境。 与我们用于桌面开发的环境不同,嵌入式编程环境需要两个系统:
- 构建系统:用于编写代码的系统
- 目标系统:您的代码将在其上运行的系统
在本章中,我们将学习如何设置这两个系统并将它们连接在一起。 构建系统的配置可能有很大差异-可能有不同的操作系统、编译器和 IDE。 目标系统配置的差异甚至更大,因为每个嵌入式系统都是独一无二的。 此外,虽然您可以使用笔记本电脑或台式机作为构建系统,但您确实需要某种类型的嵌入式主板作为目标系统。
要涵盖构建系统和目标系统的所有可能组合是不可能的。 相反,我们将只学习如何使用一种流行的配置:
- Ubuntu 18.04 作为构建系统
- 以树莓派为目标系统
我们将使用 Docker 在您的笔记本电脑或台式机上的虚拟环境中运行 Ubuntu。 Docker 支持 Windows、MacOS 和 Linux,但是,如果您已经在使用 Linux,您可以直接使用它,而无需在其上运行容器。
我们将使用Quick 模拟器(QEMU)来模拟 Raspberry PI 板。 这将教会我们如何在没有访问真实硬件的情况下为嵌入式主板构建应用。 考虑到在软件开发开始时目标硬件可能不可用,在仿真环境中执行开发的初始阶段是常见的,在许多情况下,这是唯一可能的实际解决方案。
**本章将介绍以下主题:
- 在 Docker 容器中设置构建系统
- 使用仿真器
- 交叉编译
- 连接到嵌入式系统
- 调试嵌入式应用
- 使用 gdbserver 进行远程调试
- 使用 CMake 作为构建系统
在本食谱中,我们将设置一个 Docker 容器,以便在您的台式机或笔记本电脑上运行 Ubuntu 18.04。 您的计算机上运行什么操作系统并不重要,因为 Docker 支持 Windows、MacOS 和 Linux。 作为这个菜谱的结果,您将拥有一个在您的主机操作系统中运行的统一的、虚拟化的 Ubuntu Linux 构建系统。
如果您的操作系统已经运行了 Ubuntu Linux,请随意跳到下一个食谱。
我们将在笔记本电脑或台式机上安装 Docker 应用,然后使用现成的 Ubuntu 镜像在虚拟环境中运行该操作系统:
- 在您的 Web 浏览器中,打开以下链接并按照说明为您的操作系统设置 Docker:
- 适用于 Windows:https://docs.docker.com/docker-for-windows/install/
- 对于 MacOS:https://docs.docker.com/docker-for-mac/install/
- 打开终端窗口(Windows 中的命令提示符,MacOS 中的终端应用)并运行以下命令以检查是否已正确安装:
$ docker --version
- 运行以下命令以使用 Ubuntu 映像:
$ docker pull ubuntu:bionic
- 创建工作目录。 在 MacOS、Linux Shell 或 Windows PowerShell 中,运行以下命令:
$ mkdir ~/test
- 现在,在容器中运行下载的镜像:
$ docker run -ti -v $HOME/test:/mnt ubuntu:bionic
- 接下来,运行
uname -a
命令以获取有关系统的信息:
# uname -a
您现在处于一个虚拟的 Linux 环境中,我们将在本书的后续菜谱中使用该环境。
在第一步中,我们安装 Docker-一个虚拟化环境,允许独立的 Linux 操作系统在 Windows、MacOS 或 Linux 上运行。 这是一种分发和部署容器的便捷方式,容器统一封装您使用的任何操作系统所需的所有库和程序。
安装 Docker 后,运行快速命令检查是否安装正确:
检查安装后,我们需要从 Docker 存储库中获取现成的 Ubuntu 镜像。 Docker 镜像有标签;我们可以使用bionic
标签查找 Ubuntu 版本 18.04:
下载图像需要时间。 获取映像后,我们可以创建一个目录,用于开发。 目录内容将在您的操作系统和运行在 Docker 中的 Linux 之间共享。 这样,您可以使用您喜欢的文本编辑器处理代码,但仍然可以使用 Linux 构建工具将代码编译成二进制可执行文件。
然后,我们可以使用步骤 4 中获取的 Ubuntu 镜像启动 Docker 容器。option -v $HOME/test:/mnt
命令行使在步骤 5 中创建的文件夹对 Ubuntu 可见为/mnt
目录。 这意味着您在~/test
目录中创建的所有文件都会自动出现在/mnt
中。 -ti
选项使容器具有交互性,使您可以访问 Linux shell 环境(Bash):
最后,我们对. uname
容器运行快速健全性检查,该检查显示有关 Linux 内核的信息,如下所示:
尽管您的内核的确切版本可能不同,但我们可以看到我们运行的是 Linux,我们的体系结构是x86
。 这意味着我们已经设置了构建环境,在那里我们将能够以统一的方式编译我们的代码,无论我们的计算机上运行什么操作系统。 但是,我们仍然不能运行编译后的代码,因为我们的目标架构是Acorn RISC Machines(ARM),而不是x86
。 在下一个食谱中,我们将学习如何设置模拟的 ARM 环境。
Docker 是一个功能强大且灵活的系统。 此外,它的存储库包含大量现成的图像,其中包含对大多数开发人员有用的工具。
转到https://hub.docker.com/search?q=&TYPE=IMAGE,浏览最受欢迎的图片。 您还可以使用关键字搜索图像,例如Embedded。
使用真正的嵌入式电路板并不总是可行或实用的-硬件还没有准备好,或者电路板的数量有限。 仿真器帮助开发人员使用尽可能接近目标系统的环境,但不依赖于硬件可用性。 这也是开始学习嵌入式开发的最佳方式。
在本食谱中,我们将学习如何设置 QEMU(硬件仿真器)并将其配置为模拟运行 Debian Linux 的基于 ARM 的嵌入式系统。
我们需要一个虚拟环境,与 Docker 不同,它可以用与我们计算机的体系结构不同的体系结构来模拟处理器:
- 导航到https://www.qemu.org/download/,单击与您的操作系统(Linux、MacOS 或 Windows)匹配的选项卡,然后按照安装说明进行操作。
- 除非已存在测试目录,否则请创建一个测试目录:
$ mkdir -p $HOME/raspberry
-
下载以下文件并将其复制到您在上一步中创建的
~/raspberry
目录:- Raspbian Lite zip-archive:http://downloads.raspbercrypi.org/raspbian_lite/image/raspbian_lite-2019-07-12/2019-07-10-raspbian-buster-lite.zip
- 内核映像e:HTTPS://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.14.79-stretch
- 设备树 Blob:https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/versatile-pb.dtb
-
将目录更改为
~/raspberry
并解压上一步下载的 Raspbian Lite zip 压缩文件。 它包含名为2019-07-10-raspbian-buster-lite.img
的单个文件。 -
打开终端窗口并运行 QEMU。 对于 Windows 和 Linux,命令行如下所示:
$ qemu-system-arm -M versatilepb -dtb versatile-pb.dtb -cpu arm1176 -kernel kernel-qemu-4.14.79-stretch -m 256 -drive file=2019-07-10-raspbian-buster-lite.img,format=raw -append "rw console=ttyAMA0 rootfstype=ext4 root=/dev/sda2 loglevel=8" -net user,hostfwd=tcp::22023-:22,hostfwd=tcp::9090-:9090 -net nic -serial stdio
- 应该会出现一个新窗口,显示 Linux 引导过程。 几秒钟后,将显示登录提示。
- 使用
pi
作为用户名,raspberry
作为密码登录。 然后,键入以下命令:
# uname -a
- 检查命令的输出。 这表明我们的系统架构是
ARM
,而不是x86
。 现在,我们可以使用此环境测试为 ARM 平台构建的应用。
在第一步中,我们安装 QEMU 仿真器。 如果没有可加载的代码镜像,这个虚拟机就没有多大用处。 然后,我们可以获取运行 Linux 操作系统所需的三个镜像:
- Linux 根文件系统:包含在 Raspberry PI 设备上使用的 Raspbian Linux 的快照
- Linux 内核
- 设备树 blob:包含系统硬件组件的描述
获取所有图像并将其放入~/raspberry
目录后,我们运行 QEMU,将图像的路径作为命令行参数提供。 此外,我们还配置了虚拟网络,它允许我们从本机环境连接到在虚拟环境中运行的 Linux 系统。
QEMU 启动后,我们可以看到一个带有 Linux 登录提示的窗口:
登录系统后,我们可以通过运行uname
命令来运行快速健全性检查:
与我们在前面的食谱中运行的健全性检查类似,在 Docker 容器中设置构建系统,这表明我们运行的是 Linux 操作系统,但在本例中,我们可以看到目标架构是ARM
。
QEMU 是一个功能强大的处理器仿真器,除了 x86 和 ARM 之外,它还支持其他多种架构,例如 PowerPC、SPARC64、SPARC32 和微处理器,没有互锁的流水线级(MIPS)。 它之所以如此强大的一个方面是它的灵活性,因为它有许多配置选项。 请转到https://qemu.weilnetz.de/doc/qemu-doc.html,根据需要配置 QEMU。
微控制器供应商也经常提供仿真器和仿真器。 开始针对特定硬件进行开发时,请检查可用的仿真选项,因为这可能会显著影响开发时间和工作量。
我们已经了解到嵌入式开发环境由两个系统组成:编写和构建代码的构建系统和运行代码的主机系统。
我们现在设置了两个虚拟化环境:
- Docker 容器中的 Ubuntu Linux,它将成为我们的构建系统
- 运行 Raspbian Linux 的 QEMU,它将成为我们的主机系统
在本食谱中,我们将设置为 ARM 平台构建 Linux 应用所需的交叉编译工具,并构建一个简单的*Hello,world!*应用来测试设置。
要设置交叉编译工具包,我们需要使用 Ubuntu Linux,我们在设置 Docker 容器中的构建系统食谱中设置了 Ubuntu Linux。
我们还需要~/test
目录来在操作系统和 Ubuntu 容器之间交换源代码。
让我们从创建一个简单的 C++ 程序开始,我们希望为我们的目标平台编译该程序:
- 在
~/test
目录中创建名为hello.cpp
的文件。 - 使用您最喜欢的文本编辑器将以下代码片段添加到其中:
#include <iostream>
int main() {
std::cout << "Hello, world!" << std::endl;
return 0;
}
- 现在我们有了
Hello, world!
程序的代码,我们需要编译它。 - 切换到 Ubuntu(我们的构建系统)控制台。
- 通过运行以下命令获取可用于安装的最新软件包列表:
# apt update -y
- 从 Ubuntu 服务器获取包描述需要一些时间。 运行以下命令安装交叉编译工具:
# apt install -y crossbuild-essential-armel
- 您将看到要安装的软件包的长长列表。 按Y确认安装。作为健康检查,请运行不带参数的交叉编译器:
# arm-linux-gnueabi-g++
- 将目录更改为
/mnt
# cd /mnt
- 我们在步骤 1 中创建的
hello.cpp
文件位于此处。 现在让我们构建它:
# arm-linux-gnueabi-g++ hello.cpp -o hello
- 此命令生成名为
hello
的可执行文件。 您可能会感到奇怪,为什么它没有任何扩展名。 在 UNIX 系统中,扩展是完全可选的,并且二进制可执行文件通常没有任何扩展名。 尝试运行该文件。 它应该会失败,并出现错误。 - 让我们使用
file
工具生成有关可执行二进制文件的详细信息。
在第一步中,我们创建了一个简单的*Hello,World!*C++ 程序。 我们将其放入~/test
目录,这样就可以从运行 Linux 的 Docker 容器访问它。
为了构建源代码,我们切换到了 Ubuntu shell。
如果我们尝试运行标准的 Linux g++ 编译器来构建它,我们将得到构建平台的可执行文件,即 x86。 但是,我们需要 ARM 平台的可执行文件。 要构建它,我们需要一个可以在 x86 上运行的编译器版本,构建 ARM 代码。
作为第一步,我们需要更新 Ubuntu 软件包发行版中提供的软件包信息:
我们可以通过运行apt-get install crossbuild-essential-armel
来安装该编译器以及一组相关工具:
步骤 9 中执行的快速健全性检查显示它已正确安装:
现在,我们需要使用交叉编译器构建hello.cpp
。 它为 ARM 平台生成可执行文件,这就是我们在步骤 12 中尝试在构建系统中运行它失败的原因。
为了确保它真的是 ARM 可执行文件,我们需要运行file
命令。 其输出如下:
如您所见,该二进制文件是为 ARM 平台构建的,这就是它无法在构建系统上运行的原因。
存在许多适用于各种体系结构的交叉编译工具包。 其中一些可以在 Ubuntu 存储库中随时获得;有些可能需要手动安装。
使用交叉编译器在构建系统上构建嵌入式应用后,应该将其传输到目标系统。 在基于 Linux 的嵌入式系统上实现这一点的最佳方式是使用网络连接和远程 shell。 安全外壳(SSH)因其安全性和通用性而被广泛使用。 它不仅允许您在远程主机上运行 shell 命令,还允许您使用加密加密和基于密钥的身份验证将文件从一台计算机复制到另一台计算机。
在本食谱中,我们将学习如何使用 Secure Copy 将应用二进制文件复制到模拟的 ARM 系统,使用 SSH 连接到它,并在 SSH 中运行可执行文件。
我们将使用我们在使用仿真器配方中设置的 Raspberry PI 仿真器作为我们的目标系统。 此外,我们还需要我们的 Ubuntu 构建系统和我们在交叉编译配方中构建的可执行文件hello
。
我们将通过网络访问我们的目标系统。 QEMU 为仿真机器提供了一个虚拟网络接口,我们可以在不连接到真实网络的情况下使用它。 为此,我们需要找出要使用的 IP 地址,并确保 SSH 服务器在我们的虚拟环境中运行:
在您的本机操作系统环境中,计算出您的计算机的 IP 地址。 打开终端窗口或 PowerShell。 在 MacOS 或 Linux 上运行ifconfig
,或在 Windows 上运行ipconfig
,并检查其输出。
在接下来的步骤中,我们将使用192.168.1.5
作为模板 IP 地址;您需要将其替换为您的实际 IP 地址。
- 通过运行以下命令切换到 Raspberry PI 仿真器并启用 SSH 服务:
$ sudo systemctl start ssh
- 切换到 Ubuntu 窗口,安装 SSH 客户端:
# apt install -y ssh
- 现在,我们可以将
hello
可执行文件复制到目标系统:
# scp -P22023 /mnt/hello pi@192.168.1.5:~
- 当要求输入密码时,键入
raspberry
。 切换回 Raspberry PI 仿真器窗口。 检查我们刚刚复制的可执行文件是否存在:
$ ls hello
hello
- 现在,运行该程序:
$ ./hello
正如我们所看到的,程序现在正在按预期运行。
在本配方中,我们使用 SSH 在两个虚拟环境(Docker 和 QEMU)之间设置数据交换。 为此,我们需要在目标系统(QEMU)上运行并接受连接的 SSH 服务器,以及在构建系统上启动连接的 SSH 客户端。
在步骤 2 中,我们在构建系统上设置 SSH 客户端。 我们的目标系统在 QEMU 中运行,已经启动并运行了一台 SSH 服务器。 在使用仿真器配方期间,我们将 QEMU 配置为将连接从主机端口22023
转发到虚拟机端口22
,即 SSH。
现在,我们可以使用scp
使用安全网络连接将文件从构建系统复制到目标系统。 我们可以将为 QEMU 转发配置的系统 IP 地址(在步骤 1 中发现)和端口22023
指定为scp
要连接到的参数:
复制文件后,我们可以使用 SSH 登录到目标系统,使用与scp
相同的 IP 地址、端口和用户名。 它会打开一个类似于本地控制台的登录提示符,在授权之后,我们会得到与本地终端相同的命令 shell。
我们在上一步中复制的hello
应用应该在home
目录中可用。 我们在步骤 5 中通过运行ls
命令检查了这一点。
最后,我们可以运行应用:
当我们尝试在构建系统上运行它时,收到一个错误。 现在,输出是Hello, world!
。 这正是我们所期望的,因为我们的应用是为 ARM 平台构建的,并且在 ARM 平台上运行。
尽管我们运行了连接到仿真系统的配方,但同样的步骤也适用于真正的嵌入式系统。 即使目标系统没有显示器,您也可以使用串行控制台连接设置 SSH。
在本配方中,我们只将文件复制到目标系统。 除了复制之外,通常的做法是打开到嵌入式系统的交互式 SSH 会话。 通常,它比串行控制台使用起来更高效、更方便。 它的建立方式类似于scp
:
# ssh pi@192.168.1.5 -p22023
SSH 提供各种身份验证机制。 启用并设置公钥身份验证后,无需为每次复制或登录都键入密码。 这为开发人员提供了更快、更方便的开发过程。
要了解有关 ss 键的更多信息,请访问https://www.ssh.com/ssh/key/。
调试嵌入式应用在很大程度上取决于目标嵌入式系统的类型。 微控制器制造商通常为其微控制器单元(MCU)提供专用调试器,并使用联合测试行动小组(JTAG)协议为远程调试提供硬件支持。 它允许开发人员在 MCU 开始执行指令后立即调试微控制器代码。
如果目标板运行 Linux,最实用的调试方法是使用广泛的调试输出,并使用 gdb 作为交互式调试器。
在本食谱中,我们将学习如何在命令行调试器 gdb 中运行我们的应用。
我们已经了解了如何将可执行文件传输到目标系统。 我们将使用连接到嵌入式系统配方作为起点,学习如何在目标系统上使用调试器。
我们已经学习了如何将应用复制到目标系统并在那里运行。 现在,让我们学习如何使用 gdb 开始在目标系统上调试应用。 在本菜谱中,我们将只学习如何调用调试器并在调试器环境中运行应用。 稍后将作为更高级、更实用的调试技术的基础:
- 切换到
QEMU
窗口。 - 如果您尚未登录,请使用
pi
作为用户名,使用raspberry
作为密码进行登录。 - 运行以下命令:
$ gdb ./hello
- 这将打开
gdb
命令行。 - 键入
run
以运行应用:
(gdb) run
- 您应该在输出中看到
Hello, world
。 - 现在,运行
quit
命令,或者只运行q
:
(gdb) q
这将终止调试会话,并将我们返回到 Linux shell。
我们用于仿真的 Raspberry PI 映像附带了一个预装的 GNU 调试器,因此我们可以立即使用它。
在home
用户目录中,我们应该找到hello
可执行文件,它是作为连接到嵌入式系统配方的的一部分从我们的构建系统复制的。
我们运行gdb
,将路径作为参数传递给hello
可执行文件。 此命令打开gdb
外壳,但不运行应用本身。 要运行它,我们键入run
命令:
应用运行,在屏幕上打印Hello world!
消息,然后终止。 但是,我们仍在调试器中。 要退出调试器,我们键入quit
命令:
您可以看到命令行提示符已更改。 这表明我们不再处于gdb
环境中。 我们已经返回到 Raspberry PI Linux 的默认 shell 环境,我们在运行 gdb 之前使用该环境。
在这种情况下,预先安装了 GNU 调试器,但它可能不在您的实际目标系统中。 如果它是基于 Debian 的,您可以通过运行以下命令来安装它:
# apt install gdb gdb-multiarch
在其他基于 Linux 的系统中,安装 gdb 需要不同的命令。 在许多情况下,您需要从源代码构建它并手动安装,类似于我们作为本章食谱的一部分构建和测试的hello
应用。
在本文中,我们只学习了如何使用 gdb 运行应用,gdb 是一个包含大量命令、技术和最佳实践的复杂工具。 我们将在第 5 章,调试、日志记录和性能分析中讨论其中的一些内容。
正如我们已经讨论过的,嵌入式开发环境通常包括两个系统-构建系统和目标系统(或仿真器)。 有时,由于远程通信的高延时,在目标系统上进行交互式调试是不切实际的。
在这种情况下,开发人员可以使用 GDB 提供的远程调试支持。 在此设置中,使用gdbserver在目标系统上启动嵌入式应用。 开发人员在构建系统上运行 gdb,并通过网络连接到 gdbserver。
在本食谱中,我们将学习如何使用 gdb 和 gdbserver 开始调试应用。
在连接到嵌入式系统秘诀中,我们了解了如何使我们的应用在目标系统上可用。 我们将使用该配方作为学习远程调试技术的起点。
我们将安装并运行 gdbserver 应用,这将允许我们在构建系统上运行 gdb,并将所有命令转发到目标系统。 切换到 Raspberry PI 仿真器窗口。
- 使用
raspberry
密码以pi
身份登录,除非您已经登录。 - 要安装 gdbserver,请运行以下命令:
# sudo apt-get install gdbserver
- 在
gdbserver
下运行hello
应用:
$ gdbserver 0.0.0.0:9090 ./hello
- 切换到构建系统终端,将目录切换到
/mnt/hello
:
# cd /mnt/hello
- 安装
gdb-multiarch
软件包,该软件包为 ARM 平台提供必要的支持:
# apt install -y gdb-multiarch
- 接下来,运行
gdb
:
# gdb-multiarch -q ./hello
- 通过在
gdb
命令行中键入以下命令来配置远程连接(请确保将192.168.1.5
替换为您的实际 IP 地址):
target remote 192.168.1.5:9090
- 键入以下命令:
continue
程序现在将运行。
在我们使用的 Raspberry PI 镜像中,默认情况下没有安装gdbserver
。 因此,作为第一步,我们安装gdbserver
:
安装完成后,我们运行gdbserver
,传递需要调试的应用的名称、IP 地址和侦听传入连接的端口作为其参数。 我们使用0.0.0.0
作为 IP 地址,表示我们希望接受任何 IP 地址上的连接:
然后,我们切换到构建系统并在那里运行gdb
。 但是,我们没有直接在 gdb 中运行应用,而是指示gdb
使用提供的 IP 地址和端口启动到远程主机的连接:
之后,您在gdb
提示符下键入的所有命令都将传输到 gdbserver 并在那里执行。 当我们运行应用时,我们将在构建系统的gdb
控制台中看到结果输出,即使我们运行 ARM 可执行文件:
解释很简单--二进制文件在远程 ARM 系统上运行:我们的 Raspberry PI 仿真器。 这是在目标平台上调试应用的一种便捷方式,使您可以保持在构建系统更舒适的环境中。
确保您正在使用的 gdb 和 gdbserver 的版本匹配,否则它们之间的通信可能会出现问题。
在前面的食谱中,我们学习了如何编译由一个 C++ 文件组成的程序。 然而,真正的应用通常具有更复杂的结构。 它们可以包含多个源文件,依赖于其他库,并且可以拆分成独立的项目。
我们需要一种方法来方便地为任何类型的应用定义构建规则。 CMake 是最广为人知、使用最广泛的工具之一,它允许开发人员定义高级规则并将其转换为较低级别的构建系统,如 Unix Make。
在本食谱中,我们将学习如何设置 CMake 并为我们的*Hello,world!*应用创建一个简单的项目定义。
如前所述,常见的嵌入式开发工作流包括两个环境:构建系统和目标系统。 CMake 是构建系统的一部分。 我们将使用 Ubuntu 构建系统作为起点,它是通过在 Docker 容器配方中设置构建系统而创建的。
- 我们的构建系统还没有安装 CMake。 要安装它,请运行以下命令:
# apt install -y cmake
- 切换回您的本机操作系统环境。
- 在
~/test
目录中,创建子目录hello
。 使用您喜欢的文本编辑器在hello
子目录中创建名为CMakeLists.txt
的文件。 - 输入以下行:
cmake_minimum_required(VERSION 3.5.1)
project(hello)
add_executable(hello hello.cpp)
- 保存文件并切换到 Ubuntu 控制台。
- 切换到
hello
目录:
# cd /mnt/hello
- 运行 CMake:
# mkdir build && cd build && cmake ..
- 现在,通过运行以下命令构建应用:
# make
- 使用
file
命令获取有关生成的可执行二进制文件的信息:
# file hello
- 如您所见,构建是 x86 平台的原生版本。 我们需要添加交叉编译支持。 切换回文本编辑器,打开
CMakeLists.txt
,并添加以下行:
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-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)
- 保存并切换到 Ubuntu 终端。
- 再次运行
cmake
命令以重新生成构建文件:
# cmake ..
- 通过运行
make
构建代码:
# make
- 再次检查结果输出文件的类型:
# file hello
现在,我们已经使用 CMake 为我们的目标系统构建了一个可执行文件。
首先,我们在构建系统中安装 CMake。 安装完成后,我们切换到本机环境来创建CMakeLists.txt
。 此文件包含有关项目组成和属性的高级生成说明。
我们将项目命名为hello,它从名为hello.cpp
的源文件创建名为hello
的可执行文件。 此外,我们还指定了构建应用所需的 CMake 的最低版本。
在我们创建了项目定义之后,我们可以切换回构建系统外壳,并通过运行make
来生成低级构建指令。
通常的做法是创建一个专用的构建目录来保存我们所有的构建构件。 通过这样做,编译器生成的目标文件或 CMake 生成的文件不会污染源代码目录。
在单个命令行中,我们创建一个build
目录,切换到新创建的目录,然后运行 CMake。
我们将父目录作为参数传递,让 CMake 知道在哪里查找CMakeListst.txt
:
默认情况下,CMake 为传统的 Unixmake
实用程序生成Makefile
文件。 我们运行make
来实际构建应用:
它可以工作,但会生成为 x86 平台构建的可执行二进制文件,而我们的目标系统是 ARM:
为了解决这个问题,我们在CMakeLists.txt
文件中添加了几个选项来配置交叉编译。 再次重复构建步骤,我们得到一个新的hello
二进制文件,现在用于 ARM 平台:
正如我们在file
命令的输出中看到的那样,我们构建的是 ARM 平台的可执行文件,而不是用作构建平台的 x86。 这意味着该程序不会在构建机器上运行,但可以成功地复制到我们的目标平台上并在那里运行。
为 CMake 配置交叉编译的最佳方式是使用所谓的工具链文件。 工具链文件定义特定于特定目标平台的构建规则的所有设置和参数,例如编译器前缀、编译标志和在目标平台上预先构建的库的位置。 可以使用不同的工具链文件为不同的目标平台重建应用。 有关详细信息,请参阅https://cmake.org/cmake/help/v3.6/manual/cmake-toolchains.7.html上的 Cmake 工具链文档。**