mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-08 09:37:47 +03:00
152 lines
5.3 KiB
Rust
152 lines
5.3 KiB
Rust
use std::env;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
println!("cargo:rerun-if-changed=ghostty-revision");
|
|
println!("cargo:rerun-if-changed=src/ghostty/ffi.rs");
|
|
println!("cargo:rerun-if-env-changed=GHOSTTY_SOURCE_DIR");
|
|
println!("cargo:rerun-if-env-changed=OPENCODE_ZIG_CPU");
|
|
|
|
let revision = include_str!("ghostty-revision").trim();
|
|
assert_eq!(
|
|
include_str!("src/ghostty/ffi.rs")
|
|
.lines()
|
|
.find_map(|line| line.strip_prefix("// Ghostty revision: ")),
|
|
Some(revision),
|
|
"regenerate the bindings with script/ghostty-bindings"
|
|
);
|
|
let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));
|
|
let source = match env::var_os("GHOSTTY_SOURCE_DIR") {
|
|
Some(path) => {
|
|
let path = PathBuf::from(path);
|
|
for relative in ["src", "pkg", "include", "build.zig", "build.zig.zon"] {
|
|
println!("cargo:rerun-if-changed={}", path.join(relative).display());
|
|
}
|
|
path
|
|
}
|
|
None => {
|
|
let path = out.join(format!("ghostty-{revision}"));
|
|
if !path.join(".checkout-complete").exists() {
|
|
if !path.join(".git").exists() {
|
|
run(Command::new("git").args(["init"]).arg(&path));
|
|
}
|
|
run(Command::new("git").arg("-C").arg(&path).args([
|
|
"fetch",
|
|
"--depth=1",
|
|
"https://github.com/ghostty-org/ghostty.git",
|
|
revision,
|
|
]));
|
|
run(Command::new("git").arg("-C").arg(&path).args([
|
|
"-c",
|
|
"core.longpaths=true",
|
|
"checkout",
|
|
"--detach",
|
|
revision,
|
|
]));
|
|
std::fs::write(path.join(".checkout-complete"), revision)
|
|
.expect("record Ghostty checkout");
|
|
}
|
|
path
|
|
}
|
|
};
|
|
|
|
// The checked-in declarations must match the native headers exactly.
|
|
// Local overrides are useful for builds, but not for silently changing ABI.
|
|
let head = Command::new("git")
|
|
.arg("-C")
|
|
.arg(&source)
|
|
.args(["rev-parse", "HEAD"])
|
|
.output()
|
|
.expect("read Ghostty revision");
|
|
assert!(
|
|
head.status.success(),
|
|
"GHOSTTY_SOURCE_DIR must be a Git checkout"
|
|
);
|
|
assert_eq!(
|
|
String::from_utf8(head.stdout)
|
|
.expect("Ghostty revision UTF-8")
|
|
.trim(),
|
|
revision,
|
|
"Ghostty headers and bindings are pinned together; regenerate before changing the revision"
|
|
);
|
|
run(Command::new("git").arg("-C").arg(&source).args([
|
|
"-c",
|
|
"core.longpaths=true",
|
|
"diff",
|
|
"--quiet",
|
|
"HEAD",
|
|
"--",
|
|
"include/ghostty",
|
|
]));
|
|
|
|
let target = env::var("TARGET").expect("TARGET");
|
|
let install = out.join("ghostty-install");
|
|
let mut build = Command::new("zig");
|
|
build.current_dir(&source).args([
|
|
"build",
|
|
"-Demit-lib-vt=true",
|
|
"-Demit-xcframework=false",
|
|
"-Dapp-runtime=none",
|
|
]);
|
|
build.arg(if env::var("DEBUG").as_deref() == Ok("true") {
|
|
"-Doptimize=Debug"
|
|
} else if matches!(env::var("OPT_LEVEL").as_deref(), Ok("s" | "z")) {
|
|
"-Doptimize=ReleaseSmall"
|
|
} else {
|
|
"-Doptimize=ReleaseFast"
|
|
});
|
|
// Release builds pin a portable CPU. Unix releases use script/release-bin/zig;
|
|
// Windows cannot run that shell wrapper, so it sets this instead.
|
|
if let Ok(cpu) = env::var("OPENCODE_ZIG_CPU") {
|
|
build.arg(format!("-Dcpu={cpu}"));
|
|
}
|
|
build.arg("--prefix").arg(&install);
|
|
build.arg("--cache-dir").arg(out.join("zig-cache"));
|
|
if env::var("HOST").as_deref() != Ok(target.as_str()) {
|
|
let zig_target = match target.as_str() {
|
|
"x86_64-unknown-linux-gnu" => "x86_64-linux-gnu",
|
|
"aarch64-unknown-linux-gnu" => "aarch64-linux-gnu",
|
|
"x86_64-unknown-linux-musl" => "x86_64-linux-musl",
|
|
"aarch64-unknown-linux-musl" => "aarch64-linux-musl",
|
|
"x86_64-apple-darwin" => "x86_64-macos",
|
|
"aarch64-apple-darwin" => "aarch64-macos",
|
|
"x86_64-pc-windows-msvc" => "x86_64-windows-msvc",
|
|
"aarch64-pc-windows-msvc" => "aarch64-windows-msvc",
|
|
_ => panic!("unsupported Ghostty target: {target}"),
|
|
};
|
|
build.arg(format!("-Dtarget={zig_target}"));
|
|
}
|
|
run(&mut build);
|
|
|
|
let library = install.join("lib");
|
|
let windows = target.contains("windows");
|
|
assert!(
|
|
library
|
|
.join(if windows {
|
|
"ghostty-vt-static.lib"
|
|
} else {
|
|
"libghostty-vt.a"
|
|
})
|
|
.is_file()
|
|
);
|
|
println!("cargo:rustc-link-search=native={}", library.display());
|
|
// ghostty-vt.lib is the Windows DLL import library, not the static archive.
|
|
println!(
|
|
"cargo:rustc-link-lib={}",
|
|
if windows {
|
|
"static:+verbatim=ghostty-vt-static.lib"
|
|
} else {
|
|
"static=ghostty-vt"
|
|
}
|
|
);
|
|
}
|
|
|
|
fn run(command: &mut Command) {
|
|
let status = command
|
|
.status()
|
|
.unwrap_or_else(|error| panic!("{command:?}: {error}"));
|
|
assert!(status.success(), "{command:?} failed: {status}");
|
|
}
|