use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=go.mod");
println!("cargo:rerun-if-changed=go.sum");
println!("cargo:rerun-if-changed=main.go");
println!("cargo:rerun-if-changed=vendor.zip");
let mut bin_path = std::path::PathBuf::from(
std::env::var("OUT_DIR").expect("failed to read env OUT_DIR"),
);
bin_path.push("tx5-go-pion-turn");
go_check_version();
go_unzip_vendor();
go_build(&bin_path);
}
fn go_check_version() {
let go_version = Command::new("go")
.arg("version")
.output()
.expect("error checking go version");
assert_eq!(b"go version go", &go_version.stdout[0..13]);
let ver: f64 = String::from_utf8_lossy(&go_version.stdout[13..17])
.parse()
.expect("error parsing go version");
assert!(
ver >= 1.18,
"go executable version must be >= 1.18, got: {ver}",
);
}
fn go_unzip_vendor() {
let out_dir = std::env::var("OUT_DIR")
.map(std::path::PathBuf::from)
.expect("error reading out dir");
let mut vendor_path = std::env::var("CARGO_MANIFEST_DIR")
.map(std::path::PathBuf::from)
.expect("error reading manifest dir");
vendor_path.push("vendor.zip");
zip::read::ZipArchive::new(
std::fs::File::open(vendor_path)
.expect("failed to open vendor zip file"),
)
.expect("failed to open vendor zip file")
.extract(out_dir)
.expect("failed to extract vendor zip file");
}
fn go_build(path: &std::path::Path) {
let out_dir = std::env::var("OUT_DIR")
.map(std::path::PathBuf::from)
.expect("error reading out dir");
let mut cache = out_dir.clone();
cache.push("go-build");
let manifest_path = std::env::var("CARGO_MANIFEST_DIR")
.map(std::path::PathBuf::from)
.expect("error reading manifest dir");
let cp = |f: &'static str| {
let mut a = manifest_path.clone();
a.push(f);
let mut b = out_dir.clone();
b.push(f);
std::fs::copy(a, b).expect("failed to copy go file");
};
cp("main.go");
cp("go.sum");
cp("go.mod");
let mut cmd = Command::new("go");
match std::env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() {
"arm" => {
cmd.env("GOARCH", "arm");
}
"aarch64" => {
cmd.env("GOARCH", "arm64");
}
"x86_64" => {
cmd.env("GOARCH", "amd64");
}
"x86" => {
cmd.env("GOARCH", "386");
}
_ => (),
}
let tgt_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
match tgt_os.as_str() {
"windows" => {
cmd.env("GOOS", "windows");
}
"macos" => {
cmd.env("GOOS", "darwin");
}
"ios" => {
cmd.env("GOOS", "ios");
}
"linux" => {
cmd.env("GOOS", "linux");
}
"android" => {
cmd.env("GOOS", "android");
}
"dragonfly" => {
cmd.env("GOOS", "dragonfly");
}
"freebsd" => {
cmd.env("GOOS", "freebsd");
}
"openbsd" => {
cmd.env("GOOS", "openbsd");
}
"netbsd" => {
cmd.env("GOOS", "netbsd");
}
_ => (),
}
if tgt_os == "android" {
let linker = std::env::var("RUSTC_LINKER").unwrap();
cmd.env("CC_FOR_TARGET", &linker);
cmd.env("CC", &linker);
cmd.env("CGO_ENABLED", "1");
}
#[allow(clippy::suspicious_command_arg_space)]
{
cmd.current_dir(out_dir.clone())
.env("GOCACHE", cache)
.arg("build")
.arg("-ldflags") .arg("-s -w") .arg("-buildvcs=false") .arg("-o")
.arg(path)
.arg("-mod=vendor");
}
assert!(
cmd.spawn()
.expect("error spawing go build")
.wait()
.expect("error running go build")
.success(),
"error running go build",
);
use sha2::Digest;
let data = std::fs::read(path).expect("failed to read generated exe");
let mut hasher = sha2::Sha256::new();
hasher.update(data);
let hash =
base64::encode_config(hasher.finalize(), base64::URL_SAFE_NO_PAD);
let mut exe_hash = out_dir;
exe_hash.push("exe_hash.rs");
std::fs::write(
exe_hash,
format!(
r#"
const EXE_HASH: &str = "{hash}";
"#,
),
)
.expect("failed to write exe hash");
}