Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use std::path::PathBuf;

const TYPICAL_CUDA_PATH_ENV_VARS: [&'static str; 5] = [

Check failure on line 3 in build.rs

View workflow job for this annotation

GitHub Actions / clippy

constants have by default a `'static` lifetime
"CUDA_HOME",
"CUDA_PATH",
"CUDA_ROOT",
"CUDA_TOOLKIT_ROOT_DIR",
"CUDNN_LIB",
];

fn main() {
#[cfg(all(
not(feature = "dynamic-linking"),
Expand All @@ -15,10 +23,10 @@
panic!("Both `dynamic-loading` and `dynamic-linking` features are active, this is a bug");

println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=CUDA_ROOT");
println!("cargo:rerun-if-env-changed=CUDA_PATH");
println!("cargo:rerun-if-env-changed=CUDA_TOOLKIT_ROOT_DIR");
println!("cargo:rerun-if-env-changed=CUDARC_CUDA_VERSION");
TYPICAL_CUDA_PATH_ENV_VARS
.iter()
.for_each(|var| println!("cargo:rerun-if-env-changed={var}"));

let (major, minor): (usize, usize) = if let Ok(version) = std::env::var("CUDARC_CUDA_VERSION") {
let (major, minor) = match version.as_str() {
Expand Down Expand Up @@ -231,18 +239,22 @@

#[allow(unused)]
fn link_searches(major: usize, minor: usize) -> Vec<PathBuf> {
let env_vars = [
"CUDA_PATH",
"CUDA_ROOT",
"CUDA_TOOLKIT_ROOT_DIR",
"CUDNN_LIB",
];
let env_vars = env_vars
.into_iter()
let env_vars = TYPICAL_CUDA_PATH_ENV_VARS
.iter()
.map(std::env::var)
.filter_map(Result::ok);
.filter_map(Result::ok)
.collect::<Vec<_>>();
Comment on lines +242 to +246

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Collecting the environment variables into a Vec here is inefficient as it forces an allocation. The subsequent logic then requires another allocation if no environment variables are found. This can be made more performant and idiomatic by using iterators.

Consider refactoring this part of link_searches to use a peekable() iterator and a trait object (Box<dyn Iterator<...>>) to avoid allocations:

// In link_searches function
let mut env_vars_iter = TYPICAL_CUDA_PATH_ENV_VARS
    .iter()
    .map(std::env::var)
    .filter_map(Result::ok)
    .peekable();

let no_env_vars = env_vars_iter.peek().is_none();

// ... conda warning logic using `no_env_vars` ...

let roots_iter: Box<dyn Iterator<Item = PathBuf>> = if no_env_vars {
    Box::new(typical_locations.into_iter().map(PathBuf::from))
} else {
    Box::new(env_vars_iter.map(PathBuf::from))
};

for root in roots_iter {
    // ... existing loop body
}

This approach avoids intermediate collections, reducing memory allocations and making the code cleaner.


// When building in a Conda-like environment with dynamic linking, if no
// CUDA path is supplied, then it is higly likely that, by defaulting our
// linker search paths to the typical locations below, linker errors will
// occur. Print a warning with some guidance.
#[cfg(feature = "dynamic-linking")]
if env_vars.is_empty() && std::env::var("CONDA_PREFIX").is_ok() {
println!("cargo::warning=Detected CONDA_PREFIX in the environment, but no CUDA path was set through one of: {TYPICAL_CUDA_PATH_ENV_VARS:?}. Linker errors are likely to occur. Please ensure the environment contains all required dependencies (e.g. the \"cuda-driver-dev\") and retry building with CUDA_HOME=$CONDA_PREFIX.")
Comment thread
chelsea0x3b marked this conversation as resolved.
Outdated
}

let standard_locations = [
let typical_locations = [
"/usr",
"/usr/local/cuda",
"/opt/cuda",
Expand All @@ -264,13 +276,18 @@
"C:/Program Files/NVIDIA/CUDNN/v9.1",
"C:/Program Files/NVIDIA/CUDNN/v9.0",
];
let standard_locations = standard_locations.into_iter().map(Into::into);

let possible_locations = if env_vars.is_empty() {
typical_locations
.into_iter()
.map(Into::<String>::into)
.collect()
} else {
env_vars
};

let mut candidates = Vec::new();
for root in env_vars
.chain(standard_locations)
.map(Into::<PathBuf>::into)
{
for root in possible_locations.into_iter().map(Into::<PathBuf>::into) {
candidates.extend(
[
"lib".into(),
Expand Down
Loading