build: default Codex package target and output

This commit is contained in:
Michael Bolin
2026-05-19 13:34:12 -07:00
parent 68c06d1c24
commit 7265106357
3 changed files with 67 additions and 7 deletions
+6 -1
View File
@@ -22,6 +22,10 @@ The builder creates a canonical Codex package directory:
The package directory is the primary artifact. Archive formats such as
`.tar.gz`, `.tar.zst`, and `.zip` are serializations of that directory.
If `--target` is omitted, the builder uses the current host platform. If
`--package-dir` is omitted, the builder creates a new temporary directory and
prints its path after the package is built.
## Source-built artifacts
Artifacts built from this repository are always built by the package builder in
@@ -32,7 +36,8 @@ one grouped `cargo build` command per package:
- Windows targets: `codex-command-runner` and `codex-windows-sandbox-setup`
The default cargo profile is `dev-small` because local iteration should favor
fast, small builds. Release jobs should pass `--cargo-profile release`.
fast, small builds. Release jobs should pass `--cargo-profile release` and an
explicit release target such as `x86_64-unknown-linux-musl`.
`rg` is not built from this repository, so the builder fetches it from the
DotSlash manifest at `codex-cli/bin/rg`. Downloaded archives are cached under
+16 -6
View File
@@ -1,6 +1,7 @@
"""Command-line interface for building Codex package directories."""
import argparse
import tempfile
from pathlib import Path
from .archive import write_archive
@@ -11,6 +12,7 @@ from .layout import validate_package_dir
from .ripgrep import resolve_rg_bin
from .targets import TARGET_SPECS
from .targets import PackageInputs
from .targets import default_target
def parse_args() -> argparse.Namespace:
@@ -20,9 +22,9 @@ def parse_args() -> argparse.Namespace:
)
parser.add_argument(
"--target",
required=True,
default=argparse.SUPPRESS,
choices=sorted(TARGET_SPECS),
help="Rust target triple for the package.",
help="Rust target triple for the package. Defaults to the host platform.",
)
parser.add_argument(
"--version",
@@ -37,8 +39,11 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"--package-dir",
type=Path,
required=True,
help="Output directory to create as the package root.",
default=argparse.SUPPRESS,
help=(
"Output directory to create as the package root. Defaults to a new "
"temporary directory."
),
)
parser.add_argument(
"--archive-output",
@@ -79,8 +84,13 @@ def parse_args() -> argparse.Namespace:
def main() -> int:
args = parse_args()
spec = TARGET_SPECS[args.target]
package_dir = args.package_dir.resolve()
spec = TARGET_SPECS[getattr(args, "target", None) or default_target()]
package_dir_arg = getattr(args, "package_dir", None)
package_dir = (
package_dir_arg.resolve()
if package_dir_arg is not None
else Path(tempfile.mkdtemp(prefix="codex-package-")).resolve()
)
source_outputs = build_source_binaries(
spec,
+45
View File
@@ -1,5 +1,6 @@
"""Supported package targets and default binary discovery."""
import platform
import stat
from dataclasses import dataclass
from pathlib import Path
@@ -39,12 +40,24 @@ class PackageInputs:
TARGET_SPECS: dict[str, TargetSpec] = {
"x86_64-unknown-linux-gnu": TargetSpec(
target="x86_64-unknown-linux-gnu",
is_windows=False,
is_linux=True,
dotslash_platform="linux-x86_64",
),
"x86_64-unknown-linux-musl": TargetSpec(
target="x86_64-unknown-linux-musl",
is_windows=False,
is_linux=True,
dotslash_platform="linux-x86_64",
),
"aarch64-unknown-linux-gnu": TargetSpec(
target="aarch64-unknown-linux-gnu",
is_windows=False,
is_linux=True,
dotslash_platform="linux-aarch64",
),
"aarch64-unknown-linux-musl": TargetSpec(
target="aarch64-unknown-linux-musl",
is_windows=False,
@@ -78,6 +91,29 @@ TARGET_SPECS: dict[str, TargetSpec] = {
}
HOST_TARGETS: dict[tuple[str, str], str] = {
("darwin", "aarch64"): "aarch64-apple-darwin",
("darwin", "x86_64"): "x86_64-apple-darwin",
("linux", "aarch64"): "aarch64-unknown-linux-gnu",
("linux", "x86_64"): "x86_64-unknown-linux-gnu",
("windows", "aarch64"): "aarch64-pc-windows-msvc",
("windows", "x86_64"): "x86_64-pc-windows-msvc",
}
def default_target() -> str:
system = platform.system().lower()
machine = normalize_machine(platform.machine())
target = HOST_TARGETS.get((system, machine))
if target is None:
supported = ", ".join(sorted(TARGET_SPECS))
raise RuntimeError(
f"Unsupported host platform {platform.system()}/{platform.machine()}. "
f"Pass --target explicitly. Supported targets: {supported}"
)
return target
def resolve_input_path(
explicit_path: Path | None,
description: str,
@@ -96,3 +132,12 @@ def resolve_input_path(
def is_executable(path: Path) -> bool:
return bool(path.stat().st_mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))
def normalize_machine(machine: str) -> str:
machine = machine.lower()
if machine in ("amd64", "x86_64"):
return "x86_64"
if machine in ("aarch64", "arm64"):
return "aarch64"
return machine