Skip to content

[vcpkg.targets] Skip applocal when the installed bin directory does not exist - #54330

Open
Alexandre Zollinger Chohfi (azchohfi) wants to merge 2 commits into
microsoft:masterfrom
azchohfi:applocal-skip-without-installed-bin
Open

Alexandre Zollinger Chohfi (azchohfi) wants to merge 2 commits into
microsoft:masterfrom
azchohfi:applocal-skip-without-installed-bin

Conversation

@azchohfi

Copy link
Copy Markdown

AppLocalFromInstalled runs after every link and starts vcpkg.exe z-applocal to copy DLLs from
installed\<triplet>\[debug\]bin next to the binary. When that directory does not exist, there is
nothing to copy, but the process still starts. With the user-wide integration
(vcpkg integrate install), this happens in every C++ project built with MSBuild on the machine,
including ones that use no vcpkg packages. CMake's Visual Studio generator alone builds two such
projects in every fresh configure: the compiler-ID project and the ABI try_compile.

This adds one condition to the target:

   <Target Name="AppLocalFromInstalled" AfterTargets="CopyFilesToOutputDirectory" BeforeTargets="CopyLocalFilesOutputGroup;RegisterOutput"
-          Condition="'$(_ZVcpkgClassicOrManifest)' == 'true' and '$(VcpkgApplocalDeps)' == 'true' and '$(LinkSkippedExecution)' != 'true' and '@(Link)' != ''">
+          Condition="'$(_ZVcpkgClassicOrManifest)' == 'true' and '$(VcpkgApplocalDeps)' == 'true' and '$(LinkSkippedExecution)' != 'true' and '@(Link)' != ''
+                     and Exists('$(_ZVcpkgCurrentInstalledDir)$(_ZVcpkgConfigSubdir)bin')">

The path is the same one the target already passes as --installed-bin-dir.

Manifest mode

MSBuild evaluates a target's Condition when the target is about to run, not when the project is
loaded. In manifest mode, VcpkgInstallManifestDependencies (BeforeTargets="ClCompile") has
created vcpkg_installed\<triplet>\... by then, so the check sees it. Tested below, on a project
whose vcpkg_installed did not exist before the build.

Testing

Each case is a full -t:Rebuild of a real linked C++ project, CMake's generated
CompilerIdCXX.vcxproj, at -v:d. It records whether AppLocalFromInstalled ran and what it
copied. Integration from this branch; vcpkg-tool 2026-09-26.

mode case AppLocalFromInstalled DLL deployed
classic no installed\ tree, without this change runs (z-applocal, copies nothing) —
classic no installed\ tree, with this change skipped —
classic the bin directory the target resolves for this project (installed\x64-windows\bin) holds a DLL the binary imports runs yes
manifest dependency on an overlay port that installs a DLL into bin and debug\bin; vcpkg_installed absent before the build runs, after the install step yes
manifest no dependencies (vcpkg_installed created, no bin) skipped —

No CI or test in this repository covers scripts/buildsystems/msbuild. git diff --check is
clean. Not tested: x86/arm64 triplets, static triplets, vcpkg export --nuget packages,
Release configuration.

Numbers

CMake's Visual Studio 18 generator on a two-file C++ project with the user-wide integration and no
installed\ tree. Each pass runs every case once, in rotating order; values are medians in ms,
and the brackets are the 95% bootstrap CI of the per-pass paired difference. Windows 11, i9-14900K,
MSBuild 18.10, CMake 4.4.3.

cmake -S . -B build / cmake --build build no integration master master + this change saved by this change
configure, Dev Drive 2,082 2,424 2,079 242 [192, 480]
build, Dev Drive 2,110 2,232 2,105 137 [−16, 278]
configure, C: (NTFS) 2,509 2,799 2,471 360 [197, 542]
build, C: 2,091 2,358 2,216 187 [13, 281]
  • This run. Integration from master 9b4c015 (2026-10-05); 12 passes, on a shared machine
    (load canary 1.17 before, 1.12 after).
  • An earlier run on a quiet machine. Integration from a9d71f3 (2026-10-03), whose
    scripts/buildsystems/msbuild files are byte-identical to master's; 11 passes:
    • configure: 184 ms saved [139, 263];
    • build: 93 ms saved [55, 120];
    • with the change, both are within noise of no integration: configure +41 [−19, 109], build
      +1 [−20, 90].

Context

#52315 made z-applocal the default instead of pwsh applocal.ps1, which removed most of this
cost (about 1.2 s per configure on a checkout from 2025). What remains is starting vcpkg.exe
once per linked project when there is nothing to deploy.

…ot exist

AppLocalFromInstalled starts vcpkg.exe z-applocal after every link, to copy
DLLs from installed\<triplet>\[debug\]bin next to the binary. When that
directory does not exist, there is nothing it could copy. This happens with
the user-wide integration (vcpkg integrate install) in every C++ project
that uses no vcpkg packages, including the compiler-identification and
try_compile projects that CMake's Visual Studio generator builds.

Add Exists() on that directory to the target's condition. Target conditions
are evaluated when the target is about to run, so in manifest mode the
directory created by VcpkgInstallManifestDependencies earlier in the same
build is seen.
Copilot AI balanced review requested due to automatic review settings October 6, 2026 04:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The focused condition uses the existing app-local path and is supported by relevant manual testing.

Review effort: Balanced
Findings: None

What changed in this PR

Avoids unnecessary MSBuild app-local deployment when the selected vcpkg binary directory is absent.

Changes:

  • Adds an execution-time directory existence check to AppLocalFromInstalled.
  • Preserves manifest-mode behavior after dependency installation.
File Description
scripts/​buildsystems/​msbuild/​vcpkg.targets Skips app-local deployment when no installed bin directory exists.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Pre-existing, reported by the PR whitespace check when the file is edited.

This branch has not been deployed

No deployments
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