feat(xim): runtime / build deps split (libxpkg schema + resolver/installer kind propagation)#249
Merged
Sunrisepeak merged 5 commits intomainfrom May 1, 2026
Merged
Conversation
… kind
Wires the libxpkg schema split through the resolver and installer:
* `PlanNode` gains `runtime_deps`, `build_deps`, and a `kind`
discriminator. Resolver propagates DepKind through the DFS:
- Runtime parent's runtime_deps stay Runtime.
- Runtime parent's build_deps fork to Build.
- Build subtree stays Build (transitive deps inherit).
- "Runtime wins" upgrade: a node first reached via Build that's
later reached via Runtime is upgraded so the installer activates
it, otherwise the user-requested package would be missing from
their workspace.
* `Installer::execute()` now skips run_config_hook_ for kind=Build
nodes, so the payload lands in xpkgs but no shim/version-DB/workspace
mutation happens. For Runtime nodes with build_deps the installer
injects `XLINGS_BUILDDEP_<UPPER_NAME>_PATH` env vars and prepends
each build dep's bin/ dir to PATH for the install hook subprocess
(and any process it spawns), then restores the env after.
* `cmd_info` shows runtime/build deps separately when the package
declares the new split form, falls back to the legacy "deps" line
otherwise.
* `xmake.lua` adds `--local_libxpkg=PATH` for cross-repo joint
debugging: when set, the libxpkg targets are pulled in via
`includes()` instead of through xrepo's released-version cache,
so in-flight schema changes show up immediately.
Adds e2e/E2E-20: build_deps_split_test.sh (+ fixtures under
tests/e2e/fixtures/build_deps_split/) which installs a fixture pkg
that has both runtime_deps and build_deps and verifies:
- both payloads land in xpkgs/
- runtime dep gets a PATH shim, build dep doesn't
- workspace map doesn't list the build dep
- the install hook saw the env var and could exec the build dep
- pkginfo.build_dep("bdtool") returns the expected fields
…s schema) This commit's resolver/installer/commands changes reference the runtime_deps + build_deps fields on PlatformMatrix that were just added in mcpplibs-xpkg 0.0.32 (mcpplibs-index entry committed in mcpplibs/mcpplibs-index@24309c2). The fixture xpkgs in tests/e2e/fixtures/build_deps_split/ exercise both the legacy array form (loader fan-out) and the new table form via the consumer's xpm.<platform>.deps = { runtime = ..., build = ... } shape.
…xlings sync Symptom: E2E-20 on PR #249 fails on Linux with '[error] failed to build catalog: pkgs/ directory not found' '[error] package bdconsumer not found' Root cause: the previous version of this script cp'd fixtures into the shared $FIXTURE_INDEX_DIR/pkgs/ tree. xlings install internally calls sync_all_repos when the catalog isn't loaded yet, and sync_all_repos runs 'git fetch + reset --hard' against the index repo — clobbering the fixtures we just dropped in. The catalog rebuild then sees only the original 81 entries (no bdconsumer/bdtool/rttool), so install fails with 'package not found'. Fix: follow the same pattern as remove_multi_version_test.sh / xlings_self_replace_test.sh — clone-copy the shared fixture into a runtime-private directory, neutralise its xim-indexrepos.lua to skip sub-index fetching, inject the test-only fixtures there, and have .xlings.json point 'xim' at this private dir. sync_all_repos sees a non-git path and leaves it alone.
# Conflicts: # .github/workflows/xlings-ci-linux.yml
Merged
3 tasks
Sunrisepeak
added a commit
that referenced
this pull request
May 1, 2026
…split + .tar.xz fix (#252) Bumps VERSION from 0.4.9 to 0.4.10. Highlights since 0.4.9: * #250 — `xlings remove xim:xlings` no longer silently terminates on Windows when xlings has only one version installed. Three layered fixes: (1) installer.cppm switches both `remove_shim_if_present` call sites to the error_code overload + log::warn (was throwing filesystem_error from ERROR_SHARING_VIOLATION when DeleteFile hit the running xlings.exe shim, escaping cli::run with no top-level catch → std::terminate, silent CI fail). (2) cmd_remove detects "target is xlings + only one version installed" upfront and refuses with rc=2 + redirect to `xlings self uninstall`. (3) cli::run wraps app.run in a top-level catch for filesystem_error / std::exception / ... so any future stray throw surfaces as a logged error + non-zero rc. Bonus while threading rc properly: cmdline lib stores actions as std::function<void(...)>, so action lambda's int returns were being silently discarded by every cmd_*. Captured via a wrap_rc helper so `xlings install <bad-pkg>` etc actually return non-zero to scripts now. * #249 — Build vs runtime deps schema split (xpkg/libxpkg side at mcpplibs-xpkg 0.0.32). Packages can now declare: `xpm.<platform>.deps = { runtime = {...}, build = {...} }` Runtime deps activate in the workspace as before; build deps land in xpkgs but are NOT activated — the consumer's install hook accesses them via `pkginfo.build_dep("name")` (Lua) or via injected env `XLINGS_BUILDDEP_<UPPER>_PATH` + bin on PATH for the hook subprocess. Legacy `deps = { ... }` array form is preserved via loader fan-out (populates both kinds identically). Resolver DFS propagates DepKind through the dep graph; installer skips `run_config_hook_` for kind=Build so build deps don't pollute the user's PATH or version DB. `xlings info` shows runtime/build deps separately when the new form is used. * #251 — `.tar.xz` / `.tar.lzma` extraction now uses internal liblzma instead of fork-exec'ing the system `xz` binary at runtime. xmake-repo's libarchive package def lists `add_deps("zlib", "bzip2", "lz4", "zstd", "lzma")`, but xrepo's `lzma` is the 7-Zip LZMA SDK (LzmaLib.h, LzmaCompress) while libarchive's CMakeLists actually probes for xz-utils' liblzma (lzma.h, lzma_code) — the right xrepo package is `xz`. Result on main: cmake find_package(LibLZMA) silently failed → libarchive fell back to `archive_read_support_filter_xz_external` → fork-exec'd `xz` at runtime → silent failure on musl-static minimal containers and Windows (no xz binary on PATH). Concrete affected xpkgs: node@* (linux .tar.xz), llvm (macosx-arm64 .tar.xz). Project-private libarchive override in `xmake/packages/libarchive.lua` (set_base("libarchive") + swap deps lzma → xz + force -DENABLE_LZMA=ON). Verified via `nm`: libarchive-xlings.a now has `U lzma_code / lzma_alone_decoder / lzma_crc32 / lzma_end / lzma_properties_decode`; no more "Using external xz program" string in the .a. Migration: 0.4.9 → 0.4.10 is binary-compatible; xlings's own self-replace path handles the upgrade. The new build_deps schema is opt-in (legacy array form keeps working). Drop-the-override criterion (for #251): when xmake-repo merges a fix changing libarchive's `add_deps("lzma")` → `add_deps("xz")`, `xmake/packages/libarchive.lua` can be deleted and the root xmake.lua reverted to `add_requires("libarchive 3.8.7")` + `add_packages("libarchive")`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
runtime_deps+build_deps. Loader fan-out keeps legacydeps = {...}array form working unchanged; newdeps = { runtime = ..., build = ... }table form keeps the two lists separate.pkginfo.build_dep(name)Lua API resolves a build-time dep's payload at hook time via injected env or xpkgs scan. 8/8 LoaderTest pass (incl. 2 new fixtures for both shapes).kind(Runtime/Build) + per-kind dep lists. Resolver propagates kind through DFS — Runtime parent forks build_deps to Build, Build subtree stays Build, "Runtime wins" upgrade on second encounter so user-requested packages always activate. Installer skipsrun_config_hook_for kind=Build (no shim, no workspace mutation, no version DB add) so build deps land in xpkgs/ but never pollute the user's PATH. For Runtime nodes with build_deps, installer injectsXLINGS_BUILDDEP_<UPPER>_PATHenv vars and prepends the build dep's bin/ to PATH around the install hook subprocess.cmd_infoshows runtime/build deps separately when the new schema form is declared.xmake f --local_libxpkg=/path/to/libxpkgpulls libxpkg in viaincludes()so in-flight schema edits show up in xlings without going through xrepo's released-version cache.tests/e2e/build_deps_split_test.sh(E2E-20) installs a fixture pkg with both kinds and asserts payload presence, shim-vs-no-shim, env injection, andpkginfo.build_dep()return values. Wired intoxlings-ci-linux.yml.Why
Today every dep declared by a package becomes part of the active workspace, polluting the user's tool versions even if the dep was only needed at install time. Build-time tools (compilers, patchelf, code generators) are per-consumer concerns — different consumers can require different versions without conflict if treated as build-only. This unblocks several real diamond-conflict scenarios where two packages want incompatible versions of the same tool just for their own builds.
Design doc:
docs/plans/2026-05-01-build-runtime-deps-split.md.Cross-repo coordination
This consumer change requires
mcpplibs-xpkg >= 0.0.32(or whichever version contains theruntime_deps/build_depsfields). Until released, joint-debug via--local_libxpkg=. After libxpkg releases the new version, bumpadd_requires("mcpplibs-xpkg X.Y.Z")inxmake.lua.Test plan