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
|
use cmake::Config;
use std::io;
use std::path::PathBuf;
use std::process::Command;
const COMPONENTS: &[&'static str] = &[
"LLVMCore",
"LLVMBitWriter",
#[cfg(debug_assertions)]
"LLVMAnalysis", // for module verify
#[cfg(debug_assertions)]
"LLVMBitReader",
];
fn main() {
let mut cmake = Config::new(r"../ext/llvm-project/llvm");
try_use_ninja(&mut cmake);
cmake
// For some reason Rust always links to release MSVCRT
.define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreadedDLL")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBXML2", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_ENABLE_LIBPFM", "OFF")
.define("LLVM_ENABLE_ZLIB", "OFF")
.define("LLVM_ENABLE_ZSTD", "OFF")
.define("LLVM_INCLUDE_BENCHMARKS", "OFF")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_BUILD_TOOLS", "OFF")
.define("LLVM_TARGETS_TO_BUILD", "")
.define("LLVM_ENABLE_PROJECTS", "");
cmake.build_target("llvm-config");
let llvm_dir = cmake.build();
for c in COMPONENTS {
cmake.build_target(c);
cmake.build();
}
let cmake_profile = cmake.get_profile();
let (cxxflags, ldflags, libdir, lib_names, system_libs) =
llvm_config(&llvm_dir, &["build", "bin", "llvm-config"])
.or_else(|_| llvm_config(&llvm_dir, &["build", cmake_profile, "bin", "llvm-config"]))
.unwrap();
println!("cargo:rustc-link-arg={ldflags}");
println!("cargo:rustc-link-search=native={libdir}");
for lib in system_libs.split_ascii_whitespace() {
println!("cargo:rustc-link-arg={lib}");
}
link_llvm_components(lib_names);
compile_cxx_lib(cxxflags);
}
fn try_use_ninja(cmake: &mut Config) {
let mut cmd = Command::new("ninja");
cmd.arg("--version");
if let Ok(status) = cmd.status() {
if status.success() {
cmake.generator("Ninja");
}
}
}
fn llvm_config(
llvm_build_dir: &PathBuf,
path_to_llvm_config: &[&str],
) -> io::Result<(String, String, String, String, String)> {
let mut llvm_build_path = llvm_build_dir.clone();
llvm_build_path.extend(path_to_llvm_config);
let mut cmd = Command::new(llvm_build_path);
cmd.args([
"--link-static",
"--cxxflags",
"--ldflags",
"--libdir",
"--libnames",
"--system-libs",
]);
for c in COMPONENTS {
cmd.arg(c[4..].to_lowercase());
}
let output = cmd.output()?;
if !output.status.success() {
return Err(io::Error::from(io::ErrorKind::Other));
}
let output = unsafe { String::from_utf8_unchecked(output.stdout) };
let mut lines = output.lines();
let cxxflags = lines.next().unwrap();
let ldflags = lines.next().unwrap();
let libdir = lines.next().unwrap();
let lib_names = lines.next().unwrap();
let system_libs = lines.next().unwrap();
Ok((
cxxflags.to_string(),
ldflags.to_string(),
libdir.to_string(),
lib_names.to_string(),
system_libs.to_string(),
))
}
fn compile_cxx_lib(cxxflags: String) {
let mut cc = cc::Build::new();
for flag in cxxflags.split_whitespace() {
cc.flag(flag);
}
cc.cpp(true).file("src/lib.cpp").compile("llvm_zluda_cpp");
println!("cargo:rerun-if-changed=src/lib.cpp");
println!("cargo:rerun-if-changed=src/lib.rs");
}
fn link_llvm_components(components: String) {
for component in components.split_whitespace() {
let component = if let Some(component) = component
.strip_prefix("lib")
.and_then(|component| component.strip_suffix(".a"))
{
// Unix (Linux/Mac)
// libLLVMfoo.a
component
} else if let Some(component) = component.strip_suffix(".lib") {
// Windows
// LLVMfoo.lib
component
} else {
panic!("'{}' does not look like a static library name", component)
};
println!("cargo:rustc-link-lib={component}");
}
}
|