Skip to content

Commit a8c4e18

Browse files
committed
docs: three ways to ship, none of which uses the host's libc
mcpp#375 asked for a supported way to make a distributable artifact and proposed one: link against the system libc. Three routes already produce a distributable artifact and none of them does that -- through the ecosystem (xlings repoints the ELF at install time), a static musl target, or a bundle carrying the toolchain's own glibc. The gap was never a mechanism. It was that the page opened with "use mcpp pack" and never said what the alternatives were, so the reader who wanted something else had to invent it. The note about route A is the one that answers #375 directly: a freshly built binary's PT_INTERP names the build machine's payload, and hand-copying that file elsewhere fails. That is a property of hand-copying, not of the artifact -- installed through xlings the ELF is repointed at the target's own payloads. Saying so is what stops the next reader concluding the artifact is broken and reaching for the host's loader to "fix" it.
1 parent 619e7fb commit a8c4e18

2 files changed

Lines changed: 66 additions & 7 deletions

File tree

docs/02-pack-and-release.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
11
# 02 — Packaging for Release
22

3-
> A default dynamically linked binary produced by `mcpp build` normally has a
4-
> loader and RUNPATH tied to the build sandbox. To distribute it to other
5-
> machines or deploy it to a server, use `mcpp pack` to produce a release
6-
> tarball or directory with the appropriate runtime closure.
3+
> A default dynamically linked binary produced by `mcpp build` has a loader and
4+
> RUNPATH tied to the build sandbox. It is a development artifact, not a
5+
> deliverable. Three routes turn it into one — and none of them uses the host's
6+
> C library.
7+
8+
## Three ways to ship
9+
10+
Every route below produces an artifact whose C runtime comes from the
11+
ecosystem, never from `/lib64`. That is deliberate: mcpp builds against a
12+
private glibc precisely so a binary's behaviour does not depend on which
13+
distribution happens to be underneath it, and reaching back out to the host's
14+
libc to distribute would give that away at the last step.
15+
16+
| | Route | Command | Where its C runtime comes from | Choose it when |
17+
|---|---|---|---|---|
18+
| **A** | Through the ecosystem | `mcpp emit xpkg``xlings install <pkg>` | the target machine's own xlings payloads | the target has xlings |
19+
| **B** | One static file | `mcpp build --target x86_64-linux-musl` | nowhere — it is linked in | you want a single file with no runtime at all |
20+
| **C** | Carry the runtime | `mcpp pack --mode self-contained` | shipped inside the bundle | any Linux, including older than the build machine |
21+
22+
**On route A, and the thing that surprises people.** The `PT_INTERP` baked into
23+
a freshly built binary points at *your* machine's payload, so copying that file
24+
to another machine by hand does not work — the path is not there. That is not a
25+
property of the artifact so much as of the copy: installed through `xlings`, the
26+
package's ELF files are repointed at the target machine's own payloads at
27+
install time. The baked path is a build-machine detail, not a distribution
28+
format. If you are hand-copying binaries between machines, you want B or C.
29+
30+
**On route B.** `--target …-musl` implies a static link, so there is no loader,
31+
no RUNPATH and nothing to find at run time. It is the smallest and most
32+
portable result, and the one to reach for first when the program does not need
33+
glibc-specific behaviour (NSS lookups, `dlopen` of host plugins).
34+
35+
**On route C.** The bundle carries this toolchain's glibc and its loader, so it
36+
runs on distributions older than the build machine — the case B cannot cover
37+
when glibc is actually required. Read the `/proc/self/exe` note below before
38+
choosing it: launching through a bundled loader changes what the program sees
39+
about itself.
740

841
## Two axes: target (libc) × mode (bundling depth)
942

docs/zh/02-pack-and-release.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
11
# 02 — 发布打包
22

3-
> 默认的动态链接 `mcpp build` 产物通常会把 loader 与 RUNPATH 指向构建沙盒。
4-
> 如需分发至其他机器或部署至服务器,应使用 `mcpp pack` 生成带有适当运行时闭包的
5-
> 发布 tarball 或目录。
3+
> 默认的动态链接 `mcpp build` 产物会把 loader 与 RUNPATH 指向构建沙盒。它是
4+
> 开发产物,不是交付物。有三条路把它变成交付物 —— **没有一条使用宿主的 C 库**
5+
6+
## 三种分发方式
7+
8+
下面每一条产出的产物,其 C 运行时都来自生态,而不是 `/lib64`。这是有意的:
9+
mcpp 之所以针对私有 glibc 构建,正是为了让产物的行为不取决于底下是哪个发行版;
10+
如果最后一步又伸手去拿宿主的 libc,前面这件事就白做了。
11+
12+
| | 方式 | 命令 | C 运行时来自哪里 | 何时选它 |
13+
|---|---|---|---|---|
14+
| **A** | 走生态 | `mcpp emit xpkg``xlings install <pkg>` | 目标机自己的 xlings 载荷 | 目标机装了 xlings |
15+
| **B** | 静态单文件 | `mcpp build --target x86_64-linux-musl` | 不来自任何地方 —— 已链进去 | 想要一个无任何运行时依赖的单文件 |
16+
| **C** | 自带运行时 | `mcpp pack --mode self-contained` | 随 bundle 一起分发 | 任何 Linux,含比构建机更老的 |
17+
18+
**关于 A,以及那个让人意外的地方。** 刚构建出的二进制里烙的 `PT_INTERP` 指向
19+
**你这台机器**的载荷,所以手工把这个文件拷到另一台机器上跑不起来——那个路径
20+
在那边不存在。与其说这是产物的性质,不如说是「手工拷贝」这个动作的性质:经
21+
`xlings` 安装时,包里的 ELF 会在**装机期被重指到目标机自己的载荷**。烙进去的
22+
路径是构建机的细节,不是分发格式。如果你就是要在机器之间手工拷二进制,那你要
23+
的是 B 或 C。
24+
25+
**关于 B。** `--target …-musl` 隐含静态链接,所以没有 loader、没有 RUNPATH、
26+
运行期不需要找任何东西。它的结果最小也最可移植,在程序不需要 glibc 专有行为
27+
(NSS 查询、`dlopen` 宿主插件)时应当首选。
28+
29+
**关于 C。** bundle 里带着这套工具链的 glibc 与 loader,因此能在比构建机更老的
30+
发行版上跑 —— 这是 B 覆盖不了、而又确实需要 glibc 时的那一格。选它之前先读下面
31+
`/proc/self/exe` 一节:经 bundled loader 启动会改变程序对「自己在哪」的认知。
632

733
## 两条轴:target(libc) × mode(打包深度)
834

0 commit comments

Comments
 (0)