amdgpu_device_libs_build/
lib.rs1#![allow(clippy::needless_doctest_main)]
4use std::env;
23use std::path::PathBuf;
24use std::process::Command;
25
26#[derive(Default)]
28pub struct Build {
29 pub link_args: Vec<String>,
30 pub used_env_vars: Vec<String>,
31 pub used_files: Vec<String>,
32}
33
34pub fn get_link_args(mut is_wave64_enabled: bool, target_cpu: &str) -> Build {
36 let mut build = Build::default();
37
38 let cur_dir = env!("CARGO_MANIFEST_DIR");
39
40 let mut device_libs = None;
41 if let Ok(v) = env::var("HIP_DEVICE_LIB_PATH") {
43 build.used_env_vars.push("HIP_DEVICE_LIB_PATH".into());
44 device_libs = Some(v);
45 } else {
46 let mut hipconfig = Command::new("hipconfig");
48 hipconfig.arg("-l");
49
50 let hipconfig_r = hipconfig.output();
51 if let Ok(r) = &hipconfig_r {
52 if !r.status.success() {
53 panic!(
54 "`hipconfig -l` exited unsuccessfully, either fix this or set $HIP_DEVICE_LIB_PATH"
55 );
56 }
57 let s =
58 String::from_utf8(r.stdout.clone()).expect("`hipconfig -l` returned invalid utf-8");
59 let p = PathBuf::from(s)
60 .canonicalize()
61 .expect("Failed to canonicalize device libs path")
62 .parent()
63 .expect("Device libs path must have parent")
64 .join("lib")
65 .join("clang");
66 let mut folders = Vec::new();
68 if let Ok(dir) = std::fs::read_dir(&p) {
70 for d in dir {
71 let d = d.expect("Failed to list lib/clang directory content");
72 if d.file_type().expect("Failed to get file type").is_dir() {
73 folders.push(d.path());
74 }
75 }
76 }
77 folders.sort();
78 if let Some(last) = folders.last() {
79 device_libs = Some(format!("{}/amdgcn/bitcode", last.display()));
80 }
81 }
82
83 if device_libs.is_none()
85 && let Ok(v) = env::var("ROCM_DEVICE_LIB_PATH").or_else(|_| env::var("ROCM_PATH"))
86 {
87 build.used_env_vars.push("ROCM_PATH".into());
88 build.used_env_vars.push("ROCM_DEVICE_LIB_PATH".into());
89 device_libs = Some(format!("{}/amdgcn/bitcode", v));
90 }
91 }
92 let device_libs = device_libs.expect("Device libs not found, must set $HIP_DEVICE_LIB_PATH or provide a path through `hipconfig -l`");
93
94 let gfxip = target_cpu
95 .strip_prefix("gfx")
96 .unwrap_or_else(|| panic!("target-cpu '{target_cpu}' did not start with gfx"));
97
98 build.link_args.push(format!("{device_libs}/ockl.bc"));
99 build
100 .link_args
101 .push(format!("{device_libs}/oclc_isa_version_{gfxip}.bc"));
102 build
103 .link_args
104 .push(format!("{device_libs}/oclc_abi_version_600.bc"));
105
106 is_wave64_enabled |= gfxip.starts_with('9') && gfxip.len() == 3;
108 is_wave64_enabled |= gfxip.starts_with("9-") && gfxip.ends_with("-generic");
109 let wavesize = if is_wave64_enabled { 64 } else { 32 };
110 build.link_args.push(format!(
111 "{device_libs}/oclc_wavefrontsize64_{}.bc",
112 if is_wave64_enabled { "on" } else { "off" }
113 ));
114
115 build
116 .used_files
117 .push(format!("{cur_dir}/util{wavesize}.bc"));
118 build.link_args.push(format!("{cur_dir}/util{wavesize}.bc"));
119
120 build.link_args.push("--undefined-version".into());
122 build.link_args.push("--no-gc-sections".into());
123 build
124}
125
126#[cfg(feature = "rustflags")]
136pub fn build() {
137 use std::collections::HashSet;
138
139 use rustflags::Flag;
140
141 let mut target_features = env::var("CARGO_CFG_TARGET_FEATURE")
143 .unwrap_or_default()
144 .split(',')
145 .filter(|s| !s.is_empty())
146 .map(|s| s.to_string())
147 .collect::<HashSet<_>>();
148
149 let mut target_cpu = None;
150 for flag in rustflags::from_env() {
151 if let Flag::Codegen { opt, value } = flag {
152 if opt == "target-cpu" {
153 target_cpu = value;
154 } else if opt == "target-feature"
155 && let Some(feat) = value
156 {
157 if let Some(feat) = feat.strip_prefix('-') {
158 target_features.remove(feat);
159 } else {
160 let feat = feat.trim_start_matches('+');
161 target_features.insert(feat.into());
162 }
163 }
164 }
165 }
166 let target_cpu = target_cpu.expect("Did not find target-cpu in RUSTFLAGS");
167 let is_wave64_enabled = target_features.contains("wavefrontsize64");
168 let mut build = get_link_args(is_wave64_enabled, &target_cpu);
169 build.used_env_vars.push("CARGO_CFG_TARGET_FEATURE".into());
170
171 for v in &build.used_env_vars {
172 println!("cargo::rerun-if-env-changed={v}");
173 }
174 for f in &build.used_files {
175 println!("cargo::rerun-if-changed={f}");
176 }
177 for a in &build.link_args {
178 println!("cargo::rustc-link-arg={a}");
179 }
180}