Skip to content

Commit 6edf419

Browse files
docs(13): 子集与零 libc 档是组合关系,不是互斥 (#467)
#466 里这一章断言: ⚠️ `std-freestanding` 与 `std-freestanding-nolibc` 服务于**互斥**的 安排 …… 处在零 libc 档的工程根本用不了子集。 这句话描述的是 std-freestanding 0.4.0 之前的状态,而 0.4.0 的 `nolibc` feature 恰恰让子集在这一档可用——实测 103 个头里的 94 个。同一个 PR 同时带来了那个 feature 和这句否定它的话。 障碍从来不是子集需要一个 C 库:libc++ 为 C 头提供包装头,它们通过 `#include_next` 续到真正的头去取 `size_t`、`mbstate_t`、`time_t` 与 `EOF`;没有 C 库时这条链无处可续,于是死在缺**类型**上而不是缺头上, 这正是从报错看不出成因的原因。四个很小的头把链续上。 一并写入板级支持包也能服务这一档(riscv-virt-rt 0.5.0 的 `nolibc` feature),理由与「为什么要有板级包」是同一条:UART 在哪、RAM 从哪开始、 哪个模拟器启动它,没有一条是 C 库事实。 静默替换那条警告仍然成立,但重新划定了范围:它说的是把 `std-freestanding-nolibc` **直接**与 C 库并用,而不是经由该 feature。 Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent e432f85 commit 6edf419

2 files changed

Lines changed: 38 additions & 12 deletions

File tree

docs/13-baremetal.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,28 @@ obligation rather than a convenience: `memcpy`, `memmove`, `memset` and `memcmp`
323323
must exist because the compiler lowers structure assignment and array
324324
initialisation onto them. `std-freestanding-nolibc` supplies those and `strlen`.
325325

326-
⚠️ `std-freestanding` and `std-freestanding-nolibc` serve **mutually exclusive**
327-
arrangements. The subset needs the C library's headers — measured: on the
328-
zero-libc tier it fails at compile with `'inttypes.h' file not found` — so a
329-
project that can use the subset has a C library and does not need the five
330-
functions, while a project on the zero-libc tier cannot use the subset at all.
331-
332-
⚠️ That package is for the zero-libc tier only, and using it alongside a C
333-
library fails silently rather than loudly. A C library ships as an archive, and
326+
The subset composes with this tier rather than excluding it. `std-freestanding`
327+
with `features = ["nolibc"]` compiles against no C library at all, and measured,
328+
**94 of its 103 headers** do. The obstacle was never that the subset wants a C
329+
library: libc++ ships wrappers for the C headers — `string.h` and its siblings —
330+
which reach the real header through `#include_next` to obtain `size_t`,
331+
`mbstate_t`, `time_t` and `EOF`. With no C library the chain has nothing to
332+
continue to, and the wrapper fails on a missing *type* rather than a missing
333+
header, which is why the cause is not evident from the error. Four small headers
334+
restore the chain, and the feature is what pulls them in.
335+
336+
A board-support package can serve this tier too, and for the same reason it is
337+
worth having one at all. Where a machine's UART is, where its RAM begins and
338+
which emulator boots it are not C library facts:
339+
340+
```toml
341+
[dependencies]
342+
riscv-virt-rt = { version = "0.5.0", features = ["nolibc"] }
343+
```
344+
345+
⚠️ `std-freestanding-nolibc` is what that feature resolves to, and adding it
346+
**directly** alongside a C library fails silently rather than loudly. A C library
347+
ships as an archive, and
334348
an archive member is pulled only while the symbol is still undefined; a
335349
dependency package's object files enter the link unconditionally. The package
336350
therefore defines `memcpy` first, the C library's member is never pulled, and

docs/zh/13-baremetal.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,23 @@ freestanding 翻译单元仍会用到的 C 函数中,有四个是义务而非便
293293
`memmove``memset``memcmp` 必须存在,因为编译器把结构体赋值与数组初始化下降到
294294
它们之上。`std-freestanding-nolibc` 提供这四个与 `strlen`
295295

296-
⚠️ `std-freestanding``std-freestanding-nolibc` 服务于**互斥**的安排。子集需要
297-
C 库的头文件 —— 实测:零 libc 档上它在编译期即死于 `'inttypes.h' file not found`
298-
—— 因此能用子集的工程有 C 库、不需要这五个函数,而处在零 libc 档的工程根本用不了子集。
296+
子集与这一档是**组合**关系而非互斥。`std-freestanding``features = ["nolibc"]`
297+
时在完全没有 C 库的情况下编译,实测其 **103 个头中的 94 个**可用。障碍从来不是子集
298+
需要一个 C 库:libc++ 为 C 头文件提供了包装头 —— `string.h` 及其同类 —— 它们通过
299+
`#include_next` 续到真正的头去取 `size_t``mbstate_t``time_t``EOF`。没有
300+
C 库时这条链无处可续,包装头死在缺**类型**而不是缺头文件上,这正是从报错看不出成因的
301+
原因。四个很小的头把链续上,而该 feature 负责把它们引进来。
299302

300-
⚠️ 该包仅用于零 libc 档,而与 C 库并用时是**静默**失败而非响亮失败。C 库以归档形式
303+
板级支持包同样可以服务这一档,理由与"为什么要有板级包"是同一条:一台机器的 UART 在哪、
304+
RAM 从哪开始、哪个模拟器启动它,没有一条是 C 库事实:
305+
306+
```toml
307+
[dependencies]
308+
riscv-virt-rt = { version = "0.5.0", features = ["nolibc"] }
309+
```
310+
311+
⚠️ `std-freestanding-nolibc` 正是该 feature 解析到的包,而**直接**把它与 C 库并用时
312+
**静默**失败而非响亮失败。C 库以归档形式
301313
发布,归档成员只在符号仍未定义时才被拉入;而依赖包的目标文件无条件进入链接。于是该包
302314
先定义了 `memcpy`,C 库的成员从不被拉入,构建**成功** —— 程序拿到的是逐字节实现而不是
303315
C 库经过优化的那份,且没有任何提示。实测(picolibc 在场):冷构建链接通过,`nm` 只找到

0 commit comments

Comments
 (0)