mirror of
https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git
synced 2026-06-07 19:59:33 +00:00
fix: build rapidsnark from source with -fPIC on glibc-Linux static
The prebuilt iden3 archives are non-PIC, so they cannot be linked into a downstream cdylib (e.g. the node's C bindings) — rust-lld fails with "relocation R_X86_64_PC32 ... recompile with -fPIC". They are also built against a newer glibc (undefined __isoc23_strtoll/ull on older runners). For the static feature on glibc-Linux, build rapidsnark from source with CMAKE_POSITION_INDEPENDENT_CODE=ON against the host toolchain instead. This produces PIC archives that link into a shared library and, being built against the host glibc, removes the __isoc23 dependency — so the previous compat shim (isoc23_compat.c) is no longer needed and is removed. All other targets (macOS, iOS, Android) keep using the prebuilt download path. Verified in a glibc-2.35 container: the from-source archives link into a -shared cdylib with rust-lld and carry no __isoc23 references. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
80f5e0b661
commit
384513f9c9
107
crates/build.rs
107
crates/build.rs
@ -4,6 +4,8 @@ use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
const RAPIDSNARK_DOWNLOAD_SCRIPT: &str = include_str!("./download_rapidsnark.sh");
|
||||
const RAPIDSNARK_GIT: &str = "https://github.com/iden3/rapidsnark.git";
|
||||
const RAPIDSNARK_TAG: &str = "v0.0.8";
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
@ -13,6 +15,16 @@ fn main() {
|
||||
// See: https://github.com/zkmopro/chkstk_stub
|
||||
chkstk_stub::build();
|
||||
|
||||
// On glibc-Linux with static linking the prebuilt iden3 archives don't work:
|
||||
// they are non-PIC (cannot be linked into a downstream cdylib such as the
|
||||
// node's C bindings) and are built against a newer glibc (undefined
|
||||
// __isoc23_strtoll/ull on older hosts). Build rapidsnark from source with
|
||||
// -fPIC against the host toolchain instead, which resolves both problems.
|
||||
if build_from_source_applies() {
|
||||
build_rapidsnark_from_source(&out_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -71,29 +83,86 @@ fn main() {
|
||||
// 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()
|
||||
fn build_from_source_applies() -> bool {
|
||||
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");
|
||||
}
|
||||
|
||||
/// Build rapidsnark's static archives from source with position-independent code.
|
||||
///
|
||||
/// Requires `git`, `cmake`, `make`, `nasm`, a C++ compiler, and the GMP/libsodium
|
||||
/// development headers to be available on the build host. GMP is linked from the
|
||||
/// system as a (PIC) shared library.
|
||||
fn build_rapidsnark_from_source(out_dir: &str) {
|
||||
let src = Path::new(out_dir).join("rapidsnark-src");
|
||||
if !src.join("CMakeLists.txt").exists() {
|
||||
// Clean any partial checkout so the clone can succeed.
|
||||
let _ = fs::remove_dir_all(&src);
|
||||
run(Command::new("git").args([
|
||||
"clone",
|
||||
"--depth",
|
||||
"1",
|
||||
"--branch",
|
||||
RAPIDSNARK_TAG,
|
||||
RAPIDSNARK_GIT,
|
||||
src.to_str().unwrap(),
|
||||
]));
|
||||
}
|
||||
// Only the field-element codegen (ffiasm) and JSON header are needed to build
|
||||
// the prover/verifier static libraries.
|
||||
run(Command::new("git").current_dir(&src).args([
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--depth",
|
||||
"1",
|
||||
"depends/ffiasm",
|
||||
"depends/json",
|
||||
]));
|
||||
|
||||
let build = src.join("build_pic");
|
||||
fs::create_dir_all(&build).expect("Failed to create rapidsnark build dir");
|
||||
run(Command::new("cmake").current_dir(&build).args([
|
||||
"..",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
|
||||
"-DUSE_ASM=ON",
|
||||
"-DUSE_OPENMP=OFF",
|
||||
"-DUSE_LOGGER=ON",
|
||||
]));
|
||||
|
||||
let jobs = std::thread::available_parallelism()
|
||||
.map(|n| n.get())
|
||||
.unwrap_or(4)
|
||||
.to_string();
|
||||
run(Command::new("make").current_dir(&build).args([
|
||||
"-j",
|
||||
&jobs,
|
||||
"rapidsnarkStatic",
|
||||
"fr",
|
||||
"fq",
|
||||
]));
|
||||
|
||||
let lib_dir = build.join("src");
|
||||
println!("cargo:rustc-link-search=native={}", lib_dir.display());
|
||||
println!("cargo:rustc-link-lib=static=rapidsnark");
|
||||
println!("cargo:rustc-link-lib=static=fr");
|
||||
println!("cargo:rustc-link-lib=static=fq");
|
||||
// GMP is provided by the system as a PIC shared library.
|
||||
println!("cargo:rustc-link-lib=dylib=gmp");
|
||||
println!("cargo:rustc-link-lib=stdc++");
|
||||
println!("cargo:rustc-link-lib=pthread");
|
||||
}
|
||||
|
||||
fn run(cmd: &mut Command) {
|
||||
eprintln!("rapidsnark build: running {cmd:?}");
|
||||
let status = cmd
|
||||
.status()
|
||||
.unwrap_or_else(|e| panic!("Failed to spawn {cmd:?}: {e}"));
|
||||
assert!(status.success(), "Command failed ({status}): {cmd:?}");
|
||||
}
|
||||
|
||||
fn is_static_rapidsnark() -> bool {
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* glibc >= 2.38 redirects strtoll/strtoull to the C23 interceptor symbols
|
||||
* __isoc23_strtoll / __isoc23_strtoull at compile time. The prebuilt iden3
|
||||
* rapidsnark archives were compiled against such a glibc, so their verifier
|
||||
* objects reference those symbols. When the static archives are linked on a
|
||||
* host with an older glibc (e.g. Ubuntu 22.04 / glibc 2.35) the symbols are
|
||||
* undefined and linking fails.
|
||||
*
|
||||
* Provide thin forwarders to the classic strtoll/strtoull symbols. We bind to
|
||||
* the legacy symbol names explicitly via asm labels and deliberately avoid
|
||||
* including <stdlib.h>, so this translation unit is itself immune to the C23
|
||||
* header redirect (otherwise the forwarder would recurse into itself when this
|
||||
* file is compiled on a new-glibc build host).
|
||||
*/
|
||||
extern long long __legacy_strtoll(const char *, char **, int) __asm__("strtoll");
|
||||
extern unsigned long long __legacy_strtoull(const char *, char **, int) __asm__("strtoull");
|
||||
|
||||
long long __isoc23_strtoll(const char *nptr, char **endptr, int base) {
|
||||
return __legacy_strtoll(nptr, endptr, base);
|
||||
}
|
||||
|
||||
unsigned long long __isoc23_strtoull(const char *nptr, char **endptr, int base) {
|
||||
return __legacy_strtoull(nptr, endptr, base);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user