Skip to content

Ensure that MSBuild integration bootstraps Vcpkg#41605

Merged
BillyONeal merged 6 commits into
microsoft:masterfrom
mschofie:mschofie/vcpkg-msbuild-bootstrap
May 11, 2026
Merged

Ensure that MSBuild integration bootstraps Vcpkg#41605
BillyONeal merged 6 commits into
microsoft:masterfrom
mschofie:mschofie/vcpkg-msbuild-bootstrap

Conversation

@mschofie

Copy link
Copy Markdown
Member

Fixes #23366

The current MSBuild integration doesn't bootstrap VCPkg when running in 'manifest' mode - meaning that consumers have to manually run, say, bootstrap-vcpkg.bat before building, or the build fails with errors. #23366 tracks this and calls out the problems in running bootstrap-vcpkg.bat - just adding a target that runs bootstrap-vcpkg.bat can cause concurrency problems on parallel, multi-project builds. When building in parallel, multiple MSBuild 'engines' are invoked for the multiple projects, and multiple could attempt to run bootstrap-vcpkg.bat concurrently, and bootstrap-vcpkg.bat doesn't protect against concurrent execution, resulting in errors writing files. Under CMake this isn't a problem since the CMake integration runs during the CMake 'configuration' phase, which is executed sequentially. But MSBuild doesn't have a similar, single threaded equivalent.

MSBuild does provide a threading guarantee that we can use - it guarantees that an MSBuild task for a given project, and a given set of global properties will run once (called out in the documentation for the MSBuild task). So if we invoke an MSBuild task with a global property of the Vcpkg root to bootstrap then MSBuild will ensure that it is only run once, blocking all other MSBuild engines until the bootstrap is complete. And that's what this PR does.

There's a few pieces to this change:

  1. I introduce the VcpkgAutoBootstrap property and default it to true. This allows consumers to opt-out of the functionality. I'm fine with defaulting to false, and making it opt-in if a more cautious roll-out is needed.
  2. In scripts/buildsystems/msbuild/vcpkg.targets I conditionally import scripts/buildsystems/msbuild/support/Bootstrap.targets that contains the bulk of the implementation. By putting the logic in a separate 'targets' file, then it can be 'firewalled' a little. The conditionality requires:
    1. VcpkgEnableManifest to be true, to only run on manifest builds (a requirement called out in the tracking issue)
    2. VcpkgAutoBootstrap to be true, to allow folks to opt-out (a requirement called out in the tracking issue)
    3. MSBuild is 16.5 and higher - The implementation depends on IBuildEngine6.GetGlobalProperties, which was introduced in MSBuild 16.5. The MSBuild 16.5 release notes don't call this out, I binary searched the "Microsoft.Build.Framework" NuGet packages, and 16.5 is the first version to contain IBuildEngine6.
    4. Windows - I only need this on Windows, so I'm just scoping it for now. If non-Windows support is needed, it can be added separately.
  3. scripts/buildsystems/msbuild/support/Bootstrap.targets provides a VcpkgBootstrap target that marks itself as BeforeTargets="VcpkgInstallManifestDependencies" to ensure that Vcpkg is bootstrapped before it is used. The target also configures Inputs and Outputs appropriately, so that when bootstrapped the target won't be run, and the added cost is minimal. The implementation uses a custom task to get the current global property names, and then invokes MSBuild to run the VcpkgBootstrapImplementation removing all global properties and setting the _ZVcpkgRoot property. MSBuild will only run a single VcpkgBootstrapImplementation instance, and so the work that VcpkgBootstrapImplementation does will only run once.
  4. scripts\buildsystems\msbuild\support\GetGlobalProperties.task provides the implementation of the custom task to get the global properties. The task has a single output parameter - GlobalPropertyNames - which is a semi-colon delimited list of the global property names, that the VcpkgBootstrap target specifies as the RemoveProperties parameter to MSBuild.

I've been using an implementation of this fix in my consuming repo for a week or so, and I've buddy tested this fix by forcing a long delay in bootstrap-vcpkg.bat. On a build where vcpkg.exe isn't present, the VcpkgBootstrap target is 'built' by multiple projects (showing that there's contention by default), but the VcpkgBootstrapImplementation task is only run once (so MSBuild is protecting it). On an incremental build, the VcpkgBootstrap task is skipped entirely, thanks to the MSBuild up-to-date checks.

@JonLiu1993 JonLiu1993 added the category:infrastructure Pertaining to the CI/Testing infrastrucutre label Oct 17, 2024
@Cheney-W Cheney-W added category:tool-update The issue is with build tool or build script, which requires update or should be executed correctly and removed category:infrastructure Pertaining to the CI/Testing infrastrucutre labels Oct 17, 2024
@Cheney-W Cheney-W requested a review from data-queue October 17, 2024 06:13
@mschofie mschofie marked this pull request as ready for review October 17, 2024 17:04
@JonLiu1993 JonLiu1993 added the info:needs-maintainer-attention Lets the current 'on rotation' vcpkg maintainer know they need to look at this. label Oct 21, 2024
@BillyONeal BillyONeal added requires:vcpkg-team-review This PR or issue requires someone on the vcpkg team to take a further look. and removed info:needs-maintainer-attention Lets the current 'on rotation' vcpkg maintainer know they need to look at this. labels Oct 23, 2024
@BillyONeal

Copy link
Copy Markdown
Member

We discussed this and confirm that we would be happy to make this work in MSBuild if a solution to the concurrency problem can be found and the perf impacts aren't too significant.

3. MSBuild is 16.5 and higher - The implementation depends on IBuildEngine6.GetGlobalProperties, which was introduced in MSBuild 16.5. The MSBuild 16.5 release notes don't call this out, I binary searched the "Microsoft.Build.Framework" NuGet packages, and 16.5 is the first version to contain IBuildEngine6.

We still support back to VS2015 so this ends up being kind of a problem. On older MSBuild does this 'explode' or just fail to bootstrap?

I am somewhat concerned with the dependency on RoslynCodeTaskFactory, as not all MSBuild distributions are going to have that.

@mschofie

Copy link
Copy Markdown
Member Author

Thanks for taking a look.

The reason I structured the change the way I did was to 'firewall' the new stuff. Everything in the edited files (vcpkg.props and vcpkg.targets) is as 'portable' MSBuild as I can make it. I couldn't find an explicit declaration of how far back VCPkg's support of MSBuild goes, but in vcpkg.target there's already usage of MSBuild property functions, so I used those in the version check. All 'modern' constructs are in Bootstrap.targets, and that won't be imported if the checks don't pass - that means that older MSBuild's won't even look for Bootstrap.targets and they'll get the existing behavior.

Bootstrap.targets uses a couple of 'modern' MSBuild features:

  1. IBuildEngine6.GetGlobalProperties - This is what motivated the MSBuild 16.5 check blocking the import of Bootstrap.targets. It appears to have first shipped in MSBuild 16.5.
  2. RoslynCodeTaskFactory - The documentation for RoslynCodeTaskFactory calls out that it first shipped in MSBuild 15.8. They give an example to show to use support down-level MSBuild (using CodeTaskFactory instead of RoslynCodeTaskFactory), but since I need MSBuild 16.5 and higher for the IBuildEngine6.GetGlobalProperties call, then I just left RoslynCodeTaskFactory in.

@PhoebeHui PhoebeHui assigned LilyWangLL and unassigned JonLiu1993 Apr 2, 2025
@LilyWangLL

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

BillyONeal
BillyONeal previously approved these changes Jun 20, 2025
@BillyONeal BillyONeal added the info:needs-maintainer-attention Lets the current 'on rotation' vcpkg maintainer know they need to look at this. label Jun 20, 2025
@BillyONeal

Copy link
Copy Markdown
Member

All 'modern' constructs are in Bootstrap.targets, and that won't be imported if the checks don't pass - that means that older MSBuild's won't even look for Bootstrap.targets and they'll get the existing behavior.

OK, this means no blocker to merging it.

I still have reservations about using CodeTaskFactory or RoslynCodeTaskFactory; this pattern has exploded on me on a number of occasions. But I think if that ends up being a serious issue we could just revert this.

I asked for one more confirmation from the other maintainers before landing this, probably Tuesday of next week

Comment thread scripts/buildsystems/msbuild/vcpkg.targets

@BillyONeal BillyONeal 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.

I need to check: We really only want this to run in the "git clone" vcpkg deployment paradigm

@mschofie

mschofie commented Jul 4, 2025

Copy link
Copy Markdown
Member Author

I need to check: We really only want this to run in the "git clone" vcpkg deployment paradigm

Ah, interesting. I just looked at the VS redistribution of 'vcpkg', and it doesn't have bootstrap-vcpkg.bat at all. Which means that this PR needs to accommodate that - at the minute it assumes that bootstrap-vcpkg.bat is present. Would checking for the existence of bootstrap-vcpkg.bat be sufficient to limit this functionality to the "git clone" vcpkg deployment paradigms?

@mschofie

mschofie commented Jul 4, 2025

Copy link
Copy Markdown
Member Author

I'll convert to a draft to prevent this from being completed (is there a better way? I'm more familiar with ADO than GitHub), until I've handled the bootstrap-vcpkg.bat-isn't-present problem.

@mschofie mschofie marked this pull request as draft July 4, 2025 17:22
@mschofie

Copy link
Copy Markdown
Member Author

Accommodated the 'bootstrap' file not being present and a few copy edits in the second commit. I rebased onto the latest origin/master, and buddy tested with and without the bootstrap file.

@mschofie mschofie marked this pull request as ready for review August 11, 2025 19:45
@BillyONeal BillyONeal removed the info:needs-maintainer-attention Lets the current 'on rotation' vcpkg maintainer know they need to look at this. label Oct 31, 2025
@BillyONeal BillyONeal removed the requires:vcpkg-team-review This PR or issue requires someone on the vcpkg team to take a further look. label Dec 23, 2025
@BillyONeal BillyONeal requested review from Copilot and removed request for data-queue March 19, 2026 06:28

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.

Pull request overview

This PR updates the vcpkg MSBuild integration so that, in manifest mode on Windows, vcpkg can be automatically bootstrapped in a way that avoids multi-project parallel build concurrency issues (by leveraging MSBuild’s “same project + same global properties runs once” guarantee).

Changes:

  • Adds a VcpkgAutoBootstrap opt-out property (defaulting to true) for manifest-mode builds.
  • Conditionally imports a new bootstrap orchestration target that triggers before VcpkgInstallManifestDependencies.
  • Introduces a custom MSBuild task to enumerate global property names and then invokes a nested MSBuild call with a controlled global-property set to ensure the bootstrap runs only once.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
scripts/buildsystems/msbuild/vcpkg.targets Conditionally imports bootstrap support targets for eligible builds.
scripts/buildsystems/msbuild/vcpkg.props Adds VcpkgAutoBootstrap property default.
scripts/buildsystems/msbuild/support/GetGlobalProperties.task Adds a RoslynCodeTaskFactory task to read global properties from the build engine.
scripts/buildsystems/msbuild/support/Bootstrap.targets Adds the VcpkgBootstrap target that orchestrates the “run once” bootstrap via nested MSBuild.
scripts/buildsystems/msbuild/support/BootstrapImplementation.targets Adds the actual bootstrap implementation target that runs bootstrap-vcpkg.bat.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread scripts/buildsystems/msbuild/support/BootstrapImplementation.targets Outdated
Comment thread scripts/buildsystems/msbuild/support/GetGlobalProperties.task Outdated
Comment thread scripts/buildsystems/msbuild/support/Bootstrap.targets Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@mschofie

Copy link
Copy Markdown
Member Author

Oh, hey. Some nice due diligence fixes from Copilot. Nice.

Moderate sidebar/discussion: re: microsoft/vcpkg-tool#1913. I don't think this fix would help there. This fix is ensuring that bootstrapping runs, by using MSBuild threading guarantees to avoid contentions. "bootstrapping" is tricky because there's nothing present to help with contentions (because you're bootstrapping), so the only contention prevention we can use is MSBuild itself and that's what this fix uses. From the looks of things (and I'm a little rusty/out-of-the-loop), 1913 is talking about 'installation' contention, that's always been the job of vcpkg-tool. A similar approach to this fix could move the contention prevention 'out' from vcpkg-tool to MSBuild, but I'm not sure that would help a great deal†, and it looks like a really tricky fix.

† - I suppose MSBuild might have the build-graph fidelity to know that the 'targets' would block, so might be able to do other work. The current contention blocking in vcpkg-tool will simply manifest as lots of long-running tasks in MSBuild, which might prevent MSBuild from making other progress..?

@autoantwort

Copy link
Copy Markdown
Contributor

Yes, this PR currently does not help with microsoft/vcpkg-tool#1913.
I guess it could help if we use the same technique and only run vcpkg install once and not for every project.

@BillyONeal

BillyONeal commented Apr 10, 2026

Copy link
Copy Markdown
Member

I guess it could help if we use the same technique and only run vcpkg install once and not for every project.

Yes this is what I meant. Instead of having all the MSBuilds launch different vcpkgs that all block/poll, this tech would let MSBuild do the deduplication itself. (But this PR itself doesn't do that yet)

@autoantwort

Copy link
Copy Markdown
Contributor

@BillyONeal What is the status of this PR from your side?

@autoantwort

Copy link
Copy Markdown
Contributor

One problem I currently have with this approach and vcpkg install is that it seems the process env vars (via SetEnv Task) gets lost in the msbuild task

@BillyONeal

Copy link
Copy Markdown
Member

@BillyONeal What is the status of this PR from your side?

Other stuff keeps getting in the way but it's on the todo list somewhere :(

@autoantwort

Copy link
Copy Markdown
Contributor

@BillyONeal Can we simply drop VS2015 support? That would make some things simpler. VS 2015 is out of extended support (https://learn.microsoft.com/en-us/lifecycle/products/visual-studio-2015)

@BillyONeal

Copy link
Copy Markdown
Member

Related: MicrosoftDocs/vcpkg-docs#573

@BillyONeal BillyONeal 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.

Thank you and sorry it took so long to land this!

@BillyONeal BillyONeal enabled auto-merge (squash) May 7, 2026 01:02
@BillyONeal BillyONeal merged commit 4b41e9a into microsoft:master May 11, 2026
16 checks passed
@mschofie mschofie deleted the mschofie/vcpkg-msbuild-bootstrap branch May 11, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category:tool-update The issue is with build tool or build script, which requires update or should be executed correctly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VS/MSBuild per-project integration that "just works"

9 participants