Skip to content

[vcpkg] vcpkg install fails on windows when binary caching is enabled with CreateProcessW #25521

@bengaineyarm

Description

@bengaineyarm

Describe the bug

Running vcpkg install fails with error: calling CreateProcessW failed with 2 (The system cannot find the file specified.) when attempting to fetch binaries from the binary cache.

Using --debug, I can see that it is the CreateProcessW(curl ...) command, invoked from download_files_inner (https://github.com/microsoft/vcpkg-tool/blob/2022-06-17/src/vcpkg/base/downloads.cpp#L356) that is failing.

Manually executing the curl command listed in the output works as expected.

Initially, I attempted to debug this by rebuilding vcpkg.exe, but in doing so, the error disappeared. This is due to the fact that I built a 64-bit version of vcpkg.exe instead of a 32-bit version, switching to the 32-bit version, compiled locally from the 2022-06-17 tag, I was able to reproduce. So it seems that the failure only occurs with a 32-bit vcpkg.exe.

I am running the build within a Windows container (Docker), so I assumed that the build was somehow failing to run C:\Windows\System32\curl.exe, but modifying vcpkg.exe to explicitly use that path, rather than "curl" fails in the same manor. However, leaving the command as "curl" and modifying the path to include the curl binaries available from the curl website (https://curl.se/windows/) works (in so far as CreateProcessW does not fail, the formatting of the output is slightly different necessitating a change to the -w parameter to make it work properly). Likewise, building curl using .\vcpkg.exe --triplet=x64-windows-static install curl[tool] and copying the created curl binary into the container so that it is available on the path also works.

Comparing the binaries, between the shipped C:\windows\system32\curl.exe and the one that I built using vcpkg, it seems that the main difference is that the shipped version is dynamically linked against ucrt (there are multiple references to api-xxxx.dll), whereas the vcpkg version is statically linked and the only referenced dlls are things like kernel32.dll. Now, if I copy c:\window\system32\curl.exe, and the various api-xxxx.dll files and stick them together in one folder on the path, vcpkg works as expected and successfuly attepts to fetch from our binary cache.

In summary:

vcpkg, running in a windows container fails to execute the built in curl.exe, but only when compiled as a 32-bit binary. It appears to do something to the library search path that prevents curl from finding its dependencies.

Environment

  • OS: Windows, Inside a Windows Container based FROM mcr.microsoft.com/windows/servercore:20H2-amd64
  • Compiler: Visual Studio Build Tools 2022

To Reproduce

Steps to reproduce the behavior:

  1. Install docker engine using the binaries provided: https://docs.docker.com/engine/install/binaries/#install-server-and-client-binaries-on-windows

  2. Using the following dockerfile, built with docker build -t buildtools:latest -m 4GB .

     # escape=`
    
     FROM mcr.microsoft.com/windows/servercore:20H2-amd64
    
     SHELL ["powershell.exe", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"]
    
     RUN `
       # Install Git
       ; curl.exe -SL "https://github.com/git-for-windows/git/releases/download/v2.36.1.windows.1/Git-2.36.1-64-bit.exe" -o "git-install.exe"  `
       ; Start-Process "git-install.exe" -NoNewWindow -Wait -ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/NOCANCEL", "/SP-", "/LOG", `
     	    "/DIR=C:\Tools\Git", "/COMPONENTS=gitlfs",  "/o:CRLFOption=CRLFAlways", "/o:BashTerminalOption=ConHost", "/o:GitCredentialManagerOption=Disabled", `
     	    "/o:EnableSymlinks=Enabled", "/o:EnablePseudoConsoleSupport=Enabled" `
       ; Remove-Item "git-install.exe"  `
       # Install MSVC Build Tools 2022
       ; curl.exe -SL "https://aka.ms/vs/17/release/vs_buildtools.exe" -o "vs_buildtools.exe"  `
       ; Start-Process "vs_buildtools.exe" -NoNewWindow -Wait -ArgumentList "--quiet", "--wait", "--norestart", "--nocache", `
     	    "--installPath", "C:\Tools\BuildTools2022", `
     	    "--add", "Microsoft.Component.MSBuild", `
     	    "--add", "Microsoft.VisualStudio.Component.Windows10SDK", `
     	    "--add", "Microsoft.VisualStudio.Component.Windows10SDK.18362", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.ASAN", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.ATL", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.ATL.ARM64", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.CMake.Project", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.CoreBuildTools", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.Llvm.Clang", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.MFC", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.MFC.ARM64", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", `
     	    "--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", `
     	    "--add", "Microsoft.Component.VC.Runtime.UCRTSDK" `
       ; Remove-Item "vs_buildtools.exe"  `
       # Configure environment
       ; $env:Path = $env:Path `
     	          + ';C:\Tools\BuildTools2022\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin' `
     	          + ';C:\Tools\Git\bin' `
     	          + ';C:\Users\ContainerAdministrator\AppData\Local\Programs\Git\bin' `
       ; setx.exe /M Path $env:Path
    
     # Define the entry point for the docker container.
     # This entry point starts the developer command prompt and launches the PowerShell shell.
     ENTRYPOINT ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
    
  3. Run the container using docker run -it --rm buildtools:latest

  4. Setup binary caching env vars pointing to some remote blob-cache server (we also use asset caching which is equally affected), e.g. with:

     Set-Item -force -path "ENV:VCPKG_BINARY_SOURCES" -value "clear;default;x-azblob,https://<AUTH>@<SOME-SERVER>/<PATH>/,,readwrite"
     Set-Item -force -path "ENV:X_VCPKG_ASSET_SOURCES" -value "clear;x-azurl,https://<AUTH>@<SOME-SERVER>/<PATH>/,,readwrite"
    
  5. Fetch, and bootstrap vcpkg to tag 2022.06.16.1

  6. Attempt to run vcpkg install on some project or package, with binary caching enabled so that vcpkg attempts to fetch binaries from the server (it doesn't matter that they are not there).

     .\vcpkg.exe --debug install "curl[tool]"
    
  7. Observe failure.

  8. To then observe success:

     mkdir C:\Curl\
     copy C:\Windows\System32\curl.exe C:\Curl\
     copy C:\Windows\System32\downlevel\*.dll C:\Curl
     $env:Path = 'C:\Curl;' + $env:Path
     .\vcpkg.exe --debug install "curl[tool]"
    

Expected behavior

Binary caching should work as expected; executing curl should not fail with CreateProcessW error=2.

Metadata

Metadata

Assignees

Labels

category:vcpkg-bugThe issue is with the vcpkg system (including helper scripts in `scripts/cmake/`)requires:tool-releaseAn issue that has been fixed in the microsoft/vcpkg-tool repo and is waiting for a release thereof

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions