Skip to content

Handle xwin cache paths containing spaces - #229

Open
Audacity88 wants to merge 2 commits into
rust-cross:mainfrom
Audacity88:codex/handle-xwin-cache-paths-with-spaces
Open

Handle xwin cache paths containing spaces#229
Audacity88 wants to merge 2 commits into
rust-cross:mainfrom
Audacity88:codex/handle-xwin-cache-paths-with-spaces

Conversation

@Audacity88

Copy link
Copy Markdown

Summary

  • Pass generated MSVC linker search paths through a target-scoped Cargo --config array so each path remains one rustc argument when the xwin cache directory contains spaces.
  • Quote generated MSVC include paths and enable cc-rs shell parsing so C, C++, bindgen, and resource compiler consumers preserve the same paths.
  • Add regression coverage for both environment-string contracts with a cache path containing spaces.

Problem

cargo xwin currently serializes generated -Lnative arguments through the space-separated target rustflags variable. A cache path containing a space is rejected by cargo-config2 before compilation with flag in rustflags must not contain its separator (' ').

Using a TOML array resolves that failure without restoring global encoded rustflags, which would leak Windows linker flags into cross-target artifact dependencies. The generated clang-cl include flags also need quoting. Without shell-escaped parsing, cc-rs splits an SDK include path at the space and clang-cl cannot find the Windows headers.

Approach

The spawned Cargo command receives the already-resolved target.<triple>.rustflags as a --config TOML array. This preserves cargo-xwin's existing flag-resolution behavior while keeping each complete SDK path intact and retaining the target isolation introduced for cross-target artifact dependencies. The option is inserted before any trailing -- arguments used by cargo test, cargo run, or cargo bench. The include-path helper emits quoted arguments for CL_FLAGS, target CFLAGS and CXXFLAGS, bindgen, and RCFLAGS; CC_SHELL_ESCAPED_FLAGS=1 tells cc-rs to parse those quoted arguments as shell-escaped flags.

Validation

  • A downstream cargo xwin check --locked -p zeroclaw-providers --target x86_64-pc-windows-msvc --tests completed successfully with xwin cache and Cargo target paths containing spaces.
  • git diff --check passes.
  • cargo test --locked compiler::clang_cl::tests passes (3 passed, 0 failed).

@Audacity88
Audacity88 marked this pull request as ready for review August 21, 2026 20:56

@messense messense left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! The --config target.<triple>.rustflags=[…] approach is the right way around cargo-config2's separator error, and the unit tests / fmt / clippy all pass locally. A few issues before this can land, though:

Blocking

1. Quoted include paths break everyone on cc < 1.1.11, even without spaces.
CC_SHELL_ESCAPED_FLAGS was only added in cc-rs 1.1.11 (Aug 2024, rust-lang/cc-rs#1181). Older cc ignores the env var and whitespace-splits CFLAGS_*, so /imsvc "/home/u/.cache/cargo-xwin/crt/include" becomes a literal argument with the quote characters in it and clang-cl can't find the headers. Lockfiles pinned to cc 1.0.x are still very common, so this would regress the default (no-spaces) case for a lot of users. Could we only quote / set CC_SHELL_ESCAPED_FLAGS when the cache path actually contains whitespace? That keeps today's behaviour for everyone else, and we can document the cc-rs requirement for the spaces case.

2. cargo xwin env regression.
src/env.rs only prints cmd.get_envs(). With the rustflags now passed as a --config argument, the -Lnative=… paths disappear from cargo xwin env output entirely, so eval "$(cargo xwin env)" && cargo build --target x86_64-pc-windows-msvc no longer links. env needs to keep emitting something equivalent (e.g. fall back to CARGO_TARGET_<T>_RUSTFLAGS there), or the --config path should be limited to the spawned command.

Should address

3. CC_SHELL_ESCAPED_FLAGS=1 is global, not target-scoped.
It changes how cc-rs parses all *FLAGS for the whole cargo run, including host builds (build scripts, proc-macros) and the user's own CFLAGS/CXXFLAGS/CL_FLAGS, which are appended verbatim. Anything with backslashes (/IC:\foo on a Windows host) or quotes now gets reinterpreted. Another reason to only enable it when needed, plus a README note.

4. RCFLAGS quoting is unverified.
RCFLAGS is consumed by embed-resource, not cc-rs, and I don't think the cargo check in the validation section exercised any .rc files. Please confirm embed-resource handles quoted args before changing the format. src/compiler/clang.rs still emits unquoted RCFLAGS, so the two backends would also disagree.

5. Rebuilding the Command in insert_cargo_config.
This silently drops anything get_* can't read back (env_clear, stdio, pre_exec). Nothing sets those today so it works, but it's fragile. Simpler: add --config where the command is built (build_command in src/macros.rs, run.rs, test.rs, bench.rs), e.g. by having apply_command_env return the extra args.

Minor

  • Please keep the note that RUSTFLAGS / CARGO_ENCODED_RUSTFLAGS are already folded into rustflags via cargo-config2; otherwise the new env_remove calls look like they drop user flags.
  • The new tests cover the string formats well, but nothing exercises the real case end-to-end. A CI step with a cache path containing a space (XWIN_CACHE_DIR="… /xwin cache") would be the actual regression guard.

@Audacity88

Copy link
Copy Markdown
Author

Thanks for the detailed review. I revised the branch locally to address each point:

  • Cache paths are quoted and CC_SHELL_ESCAPED_FLAGS=1 is set only when the resolved path contains whitespace. Ordinary paths retain the previous unquoted flag format, so projects pinned to cc < 1.1.11 are unchanged. The README now documents the cc >= 1.1.11 requirement for spaced paths.
  • Spawned Cargo commands use target-scoped --config target.<triple>.rustflags=[...], while cargo xwin env keeps emitting CARGO_TARGET_<TRIPLE>_RUSTFLAGS. The comment explaining that cargo-config2 has already resolved inherited rustflags is retained.
  • The command-rebuilding helper is removed. Each builder now adds generated --config arguments before its trailing -- arguments, preserving the original Command and its process configuration.
  • RCFLAGS is restored to its existing unquoted format because its quoting contract was not verified. The README explicitly excludes Windows resource compilation from the spaced-cache-path claim.
  • CI now performs a real hello-tls build with an XWIN_CACHE_DIR containing a space on the stable Ubuntu clang-cl job.

Local validation on the revised tree:

  • cargo fmt --all -- --check
  • RUST_TEST_THREADS=1 cargo test --locked (7 passed)

The serial test setting avoids the existing process-wide RUSTFLAGS race between the is_static_crt_enabled unit tests. Hosted CI is green on ab43fb54cce0, including the stable Ubuntu clang-cl job with the new end-to-end spaced-cache-path build.

@Audacity88
Audacity88 requested a review from messense August 25, 2026 00:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants