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
use glob::glob;
use std::{env, path::PathBuf};
pub fn read_env() -> Vec<PathBuf> {
if let Ok(path) = env::var("CUDA_LIBRARY_PATH") {
// The location of the libcuda, libcudart, and libcublas can be hardcoded with the
// CUDA_LIBRARY_PATH environment variable.
let split_char = if cfg!(target_os = "windows") {
";"
} else {
":"
};
path.split(split_char).map(|s| PathBuf::from(s)).collect()
} else {
vec![]
}
}
pub fn find_cuda() -> Vec<PathBuf> {
let mut candidates = read_env();
candidates.push(PathBuf::from("/opt/cuda"));
candidates.push(PathBuf::from("/usr/local/cuda"));
for e in glob("/usr/local/cuda-*").unwrap() {
if let Ok(path) = e {
candidates.push(path)
}
}
let mut valid_paths = vec![];
for base in &candidates {
let lib = PathBuf::from(base).join("lib64");
if lib.is_dir() {
valid_paths.push(lib.clone());
valid_paths.push(lib.join("stubs"));
}
let base = base.join("targets/x86_64-linux");
let header = base.join("include/cuda.h");
if header.is_file() {
valid_paths.push(base.join("lib"));
valid_paths.push(base.join("lib/stubs"));
continue;
}
}
eprintln!("Found CUDA paths: {:?}", valid_paths);
valid_paths
}
pub fn find_cuda_windows() -> PathBuf {
let paths = read_env();
if !paths.is_empty() {
return paths[0].clone();
}
if let Ok(path) = env::var("CUDA_PATH") {
// If CUDA_LIBRARY_PATH is not found, then CUDA_PATH will be used when building for
// Windows to locate the Cuda installation. Cuda installs the full Cuda SDK for 64-bit,
// but only a limited set of libraries for 32-bit. Namely, it does not include cublas in
// 32-bit, which cuda-sys requires.
// 'path' points to the base of the CUDA Installation. The lib directory is a
// sub-directory.
let path = PathBuf::from(path);
// To do this the right way, we check to see which target we're building for.
let target = env::var("TARGET")
.expect("cargo did not set the TARGET environment variable as required.");
// Targets use '-' separators. e.g. x86_64-pc-windows-msvc
let target_components: Vec<_> = target.as_str().split("-").collect();
// We check that we're building for Windows. This code assumes that the layout in
// CUDA_PATH matches Windows.
if target_components[2] != "windows" {
panic!(
"The CUDA_PATH variable is only used by cuda-sys on Windows. Your target is {}.",
target
);
}
// Sanity check that the second component of 'target' is "pc"
debug_assert_eq!(
"pc", target_components[1],
"Expected a Windows target to have the second component be 'pc'. Target: {}",
target
);
// x86_64 should use the libs in the "lib/x64" directory. If we ever support i686 (which
// does not ship with cublas support), its libraries are in "lib/Win32".
let lib_path = match target_components[0] {
"x86_64" => "x64",
"i686" => {
// lib path would be "Win32" if we support i686. "cublas" is not present in the
// 32-bit install.
panic!("Rust cuda-sys does not currently support 32-bit Windows.");
}
_ => {
panic!("Rust cuda-sys only supports the x86_64 Windows architecture.");
}
};
// i.e. $CUDA_PATH/lib/x64
return path.join("lib").join(lib_path);
}
// No idea where to look for CUDA
panic!("CUDA cannot find");
}