Skip to content

Commit 55a856d

Browse files
Link forms, standard levels and path lengths: #641 and #642 (2026.9.15.2) (#644)
* A C++-layer provider compiles its implementation units at the standard it states (#641 item 2) A package that provides the C++ layer and states [package] standard now compiles each C++ unit that neither provides nor imports a module at exactly that level; module units, the std module included, stay at the graph's level. The level is appended to the unit's own flag vector in make_plan, so the compile edge, the scan edge, compile_commands.json and the build database read one value. The provider predicate is factored into the manifest module and used by the std module adoption. The dependency cache key and the fingerprint metadata carry the stated level only when it exists; the higher-standard warning no longer reports a provider whose level is applied. Tests: unit CxxLayerStandard.* and CacheKey.ACxxLayerProvidersStatedStandardChangesTheKey; e2e 696 (requires llvm). Docs: 07-workspace 4.2 and 22-target-side with mirrors. * docs(design): #641 and #642 triage record, probes, and implementation plan * mcpp pack --features reaches every build pass of the pack, and run --format passes its features to the pack (#641 item 4) * A required compiler family takes the pins of its own payload (#641 item 1); a dependency's C++ shared library over a graph C++ runtime is refused or carries a stated private copy (#641 item 5) * The refusal offers the static edge only where a request or a default made the library shared; e2e 690 reads four legs * docs: M1-M3 in 20-toolchains, 10-pack-and-release and 50-machine-output with mirrors; CI runs the graph C++ runtime e2e scripts on the hermetic llvm job * Bounded tool-build paths: owner-relative object addresses, a short sub-build scratch, extended-length opens on Windows (#641 item 3; M7, M8, M9) M7. A source outside the package that declares it (a build program's mcpp::source under a dependency's root) is addressed as obj/<declaring>/__pkg/<owning package>/<path inside it>, or obj/<declaring>/__ext/<8-hex hash of its directory>/ when no package contains it. The mirror of the declaring-package-relative path, with one __up per level, is gone for these sources; sources inside their declaring package, root-owned flat addresses, the #233 census and backstop, and the cache address (packageRel) are unchanged. In the root census branch the escaping form applies only where the mirrored prefix was used (a basename collision), so the flat obj/<name> of a generated OUT_DIR source (#239) is unchanged. M8. The host-tool sub-build scratch moves from <entry>/build-<hash> to <cache>/tool/.build/<hash of entry and consuming work root> (tool_store::scratch_dir), keeping per-consumer isolation, re-run reuse and removal after publish; the entry layout is unchanged. M9. mcpp::platform::fs::extended_length (identity outside Windows; absolute, normal, backslash, \\?\ or \\?\UNC\ form on Windows, idempotent) with the pure spelling rule windows_extended_length_spelling. Call sites, enumerated from the $mcpp rules of ninja_backend.cppm and the __action-stamp wrapper: src/cli/cmd_build.cppm cmd_dyndep: --output; the --expect-* ddi read; emit_dyndep_single input; emit_dyndep_from_files inputs src/cli/cmd_build.cppm cmd_stage: source and --output (stage_file) src/cli/cmd_build.cppm cmd_bmi_equal: both paths (bmi_equivalent) src/cli/cmd_build.cppm cmd_coff_def: each object read; the .def write src/cli/cmd_build.cppm cmd_bmi_compile: --bmi --slot --sem --command-file --dep-from --dep-to (not --self, an executable) src/cli/cmd_build.cppm cmd_bmi_supervise: --slot --token --command-file src/cli/cmd_build.cppm cmd_bmi_await: --slot --object src/cli.cppm __action-stamp: each stamp Downstream opens receive the converted paths. Two follow-ons: the detached compile's log opens with CreateFileW (CreateFileA does not honour the prefix past MAX_PATH), and CompileRequest::bmiTarget keeps ninja's spelling of the BMI for the copied depfile's target, which must not change. Tests: unit ObjectAddress.ASourceUnderAnotherPackageIsAddressedByThatPackage, ObjectAddress.AnUnownedEscapingSourceIsAddressedByAHashOfItsDirectory (both fail on the previous object_for), ToolStoreScratch.IsShortPerConsumerAndStable, PlatformFs.ExtendedLength* (four); e2e 698 (leg A fails on 2026.9.15.1 with obj/installer/__up/__up/dep/platform/impl/helper.o). Docs: 30-build-mcpp and its Chinese mirror. * feat: a library states its default link form, and the root build program reads each dependency's form (#642 E1, E2) - [targets.<n>] linkage and its row form state a library's default form; kind = "shared" stays the constraint. Precedence: the root edge, a written dependency_linkage, the package default, static. An explicit override is honoured with an information line and no degraded record. - The link-form resolution is computed once before the root build program (hasSources from the scanner's own package_source_files) and applied after the scan as before. - The root build program receives MCPP_DEP_<NAME>_LINKAGE under the names of MCPP_DEP_<NAME>_DIR; mcpp::dep_linkage() reads it. Dependency programs do not. - Form B descriptors read linkage the same way. - Unit tests (linkage_form, manifest, xpkg), e2e 692 and 693, docs 04, 22, 30 with their Chinese mirrors, SPEC-004 1.4. * The M3 refusal reads the resolution's declaredShared fact for the package that constrains its form * Version 2026.9.15.2; CHANGELOG; the plan's ledger and refinements * dep_dir and dep_linkage answer under the qualified namespace.name a consumer writes; e2e 693 leg F * e2e 696 and 698 write fixture paths through host_path * docs: a shared library over a graph C++ runtime on Mach-O exports what its sources mark with default visibility * docs(design): refinements measured on macos-15 and for qualified dependency names * e2e 698: the consumer's tool command survives cmd.exe's quote stripping on Windows * e2e 698 sources the host path helper before it changes directory --------- Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> Co-authored-by: speak-agent <x.d2learn.org@gmail.com>
1 parent 69fae26 commit 55a856d

65 files changed

Lines changed: 4206 additions & 232 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/docs/2026-09-15-641-642-implementation-plan.md

Lines changed: 332 additions & 0 deletions
Large diffs are not rendered by default.

.agents/docs/2026-09-15-641-642-link-forms-standards-and-paths.md

Lines changed: 559 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/usr/bin/env bash
2+
# Probes for mcpp-community/mcpp#641 and #642, as recorded in
3+
# 2026-09-15-641-642-link-forms-standards-and-paths.md (§6).
4+
#
5+
# Host: Linux x86_64. Engine: the released mcpp 2026.9.15.1 (the xlings
6+
# package, whose home is ~/.mcpp). Toolchains already in that home:
7+
# llvm@22.1.8 and gcc@16.1.0; package llvm.libcxx 22.1.8.1 installed.
8+
# M1 uses the network (a fresh home fetches its index).
9+
#
10+
# Every reading is a line starting with READING; nothing else is a result.
11+
#
12+
# Usage: 2026-09-15-641-642-probes.sh <empty work directory>
13+
set -u
14+
WORK=${1:?usage: $0 <empty work directory>}
15+
mkdir -p "$WORK" && WORK=$(cd "$WORK" && pwd)
16+
M=${MCPP:-$HOME/.xlings/data/xpkgs/xim-x-mcpp/2026.9.15.1/bin/mcpp}
17+
XLINGS=${MCPP_VENDORED_XLINGS:-$HOME/.xlings/data/xpkgs/xim-x-mcpp/2026.9.15.1/registry/bin/xlings}
18+
LIBCXX=$HOME/.mcpp/registry/data/xpkgs/llvm-x-libcxx/22.1.8.1/libcxx-22.1.8.1
19+
NINJA=$(find "$HOME/.mcpp/registry/data/xpkgs/xim-x-ninja" -name ninja -type f | head -1)
20+
# An outer SubOS must not steer the engine's registry (2026.9.14.3).
21+
unset XLINGS_ACTIVE_SUBOS
22+
reading() { echo "READING $*"; }
23+
"$M" --version | sed 's/^/READING engine: /'
24+
25+
# --- M1 (#641 item 1): a required llvm on a home with no llvm installed ------
26+
mkdir -p "$WORK/m1/home" "$WORK/m1/proj/src" && cd "$WORK/m1/proj"
27+
printf '[package]\nname = "m1"\nversion = "0.1.0"\nrequires = ["mcpp:compiler=llvm"]\n' > mcpp.toml
28+
printf 'int main() { return 0; }\n' > src/main.cpp
29+
MCPP_HOME="$WORK/m1/home" MCPP_VENDORED_XLINGS="$XLINGS" XLINGS_NON_INTERACTIVE=1 \
30+
timeout 900 "$M" build > build.log 2>&1
31+
reading "M1 exit=$? spec=$(grep -o "toolchain 'llvm@[^']*'" build.log | head -1)"
32+
# The same comparison, from the other side: a family whose payload is not
33+
# named after the family finds no pin at all, although rows pin both.
34+
for fam in emsdk android-ndk; do
35+
mkdir -p "$WORK/m1/$fam/src" && cd "$WORK/m1/$fam"
36+
printf '[package]\nname = "p"\nversion = "0.1.0"\nrequires = ["mcpp:compiler=%s"]\n' "$fam" > mcpp.toml
37+
printf 'int main() { return 0; }\n' > src/main.cpp
38+
MCPP_HOME="$WORK/m1/home" XLINGS_NON_INTERACTIVE=1 timeout 300 "$M" build > build.log 2>&1
39+
reading "M1 $fam exit=$? $(grep -o 'none is installed, and no target row pins one' build.log)"
40+
done
41+
42+
# --- M2 (#641 item 2): a c++20 root over llvm.libcxx -------------------------
43+
mkdir -p "$WORK/m2/src" && cd "$WORK/m2"
44+
cat > mcpp.toml <<'T'
45+
[package]
46+
name = "m2"
47+
version = "0.1.0"
48+
standard = "c++20"
49+
50+
[toolchain]
51+
default = "llvm@22.1.8"
52+
53+
[dependencies]
54+
llvm.libcxx = "22.1.8.1"
55+
T
56+
cat > src/main.cpp <<'C'
57+
import std;
58+
int main() {
59+
std::unordered_map<std::string, int> m; m["one"] = 1;
60+
try { throw std::runtime_error("x"); } catch (const std::runtime_error&) { m["two"] = 2; }
61+
std::cout << std::format("{}-{}", m["one"], m["two"]) << std::endl;
62+
}
63+
C
64+
timeout 1800 "$M" build > build.log 2>&1
65+
reading "M2 exit=$? resize_and_overwrite errors=$(grep -c "no member named 'resize_and_overwrite'" build.log) bad_expected_access errors=$(grep -c "no template named 'bad_expected_access'" build.log)"
66+
67+
# --- M2b: the same root, with the package's implementation units at c++23 ----
68+
# `[build] cxxflags` refuses `-std=`, so the emulation uses the conditional
69+
# table the package already has for Linux. The std module is still built at
70+
# the graph's level, which is the arrangement §3.2 proposes.
71+
mkdir -p "$WORK/m2b/src" && cd "$WORK/m2b"
72+
cp -r "$LIBCXX" libcxx && chmod -R u+w libcxx
73+
python3 - <<'PY'
74+
p = 'libcxx/mcpp.toml'; s = open(p).read()
75+
old = 'cxxflags = ["-D_GNU_SOURCE"]'
76+
assert s.count(old) == 1, s.count(old)
77+
s = s.replace(old, 'cxxflags = ["-D_GNU_SOURCE", "-std=c++23"]')
78+
assert s.count('-std=c++23') == 1
79+
open(p, 'w').write(s)
80+
PY
81+
sed 's/^llvm.libcxx = .*$//; s/^name = "m2"$/name = "m2b"/' "$WORK/m2/mcpp.toml" > mcpp.toml
82+
printf '[dependencies.llvm.libcxx]\npath = "libcxx"\n' >> mcpp.toml
83+
cp "$WORK/m2/src/main.cpp" src/main.cpp
84+
timeout 1800 "$M" build > build.log 2>&1
85+
reading "M2b exit=$?"
86+
d=$(ls -d target/*/*/ 2>/dev/null | head -1)
87+
if [ -n "$d" ]; then
88+
reading "M2b graph -std: $(grep -m1 '^cxxflags' "$d/build.ninja" | grep -o -- '-std=[^ ]*')"
89+
ln=$(grep -n 'libcxx/src/new.o *:' "$d/build.ninja" | head -1 | cut -d: -f1)
90+
reading "M2b new.cpp unit -std: $(sed -n "${ln},$((ln+6))p" "$d/build.ninja" | grep -o -- '-std=[^ ]*' | tr '\n' ' ')"
91+
[ -x "$d/bin/m2b" ] && reading "M2b run: out=$("$d/bin/m2b") exit=$?"
92+
fi
93+
94+
# --- M3 (#641 item 5): a shared C++ dependency in a graph over llvm.libcxx ---
95+
mkdir -p "$WORK/m3/app/src" "$WORK/m3/fw/src" && cd "$WORK/m3"
96+
printf '[package]\nname = "fw"\nversion = "0.1.0"\n\n[targets.fw]\nkind = "shared"\n' > fw/mcpp.toml
97+
cat > fw/src/fw.cppm <<'C'
98+
export module fw;
99+
import std;
100+
export std::string fw_greet(int n);
101+
export void fw_throw_runtime();
102+
export void fw_throw_custom();
103+
export struct fw_error : std::runtime_error { using std::runtime_error::runtime_error; };
104+
C
105+
cat > fw/src/fw.cpp <<'C'
106+
module fw;
107+
import std;
108+
std::string fw_greet(int n) { return std::format("fw-{}", n); }
109+
void fw_throw_runtime() { throw std::runtime_error("from fw"); }
110+
void fw_throw_custom() { throw fw_error("custom from fw"); }
111+
C
112+
cat > app/mcpp.toml <<'T'
113+
[package]
114+
name = "app"
115+
version = "0.1.0"
116+
117+
[toolchain]
118+
default = "llvm@22.1.8"
119+
120+
[dependencies]
121+
llvm.libcxx = "22.1.8.1"
122+
fw = { path = "../fw" }
123+
T
124+
cat > app/src/main.cpp <<'C'
125+
import std;
126+
import fw;
127+
int main() {
128+
std::string s = fw_greet(3);
129+
std::cout << s << std::endl;
130+
try { fw_throw_runtime(); }
131+
catch (const std::runtime_error& e) { std::cout << "runtime_error caught by type" << std::endl; }
132+
catch (...) { std::cout << "runtime_error NOT matched by type" << std::endl; }
133+
try { fw_throw_custom(); }
134+
catch (const fw_error&) { std::cout << "fw_error caught by type" << std::endl; }
135+
catch (...) { std::cout << "fw_error NOT matched" << std::endl; }
136+
}
137+
C
138+
cd app
139+
timeout 1800 "$M" build > build.log 2>&1
140+
reading "M3 exit=$? $(grep -m1 -o "non-exported symbol '[^']*' in '[^']*' is referenced by DSO 'bin/libfw.so'" build.log)"
141+
d=$(ls -d target/*/*/ 2>/dev/null | head -1)
142+
if [ -n "$d" ] && [ -f "$d/bin/libfw.so" ]; then
143+
cd "$d"
144+
reading "M3 libfw.so inputs: $(grep '^build bin/libfw.so' build.ninja | sed 's/^build bin\/libfw.so : cxx_shared //')"
145+
reading "M3 libfw.so unit_ldflags: $(grep -A3 '^build bin/libfw.so' build.ninja | grep -o 'unit_ldflags = .*')"
146+
reading "M3 libfw.so undefined std::__1 references: $(nm -D --undefined-only bin/libfw.so | grep -c '__1')"
147+
148+
# --- M5: link each image with its own copy of the graph libc++ ---------
149+
fwcmd=$("$NINJA" -t commands bin/libfw.so | tail -1)
150+
appcmd=$("$NINJA" -t commands bin/app | tail -1)
151+
fwin=$(grep '^build bin/libfw.so' build.ninja | sed 's/^build bin\/libfw.so : cxx_shared //; s/ || .*//; s/ | .*//')
152+
appin=$(grep '^build bin/app ' build.ninja | sed 's/^build bin\/app : cxx_link //; s/ || .*//; s/ | .*//')
153+
rt=$(find obj/llvm_libcxx -name '*.o' | sort | tr '\n' ' ')
154+
printf '%s %s\n' "$fwin" "$rt" > bin/libfw.so.rsp
155+
printf '%s\n' "$appin" > bin/app.rsp
156+
eval "$fwcmd" > m5-fw.log 2>&1; reading "M5 libfw.so linked with a private libc++: exit=$?"
157+
eval "$appcmd" > m5-app.log 2>&1; reading "M5 program linked: exit=$?"
158+
out=$(./bin/app 2>&1); rc=$?
159+
reading "M5 run exit=$rc output: $(echo "$out" | tr '\n' '|')"
160+
fi
161+
162+
# --- M3b (finding F1): a shared package over a static package, no runtime ----
163+
mkdir -p "$WORK/m3b/app/src" "$WORK/m3b/fw/src" "$WORK/m3b/x/src" && cd "$WORK/m3b"
164+
printf '[package]\nname = "x"\nversion = "0.1.0"\n[build]\nsources = ["src/*.c"]\n[targets.x]\nkind = "lib"\n' > x/mcpp.toml
165+
printf 'int x_answer(void) { return 41; }\n' > x/src/x.c
166+
printf '[package]\nname = "fw"\nversion = "0.1.0"\n[build]\nsources = ["src/*.c"]\n[targets.fw]\nkind = "shared"\n[dependencies.x]\npath = "../x"\n' > fw/mcpp.toml
167+
printf 'extern int x_answer(void);\nint fw_answer(void) { return x_answer() + 1; }\n' > fw/src/fw.c
168+
printf '[package]\nname = "app"\nversion = "0.1.0"\n[dependencies.fw]\npath = "../fw"\n' > app/mcpp.toml
169+
printf 'extern "C" int fw_answer(void);\nint main() { return fw_answer() == 42 ? 0 : 1; }\n' > app/src/main.cpp
170+
cd app
171+
timeout 900 "$M" build > build.log 2>&1
172+
reading "M3b exit=$?"
173+
so=$(ls target/*/*/bin/libfw.so 2>/dev/null | head -1)
174+
if [ -n "$so" ]; then
175+
bin=$(ls target/*/*/bin/app | head -1)
176+
reading "M3b libfw.so undefined x_answer=$(nm -D --undefined-only "$so" | grep -c x_answer) program exports x_answer=$(nm -D --defined-only "$bin" | grep -c x_answer)"
177+
"$bin"; reading "M3b run exit=$?"
178+
fi
179+
180+
# --- M4 (#641 item 4): pack takes no --features ------------------------------
181+
"$M" pack --features x > pack.log 2>&1
182+
reading "M4 pack exit=$? $(head -1 pack.log)"
183+
184+
# --- M6 (#641 item 2): the key the two C++-layer packages write --------------
185+
mkdir -p "$WORK/m6/src" && cd "$WORK/m6"
186+
printf '[package]\nname = "m6"\nversion = "0.1.0"\n\n[build]\ncxx_standard = "c++23"\n' > mcpp.toml
187+
printf 'int main() { return 0; }\n' > src/main.cpp
188+
"$M" build > build.log 2>&1
189+
reading "M6 exit=$? $(grep -o "\[build\] has unsupported key 'cxx_standard' (ignored)" build.log)"

.agents/docs/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
287 records.
21+
289 records.
2222

2323
## By subject
2424

@@ -62,6 +62,8 @@ Records that declare one. Everything else is listed by date below.
6262

6363
### triage
6464

65+
- [Link forms, standard levels and a path limit: the asks of #641 and #642, read against the code](2026-09-15-641-642-link-forms-standards-and-paths.md) — active
66+
- [#641 and #642 implemented: the plan, its review from eight angles, and the ledger](2026-09-15-641-642-implementation-plan.md) — active
6567
- [#634 implemented across five repositories: the plan, its review, and the ledger that tracks it](2026-09-14-634-implementation-plan.md) — landed
6668
- [A framework's CMake parity list: the twenty-one items of #634, read against the code and routed to where each one belongs](2026-09-14-634-cmake-parity-items-by-home.md) — landed
6769
- [What a framework and its ecosystem library still hit in the engine: the ten items of #630, read against the code](2026-09-13-630-what-a-framework-still-hits-in-the-engine.md) — landed
@@ -72,6 +74,8 @@ Records that declare one. Everything else is listed by date below.
7274

7375
### 2026-09
7476

77+
- [Link forms, standard levels and a path limit: the asks of #641 and #642, read against the code](2026-09-15-641-642-link-forms-standards-and-paths.md) — active
78+
- [#641 and #642 implemented: the plan, its review from eight angles, and the ledger](2026-09-15-641-642-implementation-plan.md) — active
7579
- [The build database of #636, and two defects on the way to the latest xlings](2026-09-14-636-build-database-and-the-latest-xlings.md) — active
7680
- [#634 implemented across five repositories: the plan, its review, and the ledger that tracks it](2026-09-14-634-implementation-plan.md) — landed
7781
- [A framework's CMake parity list: the twenty-one items of #634, read against the code and routed to where each one belongs](2026-09-14-634-cmake-parity-items-by-home.md) — landed

.github/workflows/ci-linux-e2e.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,30 @@ jobs:
416416
export MCPP
417417
bash tests/e2e/86_llvm_hermetic_link.sh
418418
bash tests/e2e/37_llvm_import_std.sh
419+
420+
# The scripts whose C++ runtime is a package (`llvm.libcxx`) declare
421+
# `# requires: llvm`, which no shard has, and `run_all.sh` exits 0 when it
422+
# skips. They run here, where llvm is installed, and each is held to the
423+
# line it prints only when it ran to the end, and to the line of the step
424+
# that runs a program (#641).
425+
- name: "graph C++ runtime e2e (663, 690, 696)"
426+
run: |
427+
set -o pipefail
428+
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
429+
export MCPP
430+
run_and_assert() { # $1 = script; the remaining arguments are lines it must print
431+
local script="$1"; shift
432+
local log="$RUNNER_TEMP/$(basename "$script").log"
433+
bash "$script" 2>&1 | tee "$log"
434+
for line in "$@"; do
435+
grep -qxF "$line" "$log" || { echo "::error::$script did not print: $line"; exit 1; }
436+
done
437+
}
438+
run_and_assert tests/e2e/663_a_graph_libcxx_over_the_payloads_c_library.sh \
439+
"ok: llvm.libcxx supplies the C++ layer over the payload's C library, and the program runs"
440+
run_and_assert tests/e2e/690_a_shared_library_over_a_graph_cxx_runtime.sh \
441+
'ok: linkage = "static" builds and runs' \
442+
'ok: cxx_runtime = { shared = "self-contained" } links a private copy and runs' \
443+
"PASS: 690 a shared library over a graph C++ runtime is refused or carries a stated private copy"
444+
run_and_assert tests/e2e/696_a_cxx_layer_provider_keeps_its_own_standard.sh \
445+
"PASS: a C++-layer provider compiles its implementation units at its own standard"

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,47 @@
55

66
## [Unreleased]
77

8+
### 链接形态、标准档位与路径长度:#641 与 #642(2026.9.15.2)
9+
10+
一个 UI 框架迁到 macOS 12 下限与 Android 独立共享库时报告的七项,全部在引擎内处理。
11+
设计与实测记录:`.agents/docs/2026-09-15-641-642-*.md`。
12+
13+
- **必需编译器族的版本取自同一载荷的 pin(#641 项 1)。** 全新 home 上
14+
`requires = ["mcpp:compiler=llvm"]` 此前按族比较行 pin,取到 NDK 的
15+
`llvm@30.0.16248370`;`compiler=emsdk` / `compiler=android-ndk` 则一个都匹配不到,
16+
并谎称没有行固定版本。现按 `to_xim_package` 的包名比较(`pinned_versions_for`)。
17+
(单测 `RequiredFamilyPins.*`)
18+
- **C++ 层提供者按自己声明的标准编译实现单元(#641 项 2)。** 提供
19+
`hosted-standard-library` / `mcpp:c++-abi=` 的包若写了 `[package] standard`,其既不
20+
提供也不导入模块的 C++ 单元按该档位编译,模块单元(含 std 模块)仍按图的档位;
21+
于是 c++20 的程序可以使用 `llvm.libcxx`。该档位进入依赖缓存键与指纹;不写的提供者
22+
逐字节不变。(单测 `CxxLayerStandard.*`,e2e 696)
23+
- **工具构建的路径有界(#641 项 3)。** 位于声明包之外的源文件,对象地址改为
24+
`obj/<声明包>/__pkg/<所属包>/<包内路径>`,无所属包时为 `obj/<声明包>/__ext/<目录哈希>/`;
25+
host 工具子构建的暂存目录改为 `<cache>/tool/.build/<16 位哈希>`;ninja 调用的引擎子命令
26+
在 Windows 上以扩展长度路径打开文件。(单测 `ObjectAddress.*`、`PlatformFs.*`、
27+
`ToolStoreScratch.*`,e2e 698)
28+
- **`mcpp pack --features`(#641 项 4)。** 作用于打包的每一次构建(每条 `--target` 腿、
29+
分派格式的两次构建);`mcpp run --format` 把自己的 feature 交给它执行的打包。(e2e 689)
30+
- **图中的 C++ 运行时之上的依赖共享库(#641 项 5)。** 运行时包的对象只链进程序,依赖
31+
的 C++ 共享库此前没有任何 C++ 运行时(Linux 上 lld 拒绝链接程序,macOS 上 dylib
32+
链接失败)。现在编译前拒绝,reason 为 `shared-library-cxx-runtime`,并给出出路;
33+
写明 `cxx_runtime = { shared = "self-contained" }` 时,共享库链接运行时包对象的私有
34+
副本。实测:每个镜像一份副本时,共享库抛出的 `std::runtime_error` 在程序中不能按该类
35+
捕获,拒绝消息写明这一后果。(e2e 690,在 hermetic llvm job 上运行)
36+
- **包声明默认链接形态(#642 E1)。** `[targets.<n>]` 与
37+
`[target.<sel>.targets.<n>]` 中的 `linkage = "static" | "shared"` 是包的默认值,
38+
`kind = "shared"` 仍是约束;根的边 `linkage`、显式的 `[build] dependency_linkage`
39+
依次优先于它,覆盖默认值时打印一行信息而非降级,`--strict` 接受。解析记录的 reason
40+
为 `package-default` 或 `requested`。(单测 `LinkageForm.*`,e2e 692)
41+
- **根构建程序读取依赖的链接形态(#642 E2)。** 依赖的链接形态在根构建程序之前计算一次,
42+
应用位置不变;根构建程序得到 `MCPP_DEP_<NAME>_LINKAGE` 与 `mcpp::dep_linkage(name)`。
43+
依赖的构建程序不提供该值:只有根决定链接形态,且它运行时排在其后的包的输入尚未齐备。
44+
`hasSources` 取自扫描器导出的 `package_source_files`,p1689 扫描器由此也遵循 `!` 排除。
45+
(e2e 693)
46+
- CI:`ci-linux-e2e` 的 hermetic job 直接运行 663、690、696 并断言其结束行;这三份脚本
47+
需要 llvm,分片上一向被跳过。
48+
849
### `mcpp emit build-database`:不写工程目录的构建数据库(#636,2026.9.15.1)
950

1051
新命令按 `mcpp build --configure-only` 的方式、用相同的选择器规划,把计划打印为

0 commit comments

Comments
 (0)