Skip to content

Commit af91e99

Browse files
committed
docs: runtime closure (rpath) + toolchain default design
1 parent d3c5fe6 commit af91e99

1 file changed

Lines changed: 83 additions & 0 deletions

File tree

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# mcpp core: runtime closure (rpath) + toolchain defaults
2+
3+
> 2026-06-03 · part of the mcpp ecosystem打通 plan
4+
> Master plan: /home/speak/workspace/github/agentdocs/2026-06-03-mcpp-ecosystem-architecture-plan.md
5+
6+
This change fixes two general, long-term issues that block "native + GUI"
7+
packages (e.g. the imgui module package) from working out of the box. Neither
8+
is a special-case for any one package.
9+
10+
## R2 — dependency `[runtime] library_dirs` were dropped from binary RUNPATH
11+
12+
### Symptom
13+
A fresh consumer that depends (transitively) on `compat.glfw` builds fine but
14+
`mcpp run` fails at window creation: `GLX: Failed to load GLX`.
15+
16+
### Root cause (confirmed in source)
17+
- `compat.glx-runtime` (pulled in by `compat.glfw` on Linux) symlinks the host
18+
GLVND/GL/GLX libraries into its install dir and declares
19+
`[runtime] library_dirs = { mcpp_generated/glx_runtime/lib }`.
20+
- `src/build/plan.cppm` (~L220) already collects every dependency package's
21+
`runtime.library_dirs` into `plan.runtimeLibraryDirs` (resolved to absolute).
22+
- BUT `src/build/flags.cppm` (~L258) built the produced binary's RUNPATH by
23+
iterating only `plan.toolchain.linkRuntimeDirs` — i.e. the toolchain's own
24+
runtime dirs. The dependency runtime dirs in `plan.runtimeLibraryDirs` were
25+
never emitted as `-Wl,-rpath`. So the host-GL passthrough dir was not on the
26+
binary's RUNPATH, and the dlopen()'d `libGL.so.1` / `libGLX.so.0` were
27+
unreachable at run time.
28+
29+
The dependency dirs were correctly used for the *build/process* environment but
30+
not baked into the *binary* — so anything reached via dlopen (GL/GLX, and any
31+
plugin-style runtime lib) failed.
32+
33+
### Fix
34+
`src/build/flags.cppm`: iterate `plan.runtimeLibraryDirs` (the union of
35+
dependency runtime dirs + toolchain + payload) instead of
36+
`plan.toolchain.linkRuntimeDirs` when emitting `-L`/`-Wl,-rpath`. This is a
37+
superset, so toolchain dirs are still covered; it additionally bakes each
38+
dependency's declared runtime dir into RUNPATH.
39+
40+
This is the correct general behavior: any package that declares
41+
`[runtime] library_dirs` is promising "binaries that use me need these dirs at
42+
run time"; the producer binary must carry them as RUNPATH.
43+
44+
## R1 — fresh-machine bootstrap default toolchain was musl-static on Linux
45+
46+
### Symptom
47+
On a clean machine, "First run no toolchain configured" auto-installs
48+
`gcc@15.1.0-musl` (musl, static). Building any package that links the glibc
49+
world (X11/GL/system libs) then fails, e.g. `libXdmcp` `arc4random_buf`
50+
implicit-declaration under musl.
51+
52+
### Root cause
53+
`src/cli.cppm` (~L1390) hard-coded the Linux first-run default to
54+
`gcc@15.1.0-musl`.
55+
56+
### Fix
57+
Default Linux first-run toolchain to the platform-native glibc gcc
58+
(`gcc@16.1.0`). musl-static remains fully available but **opt-in** via
59+
`mcpp build --target x86_64-linux-musl` (which the project already supports via
60+
`[target.x86_64-linux-musl]`). This mirrors Cargo/Rust: default triple is
61+
`-gnu` (glibc), `-musl` is an explicit target for portable static binaries.
62+
musl-static is a poor *default* because it cannot link the glibc/native world.
63+
64+
## Why these are long-term/industrial, not workarounds
65+
- R2 makes the existing two-plane design actually work: the *host plane*
66+
(drivers/GLVND, provided by `compat.glx-runtime`, never vendored) is bound to
67+
the binary via RUNPATH, which is the standard ELF mechanism. No package code
68+
changes; no env hacks.
69+
- R1 aligns the default with the platform-native ABI, the same principle Cargo
70+
uses. Static/musl stays a first-class explicit option.
71+
72+
## Test plan (acceptance, via imgui-m, no special-casing)
73+
1. Self-build mcpp with these changes.
74+
2. Fresh consumer: `mcpp new app && mcpp add imgui` then:
75+
- `mcpp build` → uses glibc gcc by default (R1), no musl error.
76+
- `readelf -d <bin>` → RUNPATH contains the `compat.glx-runtime` lib dir (R2).
77+
- `mcpp run` → window opens, ImGui renders, no `GLX: Failed to load GLX`.
78+
3. `mcpp test` headless still passes on all platforms.
79+
80+
## Follow-up (separate, tracked in master plan)
81+
- Declarative `abi` capability on native packages so the resolver *derives* the
82+
ABI-correct toolchain instead of relying on a good default (defense in depth).
83+
- Capability→provider resolution for `opengl.glx.driver` (glvnd/cocoa/win32).

0 commit comments

Comments
 (0)