#!/usr/bin/env python3 import argparse import re import shutil import subprocess import sys from pathlib import Path BEGIN_RES = "# >>> CRT_RESOURCES >>>" END_RES = "# <<< CRT_RESOURCES <<<" BEGIN_SEC = "; >>> VC_REDIST_SECTION >>>" END_SEC = "; <<< VC_REDIST_SECTION <<<" REPO_ROOT = Path(__file__).resolve().parents[2] DEFAULT_CARGO_TOML = REPO_ROOT / "packages" / "oneclient_app" / "Cargo.toml" DEFAULT_OUT = REPO_ROOT / "target" / "crt" VSWHERE = Path( r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" ) CRT_GLOB = r"VC\Redist\MSVC\**\x64\Microsoft.VC*.CRT\*.dll" SECTION_REPLACEMENT = """; >>> VC_REDIST_SECTION >>> ; <<< VC_REDIST_SECTION <<<""" def region(begin: str, end: str) -> re.Pattern: return re.compile( r"^[ \t]*" + re.escape(begin) + r".*?^[ \t]*" + re.escape(end) + r"[ \t]*$", re.DOTALL | re.MULTILINE, ) REGION_RES = region(BEGIN_RES, END_RES) REGION_SEC = region(BEGIN_SEC, END_SEC) def find_crt_dir() -> Path: """Locate the newest x64 Microsoft.VC*.CRT redist directory via vswhere.""" if not VSWHERE.is_file(): sys.exit(f"error: vswhere not found at {VSWHERE}; pass --crt-dir explicitly") out = subprocess.run( [str(VSWHERE), "-latest", "-products", "*", "-find", CRT_GLOB], capture_output=True, text=True, check=True, ).stdout dirs = {Path(line).parent for line in out.splitlines() if line.strip()} if not dirs: sys.exit(f"error: vswhere found no DLLs matching {CRT_GLOB}") newest = sorted(dirs, key=lambda p: p.parts)[-1] print(f"CRT redist dir: {newest}") return newest def collect(crt_dir: Path, out_dir: Path) -> list[Path]: dlls = sorted(crt_dir.glob("*.dll")) if not dlls: sys.exit(f"error: no DLLs in {crt_dir}") if out_dir.exists(): shutil.rmtree(out_dir) out_dir.mkdir(parents=True) copied = [] for dll in dlls: dest = out_dir / dll.name shutil.copy2(dll, dest) copied.append(dest) print(f" {dll.name} ({dest.stat().st_size} bytes)") return copied def patch(cargo_toml: Path, dlls: list[Path]) -> None: text = cargo_toml.read_text(encoding="utf-8") for pat, name in ((REGION_RES, "CRT_RESOURCES"), (REGION_SEC, "VC_REDIST_SECTION")): if not pat.search(text): sys.exit(f"error: {name} region not found in {cargo_toml}") entries = "\n".join( f' {{ src = "{str(d).replace(chr(92), chr(92) * 2)}", target = "{d.name}" }},' for d in dlls ) block = ( f" {BEGIN_RES}\n" f" # Generated by distribution/windows/bundle-crt.py -- do not edit by hand.\n" f"{entries}\n" f" {END_RES}" ) text = REGION_RES.sub(lambda _: block, text, count=1) text = REGION_SEC.sub(lambda _: SECTION_REPLACEMENT, text, count=1) cargo_toml.write_text(text, encoding="utf-8") print(f"patched {cargo_toml} with {len(dlls)} app-local CRT DLLs") def main() -> None: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--cargo-toml", type=Path, default=DEFAULT_CARGO_TOML) ap.add_argument("--out-dir", type=Path, default=DEFAULT_OUT) ap.add_argument( "--crt-dir", type=Path, help="Microsoft.VC*.CRT directory to copy from (default: ask vswhere)", ) args = ap.parse_args() crt_dir = args.crt_dir.resolve() if args.crt_dir else find_crt_dir() dlls = collect(crt_dir, args.out_dir.resolve()) patch(args.cargo_toml.resolve(), dlls) if __name__ == "__main__": main()