-
Notifications
You must be signed in to change notification settings - Fork 7k
Ensure that MSBuild integration bootstraps Vcpkg #41605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Ensure that MSBuild integration bootstraps Vcpkg #41605
Conversation
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.
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 |
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 (
|
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
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 |
4. The OS is Windows. | ||
--> | ||
<Import Condition="'$(VcpkgEnableManifest)' == 'true' and '$(VcpkgAutoBootstrap)' == 'true' and $([System.Version]::new($(MSBuildVersion))) >= $([System.Version]::new(16, 5)) and $([MSBuild]::IsOSPlatform('Windows'))" | ||
Project="$(MSBuildThisFileDirectory)\support\Bootstrap.targets" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to make sure this file is in neither the VS version or the "one-liner" version. (No change requested in this PR)
Or export
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: investigate interaction with https://github.com/microsoft/vcpkg-tool/blob/d0d4200c1824a3df2d5344696f50bbadee25398f/src/vcpkg/commands.export.cpp#L151
There was a problem hiding this comment.
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
Ah, interesting. I just looked at the VS redistribution of 'vcpkg', and it doesn't have |
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 |
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 runningbootstrap-vcpkg.bat
- just adding a target that runsbootstrap-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 runbootstrap-vcpkg.bat
concurrently, andbootstrap-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:
VcpkgAutoBootstrap
property and default it totrue
. This allows consumers to opt-out of the functionality. I'm fine with defaulting tofalse
, and making it opt-in if a more cautious roll-out is needed.scripts/buildsystems/msbuild/vcpkg.targets
I conditionally importscripts/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: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 containIBuildEngine6
.scripts/buildsystems/msbuild/support/Bootstrap.targets
provides aVcpkgBootstrap
target that marks itself asBeforeTargets="VcpkgInstallManifestDependencies"
to ensure that Vcpkg is bootstrapped before it is used. The target also configuresInputs
andOutputs
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 invokesMSBuild
to run theVcpkgBootstrapImplementation
removing all global properties and setting the_ZVcpkgRoot
property. MSBuild will only run a singleVcpkgBootstrapImplementation
instance, and so the work thatVcpkgBootstrapImplementation
does will only run once.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 theVcpkgBootstrap
target specifies as theRemoveProperties
parameter toMSBuild
.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, theVcpkgBootstrap
target is 'built' by multiple projects (showing that there's contention by default), but theVcpkgBootstrapImplementation
task is only run once (so MSBuild is protecting it). On an incremental build, theVcpkgBootstrap
task is skipped entirely, thanks to the MSBuild up-to-date checks.