Skip to content

Commit fd1a539

Browse files
feat(freestanding): Cortex-M 七个目标行 + 死代码段消除 (2026.9.4.1) (#550)
* feat(freestanding): Cortex-M as seven target rows, and dead-section elimination (2026.9.4.1) The bare-metal target table grows from four rows to eleven. M-profile is seven rows rather than one: an object built for `thumbv7em` uses instructions a Cortex-M0 does not have, so the two spellings produce incompatible objects rather than expressing a preference. The table exists so that `--target <triple>` alone suffices to produce a correct object file, and a single `arm-none-eabi` row plus an `-mcpu` each project remembered would move a correctness decision out of the table and into every manifest. ⚠️ The float ABI does not settle whether the FPU is used. clang derives `-mfloat-abi` from the `eabi`/`eabihf` suffix without help, but that governs how floating-point values cross a function boundary, not what the compiler may emit inside one — and `thumbv7em` implies FPv4-SP. Measured on llvm 22.1.8: under the soft-float ABI clang still emits `vmul.f32` for a float multiply, which faults at run time on a Cortex-M4 with no FPU after a clean compile and a clean link. Every soft-float row therefore carries `-mfpu=none`, including the rows whose architecture has no FPU at all — a row states the property it guarantees rather than inheriting it from a default that is free to change. The uniform form was not the first draft: the flag was initially applied only where a non-zero instruction count had been observed, which made the table record a measurement rather than a guarantee, and the unit test quantified over the rows caught it. Freestanding builds now compile with `-ffunction-sections -fdata-sections` and link with `--gc-sections`, on both the driver path and the direct `ld.lld` path. Both halves belong to the engine because a dependency's translation units must carry them and a project cannot reach those. The flags became necessary rather than economical when a C library began arriving from the dependency graph: a dependency's object files enter a link unconditionally, unlike an archive member pulled only while its symbol is undefined, and a Cortex-M part has kilobytes where the existing bare-metal rows had megabytes. ⚠️ A linker script becomes load-bearing in a new way. An interrupt vector table is referenced by nothing — the hardware reads it by address — so `--gc-sections` collects it, and a board's script must say `KEEP(*(.vectors))`. The tier column records what was run. Four rows booted under `xim:qemu-arm@9.2.4-1` and printed over semihosting: thumbv6m on `microbit`, thumbv7m on `mps2-an385`, thumbv7em-eabihf on `mps2-an386`, thumbv8m.main-eabi on `mps2-an505`. The remaining three build and link and are marked `preview`. `lldEmulation` is empty on every M-profile row: clang has a BareMetal toolchain for arm, so these triples reach `ld.lld` through the driver as the RISC-V and aarch64 rows do, and the x86_64 row's workaround does not recur. `mcmodel` is empty because 32-bit ARM has no such axis. Coverage: * `tests/e2e/332_cortex_m_builds_and_boots.sh` boots the four verified rows, asserts a function nothing calls is absent while the vector table survives, and measures the float ABI from both sides — the hard row's FPU instruction count and the soft row's link failure naming `__aeabi_fmul`, which states that the multiply did not become an FPU instruction. Both guards were confirmed to fail independently against a reverted engine. * Three unit tests state the rules the e2e cannot: every soft row disables the FPU and no hard row does (with both halves counted, so neither is vacuous), M-profile rows need no code model and no direct lld driving, and every freestanding row compiles with per-function sections. * The script declares `# requires: qemu-arm`, which no sharded runner has, so it is invoked directly from the `baremetal` job where its PASS line and a count of four booted rows can both be demanded. Also backfills two claims in docs/13 that 2026.8.28.2 had already overturned: exceptions, RTTI and `import std` are available on a freestanding target when a package provides `hosted-standard-library`. The document had continued to state them as unconditional limitations, which would lead a reader to abandon a capability that already works. * docs: sync the target tables in README and docs/16 with the seven new rows Both mirror kKnownTargets and would otherwise describe a four-row bare-metal table that no longer exists. The README's legend for a verified row is that CI builds AND executes the artifact, which the baremetal job now does for the four rows marked so. * test(e2e): register qemu-arm in KNOWN_CAPS The harness validates every `# requires:` token against a master list before running anything, so a capability that is only added to the Linux detection branch aborts every suite on every platform. CI caught it: the msvc job failed with "declares unknown capability 'qemu-arm'" while the bare-metal job — the one that has the emulator — passed. That is the guard working. A token absent from this list would otherwise match nothing and the test would skip everywhere while looking supported. * docs(plan): 商业级裸机/嵌入式总体方案,并回填 P0 的实施状态 方案文档此前只存在于工作副本里,没有进入 PR —— 而它是本次改动的依据,读者要靠 它才能知道七个目标行与 --gc-sections 为什么是同一批。 §10 记下实施推翻方案的两处:extra 列承载的是 -mfpu=none 而不是方案写的 -mfloat-abi(triple 已经承载了浮点 ABI),以及行数是七不是六。 * revert(freestanding): drop dead-section elimination from this change ⚠️ MEASURED TO BREAK A JOB THAT IS GREEN ON main, BY A MECHANISM THAT CONTRADICTS THE CODE, WHICH IS REASON ENOUGH NOT TO SHIP IT. `--gc-sections` was correct on this machine and in the bare-metal CI job. It broke the openkal cross-build on a WINDOWS host: lld: error: unable to find library -lntdll (and four more) Three-way control, not reasoning: main, via workflow_dispatch build 3 targets on windows ✅ this PR, with gc-sections (three runs) ❌ bisect/no-gc-sections, that change alone reverted ✅ And the result contradicts the model. Both call sites sit inside `isFreestandingTarget`, which `x86_64-windows-gnu` does not satisfy; the same cross-build succeeds on a Linux host; and the `-Wl,--gc-sections` visible in the failing link line was traced to openkal-windows' own manifest rather than to the engine. The actual symptom is a MISSING `-L` for the directory holding the import libraries that package generates. So the mechanism is not understood, and an unexplained change does not belong in a release. The flags are removed here and the finding is recorded in `.agents/docs/2026-09-04-…-plan.md` §10.1 with the control that establishes it, because dead-section elimination remains a prerequisite for a C library supplied from the dependency graph. The Cortex-M rows do not depend on it: they build, link and boot without it, and the e2e still asserts the vector table is present and the float ABI is honoured on both sides. Only the two dead-code assertions are withdrawn. * test(matrix): the support matrix declares the seven M-profile rows ⭐ AND THE SCAN'S OWN PREDICATE WAS A SPELLING RATHER THAN A PROPERTY, IN TWO PLACES. `scan.sh` decided "is this a bare-metal target" with `grep -- '-none-elf$'`. That is the environment field of four particular rows, not the question being asked. Cortex-M spells the same OS `-none-eabi` and `-none-eabihf`, so both copies of the rule fell through: * the probe source picked the hosted branch and emitted `#include <cstdio>` for a target with no C library, producing a column of `build-failed` that described the probe rather than the target — precisely the defect the comment three lines above it already records; * the graph-mode skip did not skip, so fourteen cells were measured for a combination the same file declares out of scope. Both now ask the OS field. This is the shape recorded as "one rule, two copies: change one and you will miss the other", and it is why the rows are added by MEASURING with the fixed scan rather than by writing them out. The 42 payload rows are the live scan's output, verified by `compare.sh` for both modes. Graph mode contributes none, which is the declaration the file already made for every other bare-metal row. * Revert "revert(freestanding): drop dead-section elimination" The removal rested on a false signal. Reverting gc-sections made one CI run green, and that was taken as cause; the full control matrix says otherwise: main ×2 ✅ main + the seven rows ✅ main + the version bump ✅ this PR minus the version bump ✅ this PR, with AND without gc-sections, ×5 ❌ a branch holding BYTE-IDENTICAL code to the PR ✅ ← the decisive one The last row rules out every code-level explanation. The cause is GitHub Actions cache scoping: a branch reads its own cache before falling back to the default branch's, and this branch's first run — aborted by the unregistered `qemu-arm` capability — saved a half-populated sandbox that every later run on it then restored. Fresh bisect branches had no cache of their own and fell back to main's, which is why each of them passed and none of them exonerated anything. ⭐ Recorded in the plan document: when every single factor passes in isolation and the combination still fails, the next question is whether the criterion is being decided by the environment — not which factor to split next. * docs(triple): drop a sentence the table had outgrown Self-review: the paragraph above the M-profile rows still said "two rows are verified", written when two were. Four boot under QEMU and the block directly below already names all four, so the sentence contradicted the table two lines under it — the kind of stale count a reader trusts because it reads like a summary. --------- Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent dfa431f commit fd1a539

17 files changed

Lines changed: 1211 additions & 89 deletions

File tree

.agents/docs/2026-09-04-commercial-grade-baremetal-embedded-plan.md

Lines changed: 473 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/ci-linux-e2e.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ jobs:
114114
# test, and assert its PASS line appeared. A skip fails this job.
115115
# ──────────────────────────────────────────────────────────────────
116116
baremetal:
117-
name: bare-metal e2e (riscv64-none-elf, qemu)
117+
name: bare-metal e2e (riscv64-none-elf + cortex-m, qemu)
118118
runs-on: ubuntu-24.04
119119
timeout-minutes: 40
120120
env:
@@ -153,6 +153,18 @@ jobs:
153153
XLINGS_HOME="${MCPP_HOME:-$HOME/.mcpp}/registry" \
154154
"$XLINGS_BIN" install xim:picolibc-riscv -y
155155
test -d "${MCPP_HOME:-$HOME/.mcpp}/registry/data/xpkgs/xim-x-picolibc-riscv"
156+
# ⚠️ The M-profile emulator, in BOTH homes for the reason above.
157+
# `xim:qemu-arm` carries `qemu-system-arm` as well as
158+
# `qemu-system-aarch64`; test 332 addresses it by absolute path out of
159+
# the payload, so what matters is that the payload EXISTS in the home
160+
# mcpp uses rather than that a shim resolves.
161+
"$XLINGS_BIN" install xim:qemu-arm -y
162+
XLINGS_HOME="${MCPP_HOME:-$HOME/.mcpp}/registry" \
163+
"$XLINGS_BIN" install xim:qemu-arm -y
164+
# Reachable AND runnable before the tests, so that a missing emulator
165+
# fails this step rather than silently skipping test 332.
166+
ls "${MCPP_HOME:-$HOME/.mcpp}"/registry/data/xpkgs/xim-x-qemu-arm/*/bin/qemu-system-arm \
167+
| sort -V | tail -1 | xargs -I{} {} --version | head -1
156168
157169
- name: Bare-metal e2e
158170
timeout-minutes: 25
@@ -175,7 +187,8 @@ jobs:
175187
for t in tests/e2e/130_freestanding_riscv_build_and_run.sh \
176188
tests/e2e/131_freestanding_bsp_supplies_everything.sh \
177189
tests/e2e/132_freestanding_test_and_artifacts.sh \
178-
tests/e2e/133_freestanding_std_subset.sh; do
190+
tests/e2e/133_freestanding_std_subset.sh \
191+
tests/e2e/332_cortex_m_builds_and_boots.sh; do
179192
echo "=== $t ==="
180193
bash "$t" 2>&1 | tee "$(basename "$t").log"
181194
rc=${PIPESTATUS[0]}
@@ -196,6 +209,18 @@ jobs:
196209
grep -q 'PASS: the freestanding std subset' \
197210
133_freestanding_std_subset.sh.log || {
198211
echo "133 (std subset) skipped on the runner that must run it"; exit 1; }
212+
# ⚠️ 332 declares `# requires: qemu-arm`, which no sharded runner has
213+
# — so on the shards it exits 0 without running. This job is the only
214+
# place its PASS line can be demanded.
215+
grep -q 'PASS: cortex-m rows build, boot' \
216+
332_cortex_m_builds_and_boots.sh.log || {
217+
echo "332 (cortex-m) skipped on the runner that must run it"; exit 1; }
218+
# ⭐ And a count, because four `grep -q` calls that each matched say
219+
# nothing about how many rows the script actually booted: a fixture
220+
# that stopped iterating would still print its PASS line.
221+
booted=$(grep -c 'booted on ' 332_cortex_m_builds_and_boots.sh.log || true)
222+
[ "$booted" = "4" ] || {
223+
echo "332 booted $booted rows, expected 4"; exit 1; }
199224
200225
# ──────────────────────────────────────────────────────────────────
201226
# Hermetic (no host toolchain): the ONLY environment class that

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,36 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)
55
6+
## [2026.9.4.1] — 2026-09-04
7+
8+
Cortex-M 落地为七个目标行,freestanding 链接开启死代码段消除。
9+
10+
裸机目标表从四行增至十一行。M-profile 是七行而不是一行:为 `thumbv7em` 构建的
11+
目标文件使用 Cortex-M0 没有的指令,两种拼写产出互不兼容的目标文件,而表存在的
12+
理由正是让 `--target <triple>` 单独足以产出正确的目标文件。
13+
14+
```toml
15+
[build]
16+
target = "thumbv7em-none-eabihf"
17+
```
18+
19+
⚠️ **浮点 ABI 不决定 FPU 是否被使用。** `eabi`/`eabihf` 由 clang 从 triple 读出,
20+
它约束浮点值如何跨越函数边界,不约束函数内部发什么指令 —— 而 `thumbv7em` 架构
21+
蕴含 FPv4-SP。实测:软浮点 ABI 下 clang 对一次 float 乘法仍发出 `vmul.f32`,在
22+
没有 FPU 的 Cortex-M4 上于运行期触发异常,而编译与链接都是干净的。每个软浮点行
23+
因此携带 `-mfpu=none`,包括架构本来就没有 FPU 的那几行 —— 一行陈述它保证的性质,
24+
而不是从一个可以改变的默认值继承它。
25+
26+
freestanding 编译加 `-ffunction-sections -fdata-sections`、链接加 `--gc-sections`
27+
依赖的目标文件无条件进入链接(不像归档成员那样按未定义符号拉取),当 C 库改由
28+
依赖图提供时,没有死代码段消除的镜像会装进整份 C 库,而 Cortex-M 器件只有几十 KB。
29+
30+
⚠️ **链接脚本因此以新的方式承重**:中断向量表不被任何东西引用,`--gc-sections`
31+
会回收它,板级脚本必须写 `KEEP(*(.vectors))`
32+
33+
同时回填了 `docs/13` 中两条已被 2026.8.28.2 推翻的限制:当图中有包提供
34+
`hosted-standard-library` 时,裸机目标上的异常、RTTI 与 `import std` 均可用。
35+
636
## [2026.9.3.2] — 2026-09-03
737

838
`[xlings.workspace]`**推荐书写形态**定为命名空间在键上,官方包全部使用它;

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,11 @@ the right toolchain payload is resolved and installed automatically.
382382
| `aarch64-macos` | llvm *(macOS default)* ||
383383
| `riscv64-none-elf` | llvm 22 — bare metal, no OS; needs no per-host cross payload ² ||
384384
| `riscv32-none-elf` | llvm 22 — bare metal, no OS; needs no per-host cross payload ² ||
385+
| `thumbv6m-none-eabi` | llvm 22 — Cortex-M0/M0+/M1, bare metal ² ||
386+
| `thumbv7m-none-eabi` | llvm 22 — Cortex-M3, bare metal ² ||
387+
| `thumbv7em-none-eabihf` | llvm 22 — Cortex-M4F/M7F, hard float ² ||
388+
| `thumbv8m.main-none-eabi` | llvm 22 — Cortex-M33/M55, soft float ² ||
389+
| `thumbv7em-none-eabi` · `thumbv8m.base-none-eabi` · `thumbv8m.main-none-eabihf` | llvm 22 — builds and links; no emulator run recorded | 🔄 |
385390
| `riscv64-linux-musl` || 🔄 |
386391
| `aarch64-linux-gnu` || 🔄 |
387392
| `x86_64-macos` || 🔄 |

docs/13-baremetal.md

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,71 @@ covers the hosted link model this chapter departs from.
1313
## Overview
1414

1515
A freestanding target is a target whose `os` field is `none`. The target table
16-
at `modules/toolchain-model/src/triple.cppm` carries four of them:
16+
at `modules/toolchain-model/src/triple.cppm` carries eleven of them:
1717

1818
| Triple | Tier | C library |
1919
|---|---|---|
2020
| `riscv64-none-elf` | verified | `xim:picolibc-riscv` |
2121
| `riscv32-none-elf` | verified | `xim:picolibc-riscv` |
2222
| `aarch64-none-elf` | preview | none by default — the zero-libc tier; `xim:picolibc-aarch64` is declarable |
2323
| `x86_64-none-elf` | preview | none by default — the zero-libc tier; `xim:picolibc-x86` is declarable |
24+
| `thumbv6m-none-eabi` | verified | none by default — Cortex-M0/M0+/M1 |
25+
| `thumbv7m-none-eabi` | verified | none by default — Cortex-M3 |
26+
| `thumbv7em-none-eabi` | preview | none by default — Cortex-M4/M7, soft float |
27+
| `thumbv7em-none-eabihf` | verified | none by default — Cortex-M4F/M7F, hard float |
28+
| `thumbv8m.base-none-eabi` | preview | none by default — Cortex-M23 |
29+
| `thumbv8m.main-none-eabi` | verified | none by default — Cortex-M33/M55, soft float |
30+
| `thumbv8m.main-none-eabihf` | preview | none by default — Cortex-M33F/M55F, hard float |
2431

2532
`verified` means an image has been built **and run** for the row. `preview`
26-
means it builds and has been observed to run, but is not yet covered by the
27-
engine's own emulator jobs.
33+
means it builds and links, and no emulator run has been recorded.
34+
35+
### M-profile is seven rows rather than one
36+
37+
Every other bare-metal family above is one row per architecture. Cortex-M is
38+
not. An object built for `thumbv7em` uses instructions a Cortex-M0 does not
39+
have, and the two spellings produce incompatible objects rather than expressing
40+
a preference. The table exists so that `--target <triple>` alone suffices to
41+
produce a correct object file; a single `arm-none-eabi` row plus an `-mcpu` that
42+
each project remembered would move a correctness decision out of the table and
43+
into every manifest.
44+
45+
The `eabi`/`eabihf` suffix is the float ABI, and clang derives it from the
46+
triple without help: measured on llvm 22.1.8, `thumbv7em-none-eabi` yields
47+
`-mfloat-abi soft` and `thumbv7em-none-eabihf` yields `hard`.
48+
49+
⚠️ **The float ABI does not settle whether the FPU is used.** It governs how
50+
floating-point values cross a function boundary, not what the compiler may emit
51+
inside one, and the `thumbv7em` architecture implies FPv4-SP. Measured: under
52+
the soft-float ABI clang still emits `vmul.f32` for a float multiply. On a
53+
Cortex-M4 without an FPU that instruction faults at run time, after a clean
54+
compile and a clean link. Every soft-float row therefore carries `-mfpu=none`,
55+
including the rows describing architectures that have no FPU at all — a row
56+
states the property it guarantees rather than inheriting it from a default.
57+
58+
Cortex-M needs no `lldEmulation` column entry: clang has a *BareMetal* toolchain
59+
for arm, so these triples reach `ld.lld` through the driver as the RISC-V and
60+
aarch64 rows do. 32-bit ARM has no `-mcmodel` axis, so that column is empty too.
61+
62+
### Dead-section elimination
63+
64+
Freestanding builds compile with `-ffunction-sections -fdata-sections` and link
65+
with `--gc-sections`. Both halves belong to the engine rather than to a project
66+
because a dependency's translation units must carry them, and a project cannot
67+
reach those.
68+
69+
The flags became necessary rather than merely economical when a C library began
70+
arriving from the dependency graph. A dependency's object files enter the link
71+
unconditionally, unlike an archive member, which is pulled only while its symbol
72+
is undefined. That costs nothing when the C library is a prebuilt archive and
73+
the target has megabytes; a Cortex-M part has kilobytes, and without dead-section
74+
elimination every image would carry the whole of the C library.
75+
76+
⚠️ **A linker script becomes load-bearing in a new way.** An interrupt vector
77+
table is referenced by nothing — the hardware reads it by address — so
78+
`--gc-sections` collects it. A board's script must say `KEEP(*(.vectors))`.
79+
Measured: with the `KEEP` present, a function nothing calls is dropped, the
80+
table survives, and the image boots.
2881

2982
⚠️ The last two rows default to no C library, and that is a statement rather
3083
than an omission: the first consumer of both rows — the `openarch` layer of
@@ -190,8 +243,8 @@ by pointing `main` at the source file that carries `_start`.
190243
| Linker selection | `ld.lld` is addressed by **absolute path**, derived from the driver's own directory. `-fuse-ld=lld` resolves by name and finds GNU ld on any machine with binutils earlier on `PATH`, which then fails with `unrecognised emulation mode: elf64lriscv`. |
191244
| ISA flags | `-march`, `-mabi` and `-mcmodel` come from one row per target in `src/freestanding/target.cppm`, so `--target <triple>` alone is sufficient to produce a correct object file. |
192245
| C library | The **target's**, resolved by mcpp from the target's own table row exactly as the compiler is. A bare-metal project declares no libc, just as a hosted project declares no glibc. The engine places the sysroot's library directory on the link search path, so a board-support package selects out of it by bare name (`-lc`, `-lcrt0-semihost`). |
193-
| Exceptions and RTTI | Off on every translation unit in the graph, including a dependency's. There is no unwinder and no `libc++abi`, so nothing can throw; `std::optional::value()` alone would otherwise reference `__cxa_throw` and three further undefined symbols. The setting belongs to the target rather than to a project's `cxxflags` because a BMI records it, and a dependency compiled with exceptions cannot be imported by a unit without them. |
194-
| `import std` | Unavailable, and rejected at configure time with a diagnostic rather than at link time. |
246+
| Exceptions and RTTI | Off on every translation unit in the graph, including a dependency's, **unless a package supplies a C++ runtime built for this target**. There is otherwise no unwinder and no `libc++abi`, so nothing can throw; `std::optional::value()` alone would reference `__cxa_throw` and three further undefined symbols. The setting belongs to the target rather than to a project's `cxxflags` because a BMI records it, and a dependency compiled with exceptions cannot be imported by a unit without them. A package declaring `provides = ["hosted-standard-library"]` reverses the default: exceptions and RTTI are enabled, `-ffreestanding` is dropped, and `-fasynchronous-unwind-tables` is added. |
247+
| `import std` | Available when a package in the graph provides `hosted-standard-library` and names its own `std` module source; otherwise rejected at configure time with a diagnostic rather than at link time. |
195248
| Entry point | `int main()` is available whenever something supplies a `crt0`. A board-support package normally does. |
196249
| Default linkage | Static, and not as a preference: there is no loader, so there is no other option. |
197250
@@ -716,7 +769,7 @@ targets, but that expectation is **not** covered by a test.
716769
| Limitation | Observed behaviour |
717770
|---|---|
718771
| `std::format`, `std::sort` over builtin scalar types, and a complete `std::string` | Fail at **link** time naming the undefined symbol. libc++ places these entities in the compiled library — the scalar `__sort` instantiations are `extern template`, with no macro that disables them — so a target-built `libc++.a` is required. No such payload is published. |
719-
| Exceptions and RTTI | Disabled across the whole graph. `try`/`catch` is unavailable at compile time. A board shipping a target-built `libc++abi` and unwinder has a genuine case for re-enabling them; that is the point at which this becomes a manifest key. |
772+
| Exceptions and RTTI | Disabled across the whole graph **unless a package provides `hosted-standard-library`**, which `mcpplibs/openkal-llvm-runtime` does by carrying `libc++`, `libc++abi` and `libunwind` configured for the target. Without such a package `try`/`catch` remains unavailable at compile time. |
720773
| Board coverage | One board family. `riscv32-none-elf` demonstrates that the ISA table is data, not that a second machine has been ported. ARM Cortex-M has not been attempted. |
721774
| C library substitution | Expressible since 2026.8.20.2 through `[target.<triple>].sysroot`, and **verified only for the empty value** (the zero-libc tier). Pointing it at a different C library is accepted and installed through the same channel, but no second bare-metal C library is published, so that path is untested. |
722775
| `qemu-riscv` on `win32-arm64` | The upstream package publishes no asset for that host, so installation fails on it. The failure is correct rather than silent, but the host cannot run a bare-metal image. |

docs/16-the-target-triple.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,13 @@ other's rows.
428428
| `riscv32-none-elf` | verified | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
429429
| `aarch64-none-elf` | preview | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
430430
| `x86_64-none-elf` | preview | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
431+
| `thumbv6m-none-eabi` | verified | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
432+
| `thumbv7m-none-eabi` | verified | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
433+
| `thumbv7em-none-eabi` | preview | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
434+
| `thumbv7em-none-eabihf` | verified | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
435+
| `thumbv8m.base-none-eabi` | preview | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
436+
| `thumbv8m.main-none-eabi` | verified | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
437+
| `thumbv8m.main-none-eabihf` | preview | `llvm@22.1.8` | ✅ payload | ✅ payload | ✅ payload | ✅ payload |
431438

432439
`✅ payload` a toolchain payload here produces it · `⚙ graph` no payload, but a
433440
dependency can supply the system · `✅ system` located on the machine, not

0 commit comments

Comments
 (0)