Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions docs/13-baremetal.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,28 @@ obligation rather than a convenience: `memcpy`, `memmove`, `memset` and `memcmp`
must exist because the compiler lowers structure assignment and array
initialisation onto them. `std-freestanding-nolibc` supplies those and `strlen`.

⚠️ `std-freestanding` and `std-freestanding-nolibc` serve **mutually exclusive**
arrangements. The subset needs the C library's headers — measured: on the
zero-libc tier it fails at compile with `'inttypes.h' file not found` — so a
project that can use the subset has a C library and does not need the five
functions, while a project on the zero-libc tier cannot use the subset at all.

⚠️ That package is for the zero-libc tier only, and using it alongside a C
library fails silently rather than loudly. A C library ships as an archive, and
The subset composes with this tier rather than excluding it. `std-freestanding`
with `features = ["nolibc"]` compiles against no C library at all, and measured,
**94 of its 103 headers** do. The obstacle was never that the subset wants a C
library: libc++ ships wrappers for the C headers — `string.h` and its siblings —
which reach the real header through `#include_next` to obtain `size_t`,
`mbstate_t`, `time_t` and `EOF`. With no C library the chain has nothing to
continue to, and the wrapper fails on a missing *type* rather than a missing
header, which is why the cause is not evident from the error. Four small headers
restore the chain, and the feature is what pulls them in.

A board-support package can serve this tier too, and for the same reason it is
worth having one at all. Where a machine's UART is, where its RAM begins and
which emulator boots it are not C library facts:

```toml
[dependencies]
riscv-virt-rt = { version = "0.5.0", features = ["nolibc"] }
```

⚠️ `std-freestanding-nolibc` is what that feature resolves to, and adding it
**directly** alongside a C library fails silently rather than loudly. A C library
ships as an archive, and
an archive member is pulled only while the symbol is still undefined; a
dependency package's object files enter the link unconditionally. The package
therefore defines `memcpy` first, the C library's member is never pulled, and
Expand Down
20 changes: 16 additions & 4 deletions docs/zh/13-baremetal.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,23 @@ freestanding 翻译单元仍会用到的 C 函数中,有四个是义务而非便
`memmove`、`memset` 与 `memcmp` 必须存在,因为编译器把结构体赋值与数组初始化下降到
它们之上。`std-freestanding-nolibc` 提供这四个与 `strlen`。

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

⚠️ 该包仅用于零 libc 档,而与 C 库并用时是**静默**失败而非响亮失败。C 库以归档形式
板级支持包同样可以服务这一档,理由与"为什么要有板级包"是同一条:一台机器的 UART 在哪、
RAM 从哪开始、哪个模拟器启动它,没有一条是 C 库事实:

```toml
[dependencies]
riscv-virt-rt = { version = "0.5.0", features = ["nolibc"] }
```

⚠️ `std-freestanding-nolibc` 正是该 feature 解析到的包,而**直接**把它与 C 库并用时
是**静默**失败而非响亮失败。C 库以归档形式
发布,归档成员只在符号仍未定义时才被拉入;而依赖包的目标文件无条件进入链接。于是该包
先定义了 `memcpy`,C 库的成员从不被拉入,构建**成功** —— 程序拿到的是逐字节实现而不是
C 库经过优化的那份,且没有任何提示。实测(picolibc 在场):冷构建链接通过,`nm` 只找到
Expand Down
Loading