Fix msvc/intel/snippet detect when temp path contains spaces - #7523
Conversation
Pass the temp bat / test binary via the *v variants of os.run / iorun / vrun so os.argv does not split the path on whitespace.
There was a problem hiding this comment.
Code Review
This pull request updates several SDK detection and snippet checking modules to use vector-based process execution functions (e.g., os.runv, os.iorunv) to prevent path splitting on whitespace, which is common on Windows. However, the implementation introduces several bugs because the return signature of os.iorunv differs from os.iorun. Specifically, os.iorunv returns a boolean success status as its first value, causing subsequent string operations on the captured output to fail. These return values need to be correctly unpacked to avoid runtime errors.
| local outdata, errdata = try {function () return os.iorun(genvcvars_bat) end} | ||
| -- @note we use iorunv here so the bat path is not split on whitespace by os.argv, | ||
| -- which breaks detection when the temp file lives under a path with spaces. | ||
| local outdata, errdata = try {function () return os.iorunv(genvcvars_bat, {}) end} |
There was a problem hiding this comment.
The return values of os.iorunv are ok, outdata, errdata, errors. By assigning them to local outdata, errdata, outdata receives the boolean success status and errdata receives the stdout string. This causes errdata to be printed as an error message on line 301 (if stdout is not empty), and more importantly, outdata:split("\n") on line 309 will fail because outdata is a boolean. You should capture the boolean status separately and align the variables with the expected output strings.
| local output = os.iorunv(binaryfile, {}) | ||
| if output then |
There was a problem hiding this comment.
The first return value of os.iorunv is a boolean indicating success, not the output string. Assigning it to output will cause output:trim() to fail on line 264 because output is a boolean. You should capture the status and the output string separately.
local ok, output = os.iorunv(binaryfile, {})
if ok and output then
| local output = os.iorunv(binaryfile, {}) | ||
| if output then |
There was a problem hiding this comment.
The first return value of os.iorunv is a boolean indicating success, not the output string. Assigning it to output will cause output:trim() to fail on line 124 because output is a boolean. You should capture the status and the output string separately.
local ok, output = os.iorunv(binaryfile, {})
if ok and output then
|
? |
| os.run(geniclvars_bat) | ||
| -- @note we use runv here so the bat path is not split on whitespace by os.argv, | ||
| -- which breaks detection when the temp file lives under a path with spaces. | ||
| os.runv(geniclvars_bat, {}) |
Summary
tryrunC/C++/Fortran snippet detection fail on Windows when the user profile name contains a space (e.g.C:\Users\Some Name\...).xmake f --toolchain=msvc(or--toolchain=clang-cl) the user gets a "toolchain not found" error; with plainxmake fxmake silently falls back to MinGW and prints no warning.os.run/os.iorun/os.vrunto the corresponding*vvariant, so the temp file path is no longer parsed byos.argv.Root cause
The detection scripts in
xmake/modules/detect/sdks/write a generated.batunderos.tmpfile()(which on Windows lives under the user profile) and run it viaos.iorun(genvcvars_bat)oros.run(...). These wrappers parse theircmdthroughos.argv, a POSIX-shell-style word splitter (core/src/xmake/os/argv.c:83). Without surrounding quotes the path gets shredded:CreateProcessthen runs against the directoryC:\Users\Someand fails withERROR_BAD_EXE_FORMAT (193). Infind_vstudiothe failure is swallowed by the surroundingtry {}and turned into an emptyvcvarsall = {}. The same root cause hits Intel oneAPI detection on Windows (find_iccenv/find_icxenv/find_ifortenv/find_ifxenv) and anytryrunfeature probe incheck_cxsnippets/check_fcsnippets(cross-platform but rarely tripped on POSIX).Fix
Switch every site that passes a single bare path to its
*vvariant. xmake's C-sideprocess._openvalready knows how to launch a.batdirectly, so nocmd.exewrapping is needed.A short
@notecomment was added at each site so the choice does not get reverted later.Test plan
Verified on Windows 11 with a user profile path containing a space, with VS 2026 Community installed.
xmake lua detect.sdks.find_vstudioafter the fix:{ "2026" = { version = "18.0", vcvarsall_bat = "C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvarsall.bat", vcvarsall = { arm64 = { VCToolsVersion = "14.50.35717", PATH = "...", LIB = "...", INCLUDE = "...", ... }, arm64ec = { ... }, x64 = { ... }, x86 = { ... }, arm = { ... } } } }Before the fix
xmake lua detect.sdks.find_vstudioshows