11diff --git a/extensions.bzl b/extensions.bzl
2- index af11d90..30dbd3b 100644
2+ index af11d90..97789d3 100644
33--- a/extensions.bzl
44+++ b/extensions.bzl
5- @@ -50,13 +50,16 @@ load(
5+ @@ -50,13 +50,17 @@ load(
66 "merge_flags",
77 )
88 load("//private:llvm_repo.bzl", "llvm_repo")
@@ -15,18 +15,21 @@ index af11d90..30dbd3b 100644
1515 "VALID_MSVC_TARGETS",
1616+ "detect_vc_msbuild_toolset",
1717 "download_and_map",
18+ + "find_msvc_release_channel",
1819+ "get_msbuild_package_ids",
1920 "get_msvc_package_ids",
2021 "get_msvc_redist_package_ids",
2122 "get_winsdk_msi_list",
22- @@ -546,6 +549,42 @@ def _extension_impl(module_ctx):
23+ @@ -546,6 +550,44 @@ def _extension_impl(module_ctx):
2324 "winsdk_version": winsdk_version,
2425 })
2526
2627+ # 5. Construct the MSBuild repo definition. MSBuild is versioned per Visual
2728+ # Studio line, not per MSVC toolset, so a single repo is derived from the
28- + # channel that owns the default MSVC version.
29- + msbuild_packages_map = packages_maps[msvc_versions_dict[default_msvc_for_repo]]
29+ + # channel that released the default MSVC version. Engine and VC project system
30+ + # both come from it, which keeps VisualStudioVersion, the VCTargetsPath tree and
31+ + # the PlatformToolset consistent with the pinned compiler.
32+ + msbuild_packages_map = packages_maps[find_msvc_release_channel(packages_maps, default_msvc_for_repo)]
3033+ msbuild_toolset_dir, msbuild_platform_toolset = detect_vc_msbuild_toolset(msbuild_packages_map, all_targets)
3134+ msbuild_deps = get_msbuild_package_ids(
3235+ msbuild_packages_map,
@@ -62,7 +65,7 @@ index af11d90..30dbd3b 100644
6265 msiutil_repo(name = "msiutil")
6366 msiutil_label = "@msiutil//:{}".format("msiutil.exe" if normalize_repository_os(module_ctx.os.name) == "windows" else "msiutil")
6467
65- @@ -565,6 +604 ,16 @@ def _extension_impl(module_ctx):
68+ @@ -565,6 +607 ,16 @@ def _extension_impl(module_ctx):
6669 )
6770 continue
6871
@@ -385,7 +388,7 @@ index de153d3..f77afdb 100644
385388 return ctx.repo_metadata(reproducible = True)
386389
387390diff --git a/private/vs_channel_manifest.bzl b/private/vs_channel_manifest.bzl
388- index 49ab406..0615423 100644
391+ index 49ab406..ca2d048 100644
389392--- a/private/vs_channel_manifest.bzl
390393+++ b/private/vs_channel_manifest.bzl
391394@@ -57,10 +57,19 @@ def download_and_map(ctx, channel_url):
@@ -510,3 +513,33 @@ index 49ab406..0615423 100644
510513 # Valid values for hosts: x86, x64, arm64
511514 VALID_MSVC_HOSTS = ["x86", "x64", "arm64"]
512515
516+ @@ -273,6 +375,29 @@ def list_msvc_version(packages_maps):
517+ versions[version] = package_map_key
518+ return {v: versions[v] for v in sorted(versions.keys())}
519+
520+ + def find_msvc_release_channel(packages_maps, version):
521+ + """Returns the key of the oldest channel manifest shipping the given MSVC version.
522+ +
523+ + ``list_msvc_version`` prefers the newest channel when versions overlap, which is
524+ + the wrong choice for MSBuild: its VC project system has to come from the Visual
525+ + Studio line that released the toolset, otherwise a pinned compiler is driven by a
526+ + newer PlatformToolset than it was built for.
527+ +
528+ + Args:
529+ + packages_maps: Dict mapping package_map id (e.g., "18", "17") to package_map.
530+ + version: MSVC toolset version, e.g. "14.44".
531+ +
532+ + Returns:
533+ + The packages_maps key of the oldest channel containing that version.
534+ + """
535+ + prefix = "Microsoft.VC.{}.".format(version).lower()
536+ + for package_map_key in sorted(packages_maps.keys()):
537+ + for pkg_id in packages_maps[package_map_key]:
538+ + if pkg_id.startswith(prefix):
539+ + return package_map_key
540+ +
541+ + fail("No Visual Studio channel manifest ships MSVC {}".format(version))
542+ +
543+ def get_msvc_redist_package_ids(
544+ packages_map,
545+ version,
0 commit comments