1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
extern crate bindgen;
// extern crate openmp_sys; // might be useful for statically comiling with openmp
use std::{
env,
fs::{read_dir, remove_dir_all},
path::PathBuf,
process::Command,
};
/// To avoid any mistypes in paths, I chose to use this struct to set all paths once and use them for here on.
struct BuildPaths(PathBuf);
impl BuildPaths {
const WFA2FOLDER: &str = "WFA2-lib";
fn out_dir(&self) -> &PathBuf { &self.0 }
// The path of the WFA2-lib right in the base folder of this project (source)
fn wfa_src(&self) -> PathBuf { Self::WFA2FOLDER.into() }
// Copy in OUT_DIR, this is where WFA is built!
fn wfa_out(&self) -> PathBuf { self.out_dir().join(Self::WFA2FOLDER) }
// Library path for WFA lib in build directory (wfa_out)
// This is needed for the linker, otherwise wfalib will not be found.
fn wfa_out_lib(&self) -> PathBuf { self.wfa_out().join("lib") }
}
impl Default for BuildPaths {
fn default() -> Self {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
Self(out_dir)
}
}
fn build_wfa() -> Option<()> {
let build_paths = BuildPaths::default();
let mut wfa_dir = read_dir(build_paths.wfa_src()).ok()?;
if !wfa_dir.any(|f| f.unwrap().file_name() == "Makefile") {
return None;
}
let _ = remove_dir_all(build_paths.wfa_out());
// copy the WFA dir to OUT_PATH and build it there... clunky, but
// don't want to pull in the entire 100MB WFA repo, since git2
// doesn't seem to support shallow clones, and build scripts
// should only modify things inside OUT_PATH. since the WFA folder
// is just a couple MB, this is fine for now.
let _cp_wfa = Command::new("cp")
.arg("-r")
.arg(build_paths.wfa_src())
.arg(build_paths.out_dir())
.output()
.expect("Copy failed");
// hotfix Makefile
let _makefile_fix = Command::new("sed")
.arg("-i")
.arg("s/CC_FLAGS=-Wall -g/CC_FLAGS=-Wall -g -fPIC/g")
.output()
.expect("Failed hotfixing makefile");
let output = Command::new("make")
.arg("clean")
.arg("all")
.current_dir(build_paths.wfa_out())
.output();
match output {
Ok(output) => {
if output.status.success() {
Some(())
} else {
panic!("1) make error: {}", String::from_utf8_lossy(&output.stderr));
}
},
Err(err) => {
panic!("2) make error: {}", err);
},
}
}
fn wfa() {
let build_paths = BuildPaths::default();
// 1. Link instructions for Cargo.
// The directory of the WFA libraries, added to the search path.
// println!("cargo:rustc-link-search=../wfa2/lib");
// println!("cargo:rustc-link-search=WFA2-lib/lib");
// Link the `wfa-lib` library.
// Mind that the name of wfalib is set in the makefile, not here.
// Relevant part in makefile:
// LIB_WFA=$(FOLDER_LIB)/libwfa.a
// LIB_WFA_CPP=$(FOLDER_LIB)/libwfacpp.a
// Despite the folder being named WFA2-lib, the library has to be linked with wfa
println!("cargo:rustc-link-lib=wfa");
// Also link `omp`.
println!("cargo:rustc-link-lib=gomp"); // omp does not work for some reason, gomp does.
// Invalidate the built crate whenever the linked library changes.
println!("cargo:rerun-if-changed={}/libwfa.a", build_paths.wfa_out_lib().display());
// Rustc lib search for library in "OUT_DIR"
println!("cargo:rustc-link-search={}", build_paths.wfa_out_lib().display());
// 2. Generate bindings.
let bindings = bindgen::Builder::default()
// Generate bindings for this header file.
// .header("../wfa2/wavefront/wavefront_align.h")
.header("WFA2-lib/wavefront/wavefront_align.h")
// Add this directory to the include path to find included header files.
// .clang_arg("-I../wfa2")
.clang_arg(format!("-I{}", build_paths.wfa_src().display()))
// Generate bindings for all functions starting with `wavefront_`.
.allowlist_function("wavefront_.*")
// Generate bindings for all variables starting with `wavefront_`.
.allowlist_var("wavefront_.*")
// Invalidate the built crate whenever any of the included header files
// changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings_wfa.rs file.
bindings
.write_to_file(build_paths.out_dir().join("bindings_wfa.rs"))
.expect("Couldn't write bindings!");
}
fn main() {
build_wfa();
wfa();
}