使用目标三元组描述目标平台

cargo 在编译项目时,可以附加目标参数 --target <target triple> 设置项目的目标平台。平台包括硬件和软件支持,事实上,目标三元组(target triple) 包含:cpu 架构、供应商、操作系统和 ABI

安装 Rust 时,默认编译后的可执行文件要在本平台上执行,我们可以使用

rustc --version --verbose 来查看 Rust 的默认目标三元组:

  1. $ rustc --version --verbose
  2. rustc 1.42.0-nightly (859764425 2020-01-07)
  3. binary: rustc
  4. commit-hash: 85976442558bf2d09cec3aa49c9c9ba86fb15c1f
  5. commit-date: 2020-01-07
  6. host: x86_64-unknown-linux-gnu
  7. release: 1.42.0-nightly
  8. LLVM version: 9.0

host 处可以看到默认的目标三元组, cpu 架构为 x86_64 ,供应商为 unknown ,操作系统为 linux ,ABI 为 gnu 。由于我们是在 64 位 ubuntu 上安装的 Rust ,这个默认目标三元组的确描述了本平台。

官方对一些平台提供了默认的目标三元组,我们可以通过以下命令来查看完整列表:

  1. $ rustc --print target-list

目标三元组 JSON 描述文件

除了默认提供的以外,Rust 也允许我们用 JSON 文件定义自己的目标三元组。

首先我们来看一下默认的目标三元组 x86_64-unknown-linux-gnuJSON 文件描述,输入以下命令:

  1. $ rustc -Z unstable-options --print target-spec-json --target x86_64-unknown-linux-gnu

可以得到如下输出:

  1. // x86_64-unknown-linux-gnu.json
  2. {
  3. "arch": "x86_64",
  4. "cpu": "x86-64",
  5. "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
  6. "dynamic-linking": true,
  7. "env": "gnu",
  8. "executables": true,
  9. "has-elf-tls": true,
  10. "has-rpath": true,
  11. "is-builtin": true,
  12. "linker-flavor": "gcc",
  13. "linker-is-gnu": true,
  14. "llvm-target": "x86_64-unknown-linux-gnu",
  15. "max-atomic-width": 64,
  16. "os": "linux",
  17. "position-independent-executables": true,
  18. "pre-link-args": {
  19. "gcc": ["-Wl,--as-needed", "-Wl,-z,noexecstack", "-m64"]
  20. },
  21. "relro-level": "full",
  22. "stack-probes": true,
  23. "target-c-int-width": "32",
  24. "target-endian": "little",
  25. "target-family": "unix",
  26. "target-pointer-width": "64",
  27. "vendor": "unknown"
  28. }

可以看到里面描述了架构、 CPU 、操作系统、 ABI 、端序、字长等信息。

我们现在想基于 64 位 RISCV 架构开发内核,就需要一份 riscv64 的目标三元组。幸运的是,目前 Rust 编译器已经内置了一个可用的目标:riscv64imac-unknown-none-elf

我们查看一下它的 JSON 描述文件:

  1. $ rustc -Z unstable-options --print target-spec-json --target riscv64imac-unknown-none-elf
  1. // riscv64imac-unknown-none-elf.json
  2. {
  3. "abi-blacklist": [
  4. "cdecl",
  5. "stdcall",
  6. "fastcall",
  7. "vectorcall",
  8. "thiscall",
  9. "aapcs",
  10. "win64",
  11. "sysv64",
  12. "ptx-kernel",
  13. "msp430-interrupt",
  14. "x86-interrupt",
  15. "amdgpu-kernel"
  16. ],
  17. "arch": "riscv64",
  18. "code-model": "medium",
  19. "cpu": "generic-rv64",
  20. "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n64-S128",
  21. "eliminate-frame-pointer": false,
  22. "emit-debug-gdb-scripts": false,
  23. "env": "",
  24. "executables": true,
  25. "features": "+m,+a,+c",
  26. "is-builtin": true,
  27. "linker": "rust-lld",
  28. "linker-flavor": "ld.lld",
  29. "llvm-target": "riscv64",
  30. "max-atomic-width": 64,
  31. "os": "none",
  32. "panic-strategy": "abort",
  33. "relocation-model": "static",
  34. "target-c-int-width": "32",
  35. "target-endian": "little",
  36. "target-pointer-width": "64",
  37. "vendor": "unknown"
  38. }

我们来看它与默认的目标三元组有着些许不同的地方:

  1. "panic-strategy": "abort",

这个描述了 panic 时采取的策略。回忆上一章中,我们在 Cargo.toml 中设置程序在 panic 时直接 abort ,从而不必调用堆栈展开处理函数。由于目标三元组中已经包含了这个参数,我们可以将 Cargo.toml 中的设置删除了:

  1. -[profile.dev]
  2. -panic = "abort"
  3. -[profile.release]
  4. -panic = "abort"