shell.run with build: true on Windows corrupts the LIB environment variable (%% is not an escape outside batch files), breaking every torch source build
Summary
On Windows, shell.run with build: true emits this line as part of the shell initialization:
CALL set "LIB=%%CONDA_PREFIX%%\Library\lib;%%CUDA_HOME%%\lib;%%LIB%%"This appears intended to make conda-provided CUDA work with PyTorch's cpp_extension, which on Windows hardcodes $CUDA_HOME\lib\x64 — a path that does not exist in conda's flat Library\lib layout.
The intent is correct, but the implementation does not survive the shell. %% is an escape only inside batch files, not on the interactive cmd command line. On the command line %%VAR%% expands to %<value>% — the variable is substituted but the surrounding percent signs remain — so every path in LIB becomes unusable.
Environment
- Pinokio 8.2.0
- Windows 11 Pro (10.0.26200)
- Pinokio-bundled miniforge with conda
cuda 12.8.1 - torch 2.7.0+cu128, Python 3.10
- MSVC 14.29 (VS 2019 Build Tools), Windows SDK 10.0.26100
Actual behaviour
Measured inside the build shell (cmd /v:on /c "echo !LIB!"), split on ;:
%<PINOKIO_HOME>\bin\miniforge%\Library\lib <- broken (CONDA_PREFIX)
%<PINOKIO_HOME>\bin\miniforge\Library%\lib <- broken (CUDA_HOME)
%<MSVC>\Tools\MSVC\<version>\lib\x64 <- broken (leading %)
<SDK>\Lib\<version>\\\ucrt\x64 <- ok
<SDK>\Lib\<version>\\\um\x64 <- ok
<PINOKIO_HOME>\bin\miniforge\Library\lib% <- broken (trailing %)Four of six entries are unusable, including both the conda CUDA lib directory (cudart.lib) and the MSVC lib directory (msvcprt.lib).
setuptools reads LIB and passes it through as library_dirs, so the corrupted paths show up verbatim in the link command:
/LIBPATH:%<PINOKIO_HOME>\bin\miniforge%\Library\lib
/LIBPATH:%<PINOKIO_HOME>\bin\miniforge\Library%\lib
/LIBPATH:<PINOKIO_HOME>\bin\miniforge\Library\lib% c10.lib torch.lib ... cudart.liband the build dies:
LINK : fatal error LNK1181: cannot open input file 'cudart.lib'The linker stops at the first missing library, so cudart.lib is what surfaces. Supplying that one path alone just reveals the next failure, LNK1104: cannot open input file 'msvcprt.lib' — both are symptoms of the same corruption.
Expected behaviour
LIB should contain the intended paths without the surrounding percent signs, so that cudart.lib and msvcprt.lib remain resolvable.
Reproduction
Any launcher that builds a torch CUDA extension from source reproduces this. Minimal check without a build:
// probe.js
module.exports = {
run: [{
when: "{{platform === 'win32'}}",
method: "shell.run",
params: {
build: true,
message: ["cmd /v:on /c \"echo !LIB!\""]
}
}]
}Run it and inspect the output: every %%-derived entry is wrapped in literal %.
Impact
This affects any launcher performing a torch source build under build: true on Windows with the bundled conda CUDA, not one specific script. It is easy to misdiagnose, because the visible error (LNK1181: cudart.lib) points at CUDA rather than at the shell initialization, and because Pinokio's repair attempt makes it look as though conda CUDA is already handled.
Note on env
Setting LIB via a step's env does not work around this: the supplied value is substituted into the same %%LIB%% slot and gets corrupted the same way.
Workaround in use
A batch-file wrapper that rebuilds LIB from the build environment's own standard variables before running the command (inside a .bat, expansion behaves correctly):
@echo off
setlocal
set "LIB=%CUDA_LIB_DIR%;%VCToolsInstallDir%lib\x64;%UniversalCRTSdkDir%Lib\%UCRTVersion%\\\ucrt\x64;%UniversalCRTSdkDir%Lib\%UCRTVersion%\\\um\x64"
%*invoked as call "path\to\fix_lib.bat" uv pip install ... --no-build-isolation, with CUDA_LIB_DIR derived from {{path.resolve(which('nvcc'), '..', '..', 'lib')}}. With this in place, nvdiffrast and nvdiffrec build and install successfully.
Possible fix
Emit the line so it survives command-line parsing — for example by resolving the values in the kernel before writing the command, or by moving the assignment into a batch file where %% is a valid escape.
Source: pinokiocomputer/pinokio