@@ -10,11 +10,38 @@ use curl::easy::Easy;
1010use tar:: Archive ;
1111use xz:: read:: XzDecoder ;
1212
13+ struct LlvmFlavor {
14+ major : u8 ,
15+ config_env : & ' static str ,
16+ default_binary : & ' static str ,
17+ probe_cuda_home : bool ,
18+ prebuilt_url : & ' static str ,
19+ }
20+
21+ const LLVM7 : LlvmFlavor = LlvmFlavor {
22+ major : 7 ,
23+ config_env : "LLVM_CONFIG" ,
24+ default_binary : "llvm-config" ,
25+ probe_cuda_home : false ,
26+ prebuilt_url : PREBUILT_LLVM_URL_LLVM7 ,
27+ } ;
28+
29+ const LLVM19 : LlvmFlavor = LlvmFlavor {
30+ major : 19 ,
31+ config_env : "LLVM_CONFIG_19" ,
32+ default_binary : "llvm-config-19" ,
33+ probe_cuda_home : true ,
34+ prebuilt_url : PREBUILT_LLVM_URL_LLVM19 ,
35+ } ;
36+
1337static PREBUILT_LLVM_URL_LLVM7 : & str =
14- "https://github.com/rust-gpu/rustc_codegen_nvvm-llvm/releases/download/LLVM-7.1.0/" ;
38+ "https://github.com/rust-gpu/rustc_codegen_nvvm-llvm/releases/download/llvm-7.1.0/" ;
39+ static PREBUILT_LLVM_URL_LLVM19 : & str =
40+ "https://github.com/rust-gpu/rustc_codegen_nvvm-llvm/releases/download/llvm-19.1.7/" ;
1541
1642fn main ( ) {
17- rustc_llvm_build ( llvm19_enabled ( ) ) ;
43+ let flavor = if llvm19_enabled ( ) { & LLVM19 } else { & LLVM7 } ;
44+ rustc_llvm_build ( flavor) ;
1845}
1946
2047fn fail ( s : & str ) -> ! {
@@ -43,10 +70,6 @@ fn llvm19_enabled() -> bool {
4370 tracked_env_var_os ( "CARGO_FEATURE_LLVM19" ) . is_some ( )
4471}
4572
46- fn required_major_llvm_version ( llvm19_enabled : bool ) -> u8 {
47- if llvm19_enabled { 19 } else { 7 }
48- }
49-
5073fn command_version ( path : & Path ) -> Option < String > {
5174 let output = Command :: new ( path) . arg ( "--version" ) . output ( ) . ok ( ) ?;
5275 if !output. status . success ( ) {
@@ -77,90 +100,20 @@ fn sibling_llvm_tool(llvm_config: &Path, tool_prefix: &str) -> Option<PathBuf> {
77100fn target_to_llvm_prebuilt ( target : & str ) -> String {
78101 let base = match target {
79102 "x86_64-pc-windows-msvc" => "windows-x86_64" ,
80- // NOTE(RDambrosio016): currently disabled because of weird issues with segfaults and building the C++ shim
81- // "x86_64 -unknown-linux-gnu" => "linux-x86_64 ",
103+ "x86_64-unknown-linux-gnu" => "linux-x86_64" ,
104+ "aarch64 -unknown-linux-gnu" => "linux-aarch64 " ,
82105 _ => panic ! (
83- "Unsupported target with no matching prebuilt LLVM: `{target}`, install LLVM and set LLVM_CONFIG"
106+ "Unsupported target with no matching prebuilt LLVM: `{target}`, install LLVM and set LLVM_CONFIG (or LLVM_CONFIG_19 when the `llvm19` feature is enabled) "
84107 ) ,
85108 } ;
86109 format ! ( "{base}.tar.xz" )
87110}
88111
89- fn find_llvm_config ( target : & str , llvm19_enabled : bool ) -> PathBuf {
90- if llvm19_enabled {
91- return find_llvm_config_llvm19 ( ) ;
92- }
93-
94- find_llvm_config_llvm7 ( target)
95- }
96-
97- fn find_llvm_config_llvm19 ( ) -> PathBuf {
98- let required_major = required_major_llvm_version ( true ) ;
99- let mut candidates = Vec :: new ( ) ;
100-
101- if let Some ( path) = tracked_env_var_os ( "LLVM_CONFIG_19" ) {
102- candidates. push ( PathBuf :: from ( path) ) ;
103- }
104-
105- candidates. push ( PathBuf :: from ( "llvm-config-19" ) ) ;
106-
107- if let Some ( cuda_home) = tracked_env_var_os ( "CUDA_HOME" ) {
108- let cuda_home = PathBuf :: from ( cuda_home) ;
109- candidates. push ( cuda_home. join ( "nvvm" ) . join ( "bin" ) . join ( "llvm-config" ) ) ;
110- candidates. push ( cuda_home. join ( "bin" ) . join ( "llvm-config" ) ) ;
111- }
112-
113- for candidate in & candidates {
114- if llvm_version_matches ( candidate, required_major) {
115- return candidate. clone ( ) ;
116- }
117- }
118-
119- let tried = candidates
120- . iter ( )
121- . map ( |candidate| format ! ( " - {}" , candidate. display( ) ) )
122- . collect :: < Vec < _ > > ( )
123- . join ( "\n " ) ;
124-
125- fail ( & format ! (
126- "LLVM 19 support is enabled, but no LLVM 19 toolchain was found.\n \
127- Tried:\n {tried}\n \n \
128- Set LLVM_CONFIG_19=/path/to/llvm-config from an LLVM 19 installation."
129- ) ) ;
130- }
131-
132- fn find_llvm_config_llvm7 ( target : & str ) -> PathBuf {
133- let required_major = required_major_llvm_version ( false ) ;
134- // first, if LLVM_CONFIG is set then see if its llvm version if 7.x, if so, use that.
135- let config_env = tracked_env_var_os ( "LLVM_CONFIG" ) ;
136- // if LLVM_CONFIG is not set, try using llvm-config as a normal app in PATH.
137- let path_to_try = config_env. unwrap_or_else ( || "llvm-config" . into ( ) ) ;
138-
139- // if USE_PREBUILT_LLVM is set to 1 then download prebuilt llvm without trying llvm-config
140- if tracked_env_var_os ( "USE_PREBUILT_LLVM" ) != Some ( "1" . into ( ) ) {
141- let cmd = Command :: new ( & path_to_try) . arg ( "--version" ) . output ( ) ;
142-
143- if let Ok ( out) = cmd {
144- let version = String :: from_utf8 ( out. stdout ) . unwrap ( ) ;
145- if version. starts_with ( & required_major. to_string ( ) ) {
146- return PathBuf :: from ( path_to_try) ;
147- }
148- println ! (
149- "cargo:warning=Prebuilt llvm-config version does not start with {required_major}"
150- ) ;
151- } else {
152- println ! ( "cargo:warning=Failed to run prebuilt llvm-config" ) ;
153- }
154- }
155-
156- // otherwise, download prebuilt LLVM.
157- println ! ( "cargo:warning=Downloading prebuilt LLVM" ) ;
158- let mut url = tracked_env_var_os ( "PREBUILT_LLVM_URL" )
159- . map ( |x| x. to_string_lossy ( ) . to_string ( ) )
160- . unwrap_or_else ( || PREBUILT_LLVM_URL_LLVM7 . to_string ( ) ) ;
161-
112+ fn download_prebuilt_llvm ( target : & str , base_url : & str ) -> PathBuf {
162113 let prebuilt_name = target_to_llvm_prebuilt ( target) ;
163- url = format ! ( "{url}{prebuilt_name}" ) ;
114+ let url = format ! ( "{base_url}{prebuilt_name}" ) ;
115+
116+ println ! ( "cargo:warning=Downloading prebuilt LLVM from {url}" ) ;
164117
165118 let out = env:: var ( "OUT_DIR" ) . expect ( "OUT_DIR was not set" ) ;
166119 let mut easy = Easy :: new ( ) ;
@@ -194,19 +147,61 @@ fn find_llvm_config_llvm7(target: &str) -> PathBuf {
194147 . join ( format ! ( "llvm-config{}" , std:: env:: consts:: EXE_SUFFIX ) )
195148}
196149
197- fn find_llvm_as_llvm19 ( llvm_config : & Path ) -> PathBuf {
198- let required_major = required_major_llvm_version ( true ) ;
150+ fn find_llvm_config ( target : & str , flavor : & LlvmFlavor ) -> PathBuf {
151+ // USE_PREBUILT_LLVM=1 skips local probing and goes straight to download.
152+ if tracked_env_var_os ( "USE_PREBUILT_LLVM" ) != Some ( "1" . into ( ) ) {
153+ let mut candidates = Vec :: new ( ) ;
154+
155+ if let Some ( path) = tracked_env_var_os ( flavor. config_env ) {
156+ candidates. push ( PathBuf :: from ( path) ) ;
157+ }
158+
159+ candidates. push ( PathBuf :: from ( flavor. default_binary ) ) ;
160+
161+ if flavor. probe_cuda_home
162+ && let Some ( cuda_home) = tracked_env_var_os ( "CUDA_HOME" )
163+ {
164+ let cuda_home = PathBuf :: from ( cuda_home) ;
165+ candidates. push ( cuda_home. join ( "nvvm" ) . join ( "bin" ) . join ( "llvm-config" ) ) ;
166+ candidates. push ( cuda_home. join ( "bin" ) . join ( "llvm-config" ) ) ;
167+ }
168+
169+ for candidate in & candidates {
170+ if llvm_version_matches ( candidate, flavor. major ) {
171+ return candidate. clone ( ) ;
172+ }
173+ }
174+
175+ let tried = candidates
176+ . iter ( )
177+ . map ( |candidate| format ! ( " - {}" , candidate. display( ) ) )
178+ . collect :: < Vec < _ > > ( )
179+ . join ( "\n " ) ;
180+
181+ println ! (
182+ "cargo:warning=No matching LLVM {} toolchain found, falling back to prebuilt LLVM. Tried:\n {}" ,
183+ flavor. major, tried
184+ ) ;
185+ }
186+
187+ let url = tracked_env_var_os ( "PREBUILT_LLVM_URL" )
188+ . map ( |x| x. to_string_lossy ( ) . to_string ( ) )
189+ . unwrap_or_else ( || flavor. prebuilt_url . to_string ( ) ) ;
190+ download_prebuilt_llvm ( target, & url)
191+ }
192+
193+ fn find_llvm_as ( llvm_config : & Path , flavor : & LlvmFlavor ) -> PathBuf {
199194 let mut candidates = Vec :: new ( ) ;
200195
201196 if let Some ( path) = sibling_llvm_tool ( llvm_config, "llvm-as" ) {
202197 candidates. push ( path) ;
203198 }
204199
205- candidates. push ( PathBuf :: from ( "llvm-as-19" ) ) ;
200+ candidates. push ( PathBuf :: from ( format ! ( "llvm-as-{}" , flavor . major ) ) ) ;
206201 candidates. push ( PathBuf :: from ( "llvm-as" ) ) ;
207202
208203 for candidate in & candidates {
209- if llvm_version_matches ( candidate, required_major ) {
204+ if llvm_version_matches ( candidate, flavor . major ) {
210205 return candidate. clone ( ) ;
211206 }
212207 }
@@ -218,8 +213,9 @@ fn find_llvm_as_llvm19(llvm_config: &Path) -> PathBuf {
218213 . join ( "\n " ) ;
219214
220215 fail ( & format ! (
221- "LLVM 19 support is enabled, but llvm-as 19 was not found.\n \
222- Tried:\n {tried}"
216+ "LLVM {} support is enabled, but llvm-as {} was not found.\n \
217+ Tried:\n {tried}",
218+ flavor. major, flavor. major
223219 ) ) ;
224220}
225221
@@ -238,60 +234,49 @@ pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString>
238234 env:: var_os ( key)
239235}
240236
241- fn configure_libintrinsics ( llvm_config : & Path , llvm19_enabled : bool ) {
237+ fn configure_libintrinsics ( llvm_config : & Path , flavor : & LlvmFlavor ) {
242238 let manifest_dir =
243239 PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) . expect ( "CARGO_MANIFEST_DIR was not set" ) ) ;
244240
245- // Both paths share `libintrinsics.ll`. The LLVM 7 build consumes the checked-in
246- // `libintrinsics.bc` (regenerate manually with `llvm-as-7` when the .ll changes).
247- // The LLVM 19 build assembles the same .ll on the fly with `llvm-as-19`.
248241 build_helper:: rerun_if_changed ( Path :: new ( "libintrinsics.ll" ) ) ;
249242
250- if llvm19_enabled {
251- let input = manifest_dir. join ( "libintrinsics.ll" ) ;
252- let output = PathBuf :: from ( env:: var ( "OUT_DIR" ) . expect ( "OUT_DIR was not set" ) )
253- . join ( "libintrinsics_v19.bc" ) ;
254- let llvm_as = find_llvm_as_llvm19 ( llvm_config) ;
255-
256- let status = Command :: new ( & llvm_as)
257- . arg ( & input)
258- . arg ( "-o" )
259- . arg ( & output)
260- . stderr ( Stdio :: inherit ( ) )
261- . stdout ( Stdio :: inherit ( ) )
262- . status ( )
263- . unwrap_or_else ( |err| {
264- fail ( & format ! (
265- "failed to execute llvm-as for LLVM 19: {llvm_as:?}\n error: {err}"
266- ) )
267- } ) ;
268-
269- if !status. success ( ) {
243+ let input = manifest_dir. join ( "libintrinsics.ll" ) ;
244+ let output = PathBuf :: from ( env:: var ( "OUT_DIR" ) . expect ( "OUT_DIR was not set" ) )
245+ . join ( format ! ( "libintrinsics_v{}.bc" , flavor. major) ) ;
246+ let llvm_as = find_llvm_as ( llvm_config, flavor) ;
247+
248+ let status = Command :: new ( & llvm_as)
249+ . arg ( & input)
250+ . arg ( "-o" )
251+ . arg ( & output)
252+ . stderr ( Stdio :: inherit ( ) )
253+ . stdout ( Stdio :: inherit ( ) )
254+ . status ( )
255+ . unwrap_or_else ( |err| {
270256 fail ( & format ! (
271- "llvm-as did not assemble {} successfully" ,
272- input. display( )
273- ) ) ;
274- }
275-
276- println ! (
277- "cargo:rustc-env=NVVM_LIBINTRINSICS_BC_PATH={}" ,
278- output. display( )
279- ) ;
280- } else {
281- build_helper:: rerun_if_changed ( Path :: new ( "libintrinsics.bc" ) ) ;
282- println ! (
283- "cargo:rustc-env=NVVM_LIBINTRINSICS_BC_PATH={}" ,
284- manifest_dir. join( "libintrinsics.bc" ) . display( )
285- ) ;
257+ "failed to execute llvm-as for LLVM {}: {llvm_as:?}\n error: {err}" ,
258+ flavor. major
259+ ) )
260+ } ) ;
261+
262+ if !status. success ( ) {
263+ fail ( & format ! (
264+ "llvm-as did not assemble {} successfully" ,
265+ input. display( )
266+ ) ) ;
286267 }
268+
269+ println ! (
270+ "cargo:rustc-env=NVVM_LIBINTRINSICS_BC_PATH={}" ,
271+ output. display( )
272+ ) ;
287273}
288274
289- fn rustc_llvm_build ( llvm19_enabled : bool ) {
275+ fn rustc_llvm_build ( flavor : & LlvmFlavor ) {
290276 let target = env:: var ( "TARGET" ) . expect ( "TARGET was not set" ) ;
291- let llvm_config = find_llvm_config ( & target, llvm19_enabled) ;
292- let required_major = required_major_llvm_version ( llvm19_enabled) ;
277+ let llvm_config = find_llvm_config ( & target, flavor) ;
293278
294- configure_libintrinsics ( & llvm_config, llvm19_enabled ) ;
279+ configure_libintrinsics ( & llvm_config, flavor ) ;
295280
296281 let required_components = & [ "ipo" , "bitreader" , "bitwriter" , "lto" , "nvptx" ] ;
297282
@@ -340,7 +325,7 @@ fn rustc_llvm_build(llvm19_enabled: bool) {
340325 cfg. define ( & flag, None ) ;
341326 }
342327
343- let llvm_version_major = required_major . to_string ( ) ;
328+ let llvm_version_major = flavor . major . to_string ( ) ;
344329 cfg. define ( "LLVM_VERSION_MAJOR" , Some ( llvm_version_major. as_str ( ) ) ) ;
345330
346331 if tracked_env_var_os ( "LLVM_RUSTLLVM" ) . is_some ( ) {
0 commit comments