Skip to content

Commit b718f49

Browse files
committed
docs: the SDK toolchains had no declaration surface written down
`emsdk` and `android-ndk` appeared in docs as valid toolchain spellings and nowhere else. Measured: `toolchain = "android-ndk@30.0.16248370"` works, the row's pin is the default, the payload installs on demand, and a foreign toolchain is refused -- none of which a reader could learn from the documentation. docs/20-toolchains.md gains a section, mirrored in the Chinese copy, covering the five things that surface actually has: nothing to declare the row names its own payload and that pin is the default; it installs on demand like any other declaring one anyway the ordinary per-target key, and naming the row's own payload is always accepted -- which is how a project pins a version across machines what cannot be overridden the payload NAME is fixed and the version is open, because for these rows the pin is a capability rather than a preference. With the refusal quoted, and the reason it is not about code generation: a stock clang emits aarch64 ELF perfectly well; what it cannot supply is the SYSTEM what belongs to the project the deployment floor, which is a different axis with its own key per platform -- one NDK serves a range of API levels, so naming a version does not pin one running the output neither the emulator nor a device is on the toolchain axis; `runner` is an argv prefix and the session belongs to a package Two checks in this repository caught things while writing it, which is the reason both exist: heading parity refused an English-only section, and the Chinese style rule refused three interrogative headings ("什么都不用声明") in favour of noun phrases.
1 parent 7cc82d1 commit b718f49

2 files changed

Lines changed: 202 additions & 0 deletions

File tree

‎docs/20-toolchains.md‎

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,112 @@ is built per project and cl bakes `_MSVC_MT`/`_MSVC_MD` into it, so a
491491
per-role override (`cxx_runtime = { tests = … }`) is refused with a message
492492
saying so rather than producing a module mismatch inside the ucrt headers.
493493

494+
## SDK Toolchains (`emsdk`, `android-ndk`)
495+
496+
Two of the five toolchain spellings name an **SDK** rather than a bare
497+
compiler: `emsdk` and `android-ndk`. Their compiler *is* clang -- so they are
498+
not a separate compiler family, and mcpp does not pretend they are -- but the
499+
archive brings its own sysroot, its own C library and, for both of these, its
500+
own generated `std` module surface. That difference is what the rest of this
501+
section is about.
502+
503+
### Nothing has to be declared
504+
505+
A target row names its own payload, and that pin is the default. Neither of
506+
these needs a line in `mcpp.toml`:
507+
508+
```bash
509+
mcpp build --target wasm32-emscripten # resolves emsdk@6.0.9
510+
mcpp build --target aarch64-linux-android # resolves android-ndk@30.0.16248370
511+
```
512+
513+
The payload is **installed on demand** the first time a target needs it, the
514+
same way a gcc or llvm payload is. `mcpp toolchain list` shows the pin beside
515+
the row, and the build reports which archive answered:
516+
517+
```
518+
Resolved emsdk@6.0.9 → wasm32-emscripten → …/xim-x-emsdk/6.0.9/emscripten/em++
519+
Resolved android-ndk@30.0.16248370 → aarch64-linux-android → …/prebuilt/linux-x86_64/bin/clang++
520+
```
521+
522+
### Declaring one anyway
523+
524+
The ordinary per-target key works, and naming the row's own payload is always
525+
accepted:
526+
527+
```toml
528+
[target.aarch64-linux-android]
529+
toolchain = "android-ndk@30.0.16248370"
530+
531+
[target.wasm32-emscripten]
532+
toolchain = "emsdk@6.0.9"
533+
```
534+
535+
Use it to pin a version across machines, or to opt into a payload newer than
536+
the row's convention. The **version** is free -- anything the index publishes
537+
resolves -- so this is how a project moves ahead of, or stays behind, the
538+
default.
539+
540+
### What cannot be overridden, and why
541+
542+
For these rows the pin is a **capability** rather than a convention: it is not
543+
mcpp's preference among several payloads that could serve the target, it is the
544+
only thing that can. So the payload NAME is fixed while the version is open:
545+
546+
```toml
547+
[target.aarch64-linux-android]
548+
toolchain = "llvm@22.1.8" # refused
549+
```
550+
551+
```
552+
error: target 'aarch64-linux-android' cannot be emitted by 'llvm@22.1.8'.
553+
An Android target needs bionic, not just an aarch64 or x86_64 back end:
554+
its headers, its per-API-level stubs and its loader path are inside the
555+
NDK, and no package adds them to another compiler.
556+
```
557+
558+
The refusal is not about code generation. A stock clang emits aarch64 ELF
559+
perfectly well; what it cannot supply is the SYSTEM. Saying so at the
560+
declaration is better than resolving llvm and failing deep inside the build,
561+
which is what happened before this gate existed -- first `'__config' file not
562+
found`, then `Unversioned target triples are not supported!` from bionic's own
563+
header, neither of them naming the toolchain that could not serve the row.
564+
565+
`wasm32-emscripten` refuses on the same rule with its own sentence: nothing but
566+
Emscripten emits WebAssembly.
567+
568+
### What belongs to the project instead
569+
570+
The toolchain is the SDK's; the **deployment floor** is the project's, and it
571+
has its own key per platform -- see
572+
[04 — mcpp.toml](04-mcpp-toml.md) §2.7.3:
573+
574+
```toml
575+
[target.aarch64-linux-android]
576+
min_api_level = 24 # Android
577+
```
578+
579+
```toml
580+
[package]
581+
macos_deployment_target = "14.0" # Apple
582+
```
583+
584+
One NDK serves a range of API levels, so the level is a project decision and
585+
naming `android-ndk@<version>` does not pin one. Left out, mcpp reads the floor
586+
the NDK itself declares in `meta/platforms.json`.
587+
588+
### Running what they produce
589+
590+
Neither the emulator nor a device is part of the toolchain axis. `mcpp run`
591+
executes a wasm module directly, because Emscripten's output is a program
592+
`node` can run. For a target whose artifact runs elsewhere, the `runner` key is
593+
an argv prefix and the session belongs to a package rather than to the engine:
594+
595+
```toml
596+
[target.x86_64-linux-android]
597+
runner = ["adb-run"] # a program from xim:android-platform-tools
598+
```
599+
494600
## Project-Level Version Pinning
495601

496602
If a project needs to pin a specific version rather than rely on the global default, declare it in the project's `mcpp.toml`:

‎docs/zh/20-toolchains.md‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,102 @@ CRT。
448448
toolset 自带的那份可再分发 CRT(`vcruntime140.dll` / `msvcp140.dll`)可以跟着
449449
产物走 —— 见 `docs/zh/04-mcpp-toml.md` 的 `cxx_runtime = "toolchain-coupled"`。
450450

451+
## SDK 工具链(`emsdk`、`android-ndk`)
452+
453+
五种工具链拼法里有两种命名的是一个 **SDK** 而不是一个裸编译器:`emsdk` 与
454+
`android-ndk`。它们的编译器**就是** clang —— 所以它们不是一个独立的编译器 family,
455+
mcpp 也不假装它们是 —— 而那份归档自带 sysroot、自带 C 库,并且这两者都自带一份
456+
生成好的 `std` 模块面。本节讲的就是这个差别。
457+
458+
### 默认值:该行自己的钉
459+
460+
一个目标行命名了它自己的载荷,而那个钉就是默认值。这两者都不需要在 `mcpp.toml`
461+
里写一行:
462+
463+
```bash
464+
mcpp build --target wasm32-emscripten # 解析到 emsdk@6.0.9
465+
mcpp build --target aarch64-linux-android # 解析到 android-ndk@30.0.16248370
466+
```
467+
468+
载荷在某个目标第一次需要它时**按需安装**,和一个 gcc 或 llvm 载荷完全一样。
469+
`mcpp toolchain list` 会在行旁边显示那个钉,而构建会报出是哪份归档回答的:
470+
471+
```
472+
Resolved emsdk@6.0.9 → wasm32-emscripten → …/xim-x-emsdk/6.0.9/emscripten/em++
473+
Resolved android-ndk@30.0.16248370 → aarch64-linux-android → …/prebuilt/linux-x86_64/bin/clang++
474+
```
475+
476+
### 也可以显式声明
477+
478+
普通的按目标键照常可用,而点名该行自己的载荷总是被接受:
479+
480+
```toml
481+
[target.aarch64-linux-android]
482+
toolchain = "android-ndk@30.0.16248370"
483+
484+
[target.wasm32-emscripten]
485+
toolchain = "emsdk@6.0.9"
486+
```
487+
488+
用它把版本跨机器钉住,或者选用比该行约定更新的载荷。**版本是自由的** —— 索引里
489+
发布过的都能解析 —— 所以一个工程就是用它走在默认值之前或留在它之后。
490+
491+
### 不可覆盖的部分及其依据
492+
493+
对这两行,那个钉是一个**能力**而不是一个约定:它不是 mcpp 在几个都能服务该目标的
494+
载荷之间的偏好,而是唯一能服务它的东西。所以载荷的**名字**是固定的,版本是开放的:
495+
496+
```toml
497+
[target.aarch64-linux-android]
498+
toolchain = "llvm@22.1.8" # 被拒绝
499+
```
500+
501+
```
502+
error: target 'aarch64-linux-android' cannot be emitted by 'llvm@22.1.8'.
503+
An Android target needs bionic, not just an aarch64 or x86_64 back end:
504+
its headers, its per-API-level stubs and its loader path are inside the
505+
NDK, and no package adds them to another compiler.
506+
```
507+
508+
这次拒绝与代码生成无关。一个普通 clang 发 aarch64 ELF 完全没问题;它拿不出来的是
509+
**体系**。在声明处就说出来,比解析出 llvm 再在构建深处失败要好 —— 而后者正是这道闸
510+
存在之前发生的事:先是 `'__config' file not found`,然后是 bionic 自己头文件里的
511+
`Unversioned target triples are not supported!`,两句都没点名那个服务不了这一行的
512+
工具链。
513+
514+
`wasm32-emscripten` 按同一条规则、用它自己的句子拒绝:除了 Emscripten 没有东西发
515+
WebAssembly。
516+
517+
### 属于工程的那一半
518+
519+
工具链是 SDK 的;**部署下限**是工程的,而它按平台各有自己的键 —— 见
520+
[04 — mcpp.toml](04-mcpp-toml.md) §2.7.3:
521+
522+
```toml
523+
[target.aarch64-linux-android]
524+
min_api_level = 24 # Android
525+
```
526+
527+
```toml
528+
[package]
529+
macos_deployment_target = "14.0" # Apple
530+
```
531+
532+
一个 NDK 服务一个 API level 的**区间**,所以级别是工程的决定,而点名
533+
`android-ndk@<version>` 并不钉住其中任何一个。不写的话,mcpp 读 NDK 自己在
534+
`meta/platforms.json` 里声明的下限。
535+
536+
### 产物的运行方式
537+
538+
模拟器和真机都不属于工具链这根轴。`mcpp run` 直接执行一个 wasm 模块,因为
539+
Emscripten 的产物就是一个 `node` 能跑的程序。对于产物在别处运行的目标,`runner`
540+
键是一个 argv 前缀,而那个会话属于一个**包**而不属于引擎:
541+
542+
```toml
543+
[target.x86_64-linux-android]
544+
runner = ["adb-run"] # 来自 xim:android-platform-tools 的一个程序
545+
```
546+
451547
## 项目级版本锁定
452548

453549
若项目需固定特定版本而不依赖全局默认,可在项目的 `mcpp.toml` 中声明:

0 commit comments

Comments
 (0)