use std::env;
use std::fs;
use std::path::{Path, PathBuf};
#[cfg(feature = "vendored")]
fn patch_source(src: &Path, out_dir: &Path, replacements: &[(&str, &str)], label: &str) -> PathBuf {
let filename = src.file_name().expect("source path has no file name");
let dst = out_dir.join(filename);
let mut contents =
fs::read_to_string(src).unwrap_or_else(|e| panic!("failed to read {}: {e}", src.display()));
for (needle, replacement) in replacements {
assert!(
contents.contains(needle),
"{label}: patch target not found in {} — upstream may have fixed this; \
remove the corresponding patch from build.rs.",
src.display()
);
contents = contents.replacen(needle, replacement, 1);
}
fs::write(&dst, contents).unwrap_or_else(|e| panic!("failed to write {}: {e}", dst.display()));
println!("cargo:rerun-if-changed={}", src.display());
dst
}
#[allow(clippy::too_many_lines)]
fn main() {
let src_dir = PathBuf::from("vendor/primer3/src");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
#[cfg(feature = "vendored")]
let oligotm_src = patch_source(
&src_dir.join("oligotm.c"),
&out_dir,
&[(
" static double a = 0,b = 0,c = 0,d = 0,e = 0,f = 0,g = 0;",
" double a = 0,b = 0,c = 0,d = 0,e = 0,f = 0,g = 0;",
)],
"oligotm.c thread-safety",
);
#[cfg(feature = "vendored")]
{
cc::Build::new()
.files([
src_dir.join("thal.c"),
oligotm_src.clone(),
src_dir.join("dpal.c"),
src_dir.join("p3_seq_lib.c"),
src_dir.join("masker.c"),
src_dir.join("read_boulder.c"),
src_dir.join("print_boulder.c"),
src_dir.join("format_output.c"),
])
.include(&src_dir)
.define("MAX_PRIMER_LENGTH", "60")
.opt_level(2)
.warnings(false)
.flag_if_supported("-ffloat-store")
.compile("primer3_c");
cc::Build::new()
.file(src_dir.join("libprimer3.cc"))
.include(&src_dir)
.define("MAX_PRIMER_LENGTH", "60")
.cpp(true)
.std("c++11")
.opt_level(2)
.warnings(false)
.compile("primer3_cc");
let target = env::var("TARGET").unwrap();
if target.contains("apple") || target.contains("freebsd") {
println!("cargo:rustc-link-lib=c++");
} else {
println!("cargo:rustc-link-lib=stdc++");
}
}
#[cfg(feature = "system")]
{
println!("cargo:rustc-link-lib=primer3");
}
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_arg(format!("-I{}", src_dir.display()))
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.allowlist_function("thal")
.allowlist_function("set_thal_default_args")
.allowlist_function("set_thal_oligo_default_args")
.allowlist_function("thal_set_null_parameters")
.allowlist_function("thal_load_parameters")
.allowlist_function("thal_free_parameters")
.allowlist_function("get_thermodynamic_values")
.allowlist_function("destroy_thal_structures")
.allowlist_function("oligotm")
.allowlist_function("seqtm")
.allowlist_function("long_seq_tm")
.allowlist_function("oligodg")
.allowlist_function("end_oligodg")
.allowlist_function("symmetry")
.allowlist_function("divalent_to_monovalent")
.allowlist_function("p3_create_global_settings")
.allowlist_function("p3_destroy_global_settings")
.allowlist_function("create_seq_arg")
.allowlist_function("destroy_seq_args")
.allowlist_function("choose_primers")
.allowlist_function("destroy_p3retval")
.allowlist_function("p3_set_gs_.*")
.allowlist_function("p3_set_sa_.*")
.allowlist_function("p3_sa_add_to_.*")
.allowlist_function("read_and_create_seq_lib")
.allowlist_function("destroy_seq_lib")
.allowlist_function("seq_lib_num_seq")
.allowlist_function("create_empty_seq_lib")
.allowlist_function("add_seq_and_rev_comp_to_seq_lib")
.allowlist_type("thal_args")
.allowlist_type("thal_results")
.allowlist_type("thal_parameters")
.allowlist_type("thal_alignment_type")
.allowlist_type("thal_mode")
.allowlist_type("tm_ret")
.allowlist_type("tm_method_type")
.allowlist_type("salt_correction_type")
.allowlist_type("p3_global_settings")
.allowlist_type("seq_args")
.allowlist_type("p3retval")
.allowlist_type("primer_rec")
.allowlist_type("primer_pair")
.allowlist_type("oligo_array")
.allowlist_type("oligo_stats")
.allowlist_type("pair_stats")
.allowlist_type("seq_lib")
.allowlist_type("args_for_one_oligo_or_primer")
.allowlist_type("oligo_weights")
.allowlist_type("pair_weights")
.allowlist_type("task")
.allowlist_type("masker_parameters")
.allowlist_type("formula_parameters")
.allowlist_type("input_sequence")
.allowlist_type("output_sequence")
.allowlist_type("masking_direction")
.allowlist_var("THAL_MAX_ALIGN")
.allowlist_var("THAL_MAX_SEQ")
.allowlist_var("_INFINITY")
.allowlist_var("ABSOLUTE_ZERO")
.allowlist_var("MAX_LOOP")
.allowlist_var("MIN_LOOP")
.generate()
.expect("Unable to generate bindings");
bindings.write_to_file(out_dir.join("bindings.rs")).expect("Couldn't write bindings!");
}