Skip to content

build_command_prefix: 'global mode' unsets XLINGS_PROJECT_DIR on POSIX and sets it to the empty string on Windows #614

Description

@Sunrisepeak

The asymmetry (source-confirmed)

src/xlings/xlings.cppm, build_command_prefix, on the same env.projectDir.empty() condition:

if constexpr (mcpp::platform::is_windows) {
    mcpp::platform::env::set("XLINGS_HOME", env.home.string());
    mcpp::platform::env::set("XLINGS_PROJECT_DIR",
              env.projectDir.empty() ? "" : env.projectDir.string());   // ← set to ""
    mcpp::platform::windows::prepend_path(xvmBin);
    return env.binary.string();
} else {
    if (env.projectDir.empty()) {
        // Global mode: unset XLINGS_PROJECT_DIR (existing behavior).
        return std::format(
            "cd {} && env -u XLINGS_PROJECT_DIR PATH={}:\"$PATH\" XLINGS_HOME={} {}", …);
    }
    …
}

The POSIX comment names the intent — "Global mode: unset XLINGS_PROJECT_DIR" — and the Windows branch does not implement it. Absent and present-but-empty are not the same answer to "which scope is this", and xlings resolves its subos scope from that variable.

The same shape appears at the self init call site (env::set("XLINGS_PROJECT_DIR", "") on Windows, env -u XLINGS_PROJECT_DIR on POSIX).

A second, smaller difference in the same block: the Windows branch mutates the process environment with env::set, so the value persists past the invocation, while the POSIX branch scopes it to the one command via env.

Where it surfaced (circumstantial — I cannot prove causation without a Windows box)

xim:vulkan-loader's Windows config() declared one subos.env{ var = "PATH", op = "prepend", … }. Same descriptor, two environments, opposite results:

environment result
full xlings (openxlings/xim-pkgindex windows-test) ✓ local:vulkan-loader@1.4.313 done, [PASS] new shim, subos default present
mcpp project sandbox (mcpplibs/mcpp-index#391, windows leg) E_INTERNAL: [vulkan-loader] failed: config hook failed

In #391 every other leg is green (12 pass / 1 fail) and the loader is downloaded and installed before the hook runs, so the dependency edge and the payload are both fine.

What I could establish from source: the Lua side cannot throw — subos.env and xvm.add only table.insert into _XVM_OPS and return. The failure is therefore in xlings' C++ consumer (apply_subos_env_ops_, src/core/xim/installer.cpp), whose early exits all involve the subos manifest it locates via Config::xvm_artifact_subos_dir() → the scope resolved from XLINGS_PROJECT_DIR. prepend itself is implemented (src/core/subos.cpp discusses its semantics), so the mode is not the problem.

That is where the trail ends without a Windows machine. The asymmetry above is certain; its connection to this failure is a hypothesis.

Diagnosability, which cost most of the time here

xlings logs the precise rejection — log::error("[xim] …") with the variable, the binding and the reason. None of it reaches mcpp's output: the CI log contains no [xim] line at all, only

xlings reported: E_INTERNAL: [vulkan-loader] failed: config hook failed; [vulkan-loader] failed: config hook failed

Surfacing xlings' error-level lines (or an opt-in flag) would have turned this into a one-look diagnosis instead of a source read across three repos.

Status

Not blocking anyone: openxlings/xim-pkgindex#819 routes around it by declaring exports.runtime.libdirs instead, which needs no subos — that is the mechanism the package should have used anyway (mcpp copies a dependency's *.dll beside the executable, src/build/plan.cppm). Filing so the asymmetry is recorded rather than rediscovered.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions