"""Compile actual public headers and verify MSVC C4996 migration diagnostics.""" import argparse import os from pathlib import Path import subprocess import tempfile parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--arch", choices=["x64", "ARM64"], default="x64") args = parser.parse_args() root = Path(__file__).resolve().parents[1] vc = Path(os.environ["VCToolsInstallDir"]) kit = Path(os.environ["WindowsSdkDir"]) / "Include" / os.environ["WindowsSDKVersion"].strip("\\/") compiler = vc / "bin/Hostx64" / args.arch.lower() / "cl.exe" architecture = ["/D_AMD64_", "/D_AMD64", "/Gz"] if args.arch == "x64" else ["/D_ARM64_", "/DARM64"] common = [ "/nologo", "/c", "/kernel", "/W4", "/WX", "/we4996", "/D_WIN64", "/DWINNT=1", "/DNTDDI_VERSION=0x0A000008", "/D_WIN32_WINNT=0x0A00", *architecture, "/I" + str(vc / "include"), "/I" + str(kit / "km"), "/I" + str(kit / "shared"), "/I" + str(kit / "ucrt"), "/I" + str(root / "include"), ] old = { "DomitoGetPortableExecutableDigestKind": "DomitoGetPortableExecutableDigestKindEx", "DomitoCalculatePortableExecutableDigest": "DomitoCalculatePortableExecutableDigestEx", "DomitoValidateFileLegacyMode": "DomitoValidateFileLegacyModeEx", "DomitoGetProcessImageName": "DomitoGetProcessImageNameEx", } modern = [ *old.values(), "DomitoFreePortableExecutableDigest", "DomitoFreeProcessImageName", "DomitoValidateFileObjectEx", "DomitoValidateFileHandleEx", "DomitoValidateFilePathEx", "DomitoGetCiChainView", "DomitoGetCertificatePublisherName", "DomitoFindModuleBaseAddress", "DomitoFindExportedFunctionAddress", "DomitoReadFile", "DomitoReadFileAt", "CiValidateFileObject", ] prefix = "#include \n#include \n#include \n#include \n#include \n" checks = 0 with tempfile.TemporaryDirectory(prefix="domito-deprecation-") as temp: build = Path(temp) for language in ["c", "cpp"]: for index, (name, replacement) in enumerate([("modern", None), *old.items()]): source = build / (f"check-{index}." + language) refs = modern if replacement is None else [name] source.write_text( prefix + "void Check(void) {\n" + "".join(f" (void)&{ref};\n" for ref in refs) + "}\n" ) result = subprocess.run( [ str(compiler), *common, "/TC" if language == "c" else "/TP", "/Fo" + str(build / "check.obj"), str(source), ], text=True, capture_output=True, ) output = result.stdout + result.stderr if replacement is None: assert result.returncode == 0, output else: assert ( result.returncode != 0 and "C4996" in output and name in output and replacement in output ), output errors = [line for line in output.splitlines() if "error C" in line] assert errors and all("C4996" in line for line in errors), output checks += 1 print(f"PASS: {checks} {args.arch} C/C++ public-header deprecation checks")