mirror of
https://github.com/openai/codex.git
synced 2026-09-11 20:36:49 +00:00
## What changed - Add explicit x64 and ARM64 targets for native builds, runtime preparation, and linking using the existing voice recipes. Each target requires native Windows execution of the matching architecture. - Declare compiler, SDK, Python, and CMake inputs; require an explicitly supplied Cygwin/pkgconf tool tree and a fixed `SystemRoot`. Validate installed tool selections against the manifest and declared files. - Pair Windows DLLs with SDK import libraries, preserve plugin and receipt runfiles, and omit Unix runtime-search flags. Use Python for portable payload copying. - Correct the MSVC ARM64 tool directory casing to `HostArm64` and document provisioning and build commands. The generic Rust-consumer aliases remain separate; native Windows Bazel execution and consumer validation are still needed to establish complete Windows voice support. ## Testing Add eight unit tests covering tool selection, path anchoring, invalid inputs, and DLL/import-library copying, plus x64 and ARM64 link smoke targets that reference `gst_version`. GitOrigin-RevId: fb2b4998e9ffb5b64ca830ebf4bb4633fc959eb9
172 lines
6.6 KiB
Python
172 lines
6.6 KiB
Python
"""Adapt declared Windows tool paths to the existing native build/runtime recipes."""
|
|
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
import shutil
|
|
import sys
|
|
import tarfile
|
|
import tempfile
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
from build_native import NativeBuild
|
|
from windows_build_inputs import build_environment
|
|
|
|
|
|
def selected_inputs(config, root):
|
|
inputs = dict(config["inputs"])
|
|
tools = {name: (root / path).absolute() for name, path in inputs["tools"].items()}
|
|
manifest = (root / config["manifest"]).absolute()
|
|
declared = {(root / path).absolute() for path in config["installed_files"]}
|
|
if manifest.stat().st_size > 65536:
|
|
raise ValueError("installed Windows tool metadata exceeds limits")
|
|
installed = json.loads(manifest.read_text(encoding="utf-8"))
|
|
expected = {"shell", "make", "cygpath", "automake", "pkg_config"}
|
|
if (
|
|
installed.get("schemaVersion") != 1
|
|
or installed.get("target") != inputs["target"]
|
|
or installed.get("cygwinArchitecture") != "x86_64"
|
|
or set(installed.get("tools", {})) != expected
|
|
):
|
|
raise ValueError("installed Windows tools do not match the selected target")
|
|
for name in expected:
|
|
relative = Path(installed["tools"][name])
|
|
source = (manifest.parent / relative).absolute()
|
|
if (
|
|
relative.is_absolute()
|
|
or ".." in relative.parts
|
|
or source not in declared
|
|
or (name == "pkg_config" and tools.get(name) != source)
|
|
or not source.resolve(strict=True).is_relative_to(
|
|
manifest.parent.resolve(strict=True)
|
|
)
|
|
):
|
|
raise ValueError(f"installed Windows tool selection differs: {name}")
|
|
tools[name] = source
|
|
inputs["tools"] = {name: str(path) for name, path in tools.items()}
|
|
for name in ("INCLUDE", "LIB"):
|
|
inputs[name] = [str((root / path).absolute()) for path in inputs[name]]
|
|
return inputs
|
|
|
|
|
|
def main():
|
|
operation, config_path = sys.argv[1:]
|
|
config = json.loads(Path(config_path).read_text(encoding="utf-8"))
|
|
root = Path.cwd()
|
|
with tempfile.TemporaryDirectory(prefix="voice-windows-") as temporary:
|
|
temporary = Path(temporary)
|
|
document = temporary / "windows-inputs.json"
|
|
inputs = selected_inputs(config, root)
|
|
document.write_text(json.dumps(inputs), encoding="utf-8")
|
|
environment, _ = build_environment(
|
|
document, inputs["target"], {"python": Path(sys.executable)}
|
|
)
|
|
# Keep executor scratch directories, never its developer tool search path.
|
|
environment.update(
|
|
{name: os.environ[name] for name in ("TMP", "TEMP") if name in os.environ}
|
|
)
|
|
home = temporary / "home"
|
|
home.mkdir()
|
|
environment.update({"HOME": str(home), "USERPROFILE": str(home)})
|
|
os.environ.clear()
|
|
os.environ.update(environment)
|
|
if operation == "prepare":
|
|
from prepare_built_runtime import prepare_archive
|
|
|
|
output = root / config["output"]
|
|
sdk = root / config["sdk"]
|
|
for path in (output, sdk):
|
|
if path.exists():
|
|
path.rmdir()
|
|
try:
|
|
prepare_archive(
|
|
root / config["prefix"],
|
|
root / config["receipt"],
|
|
root / config["status"],
|
|
inputs["target"],
|
|
output,
|
|
sdk_output=sdk,
|
|
)
|
|
except ValueError as exc:
|
|
if str(exc) != "native build receipt is incomplete or mismatched":
|
|
raise
|
|
receipt = json.loads((root / config["receipt"]).read_text())
|
|
commits = [
|
|
line
|
|
for line in (root / config["status"]).read_text().splitlines()
|
|
if line.startswith("STABLE_GIT_COMMIT ")
|
|
]
|
|
steps = receipt.get("steps", [])
|
|
checks = {
|
|
"commit_count": len(commits) == 1,
|
|
"commit_format": len(commits) == 1
|
|
and bool(
|
|
re.fullmatch(r"STABLE_GIT_COMMIT [0-9a-f]{40}", commits[0])
|
|
),
|
|
"target": receipt.get("target") == inputs["target"],
|
|
"manifest": receipt.get("manifest_sha256")
|
|
== hashlib.sha256(
|
|
Path(__file__).with_name("sources.json").read_bytes()
|
|
).hexdigest(),
|
|
"step_count": 1 <= len(steps) <= 128,
|
|
"step_exit": all(step.get("exit_code") == 0 for step in steps),
|
|
"last_step": bool(steps)
|
|
and steps[-1].get("name") == "gst-plugins-good-install",
|
|
}
|
|
print(
|
|
"Receipt checks failed: "
|
|
+ ", ".join(name for name, valid in checks.items() if not valid),
|
|
file=sys.stderr,
|
|
)
|
|
raise
|
|
return
|
|
if operation != "build":
|
|
raise ValueError("unknown Windows native action")
|
|
archives = temporary / "archives"
|
|
archives.mkdir()
|
|
for path in config["archives"]:
|
|
source = root / path
|
|
shutil.copyfile(source, archives / source.name)
|
|
tools = inputs["tools"]
|
|
builder = NativeBuild(
|
|
SimpleNamespace(
|
|
target=inputs["target"],
|
|
deployment_target=None,
|
|
jobs=8,
|
|
output=temporary / "build",
|
|
archives=archives,
|
|
windows_build_inputs=document,
|
|
**{
|
|
name: Path(tools[name])
|
|
for name in (
|
|
"cc",
|
|
"cxx",
|
|
"cmake",
|
|
"make",
|
|
"pkg_config",
|
|
"shell",
|
|
"bootstrap_make",
|
|
)
|
|
},
|
|
),
|
|
environment,
|
|
)
|
|
try:
|
|
builder.build()
|
|
except Exception:
|
|
if builder.record["steps"]:
|
|
log = builder.output / (builder.record["steps"][-1]["name"] + ".log")
|
|
if log.is_file():
|
|
print(log.read_text(errors="replace"), file=sys.stderr)
|
|
raise
|
|
with tarfile.open(root / config["prefix"], "w") as archive:
|
|
archive.add(builder.prefix, arcname=".")
|
|
shutil.copyfile(builder.output / "built.json", root / config["receipt"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|