mirror of
https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git
synced 2026-06-07 19:59:33 +00:00
The prebuilt iden3 rapidsnark archives are compiled on a glibc >= 2.38 host (Ubuntu 24.04 / GCC 13), whose headers redirect strtoll/strtoull to the C23 interceptor symbols __isoc23_strtoll / __isoc23_strtoull. When the static archives (static-rapidsnark feature) are linked on a host with an older glibc (e.g. glibc 2.35), those symbols are undefined and linking fails: rust-lld: error: undefined symbol: __isoc23_strtoull Compile thin forwarders to the classic strtoll/strtoull symbols and link them via whole-archive so the static path resolves regardless of the host glibc version. Gated to the static feature on glibc-Linux; the shared library and all other targets are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
111 lines
4.4 KiB
Rust
111 lines
4.4 KiB
Rust
use std::env;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use std::process::Command;
|
|
|
|
const RAPIDSNARK_DOWNLOAD_SCRIPT: &str = include_str!("./download_rapidsnark.sh");
|
|
|
|
fn main() {
|
|
let target = env::var("TARGET").unwrap();
|
|
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
|
|
let arch = target.split('-').next().unwrap();
|
|
|
|
// See: https://github.com/zkmopro/chkstk_stub
|
|
chkstk_stub::build();
|
|
|
|
// Try to list contents of the target directory
|
|
let rapidsnark_path = Path::new(&out_dir).join(Path::new("rapidsnark"));
|
|
// If the rapidsnark repo is not downloaded, download it
|
|
if !rapidsnark_path.exists() {
|
|
let rapidsnark_script_path = Path::new(&out_dir).join(Path::new("download_rapidsnark.sh"));
|
|
fs::write(&rapidsnark_script_path, RAPIDSNARK_DOWNLOAD_SCRIPT)
|
|
.expect("Failed to write build script");
|
|
let child_process = Command::new("sh")
|
|
.arg(rapidsnark_script_path.to_str().unwrap())
|
|
.spawn();
|
|
if let Err(e) = child_process {
|
|
panic!("Failed to spawn rapidsnark download: {e}");
|
|
}
|
|
let status = child_process.unwrap().wait();
|
|
if let Err(e) = status {
|
|
panic!("Failed to wait for rapidsnark download: {e}");
|
|
} else if !status.unwrap().success() {
|
|
panic!("Failed to wait for rapidsnark download");
|
|
}
|
|
}
|
|
let absolute_lib_path = if rapidsnark_path.join(&target).exists() {
|
|
rapidsnark_path.join(&target)
|
|
} else {
|
|
rapidsnark_path.join(arch)
|
|
};
|
|
let compiler = cc::Build::new().get_compiler();
|
|
let cpp_stdlib = if compiler.is_like_clang() {
|
|
"c++"
|
|
} else {
|
|
"stdc++"
|
|
};
|
|
|
|
println!(
|
|
"cargo:rustc-link-search=native={}",
|
|
absolute_lib_path.display()
|
|
);
|
|
|
|
// The shared rapidsnark artifact is already linked with its fr/fq/gmp implementation.
|
|
// Linking those helper libraries again is redundant and can accidentally pull static archives
|
|
// into downstream binaries, exporting generic Fr_* / Fq_* symbols that collide with other
|
|
// native ZK libraries.
|
|
//
|
|
// The static rapidsnark archive is different: it leaves Fr_*, Fq_*, and GMP symbols unresolved,
|
|
// so static/mobile builds must link the helper archives.
|
|
if is_static_rapidsnark() || is_mobile_target() {
|
|
println!("cargo:rustc-link-lib=static=rapidsnark");
|
|
println!("cargo:rustc-link-lib=static=fr");
|
|
println!("cargo:rustc-link-lib=static=fq");
|
|
println!("cargo:rustc-link-lib=static=gmp");
|
|
} else {
|
|
println!("cargo:rustc-link-lib=dylib=rapidsnark");
|
|
}
|
|
|
|
println!("cargo:rustc-link-lib={cpp_stdlib}");
|
|
|
|
// Android bundles pthread into libc
|
|
let thread_lib = if is_android_target() { "c" } else { "pthread" };
|
|
println!("cargo:rustc-link-lib={thread_lib}");
|
|
|
|
// glibc >= 2.38 redirects strtoll/strtoull to the C23 interceptor symbols
|
|
// __isoc23_strtoll / __isoc23_strtoull. The prebuilt iden3 rapidsnark archives
|
|
// were compiled against such a glibc, so when they are linked statically on a
|
|
// host with an older glibc (e.g. glibc 2.35) the verifier objects reference
|
|
// __isoc23_* symbols that do not exist there and linking fails. Compile thin
|
|
// forwarders to the classic strtoll/strtoull and link them so the static path
|
|
// resolves regardless of the host glibc version. Only relevant for the static
|
|
// archive on glibc-Linux; the shared library and other targets are unaffected.
|
|
println!("cargo:rerun-if-changed=isoc23_compat.c");
|
|
if is_static_rapidsnark()
|
|
&& env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux")
|
|
&& env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("gnu")
|
|
{
|
|
cc::Build::new()
|
|
.file("isoc23_compat.c")
|
|
.cargo_metadata(false)
|
|
.compile("isoc23_compat");
|
|
println!("cargo:rustc-link-search=native={out_dir}");
|
|
// whole-archive so the forwarders are included unconditionally, regardless
|
|
// of this archive's position relative to librapidsnark.a on the link line.
|
|
println!("cargo:rustc-link-lib=static:+whole-archive=isoc23_compat");
|
|
}
|
|
}
|
|
|
|
fn is_static_rapidsnark() -> bool {
|
|
env::var_os("CARGO_FEATURE_STATIC_RAPIDSNARK").is_some()
|
|
}
|
|
|
|
fn is_mobile_target() -> bool {
|
|
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
target_os.contains("ios") || target_os.contains("android")
|
|
}
|
|
|
|
fn is_android_target() -> bool {
|
|
env::var("CARGO_CFG_TARGET_OS").unwrap().contains("android")
|
|
}
|