@@ -6,6 +6,15 @@ use std::{
6
6
process:: { Command , Stdio } ,
7
7
} ;
8
8
9
+ use curl:: easy:: Easy ;
10
+ use tar:: Archive ;
11
+ use xz:: read:: XzDecoder ;
12
+
13
+ static PREBUILT_LLVM_URL : & str =
14
+ "https://github.com/RDambrosio016/rustc_codegen_nvvm-llvm/releases/download/LLVM-7.1.0/" ;
15
+
16
+ static REQUIRED_MAJOR_LLVM_VERSION : u8 = 7 ;
17
+
9
18
fn main ( ) {
10
19
rustc_llvm_build ( ) ;
11
20
@@ -40,6 +49,74 @@ pub fn output(cmd: &mut Command) -> String {
40
49
String :: from_utf8 ( output. stdout ) . unwrap ( )
41
50
}
42
51
52
+ fn target_to_llvm_prebuilt ( target : & str ) -> String {
53
+ let base = match target {
54
+ "x86_64-pc-windows-msvc" => "windows-x86_64" ,
55
+ "x86_64-unknown-linux-gnu" => "linux-x86_64" ,
56
+ _ => panic ! ( "Unsupported target with no matching prebuilt LLVM: `{}`, install LLVM and set LLVM_CONFIG" , target)
57
+ } ;
58
+ format ! ( "{}.tar.xz" , base)
59
+ }
60
+
61
+ fn find_llvm_config ( target : & str ) -> PathBuf {
62
+ // first, if LLVM_CONFIG is set then see if its llvm version if 7.x, if so, use that.
63
+ let config_env = tracked_env_var_os ( "LLVM_CONFIG" ) ;
64
+ // if LLVM_CONFIG is not set, try using llvm-config as a normal app in PATH.
65
+ let path_to_try = config_env. unwrap_or_else ( || "llvm-config" . into ( ) ) ;
66
+
67
+ // if USE_PREBUILT_LLVM is set to 1 then download prebuilt llvm without trying llvm-config
68
+ if tracked_env_var_os ( "USE_PREBUILT_LLVM" ) != Some ( "1" . into ( ) ) {
69
+ let cmd = Command :: new ( & path_to_try) . arg ( "--version" ) . output ( ) ;
70
+
71
+ if let Ok ( out) = cmd {
72
+ let version = String :: from_utf8 ( out. stdout ) . unwrap ( ) ;
73
+ if version. starts_with ( & REQUIRED_MAJOR_LLVM_VERSION . to_string ( ) ) {
74
+ return PathBuf :: from ( path_to_try) ;
75
+ }
76
+ }
77
+ }
78
+
79
+ // otherwise, download prebuilt LLVM.
80
+ println ! ( "cargo:warning=LLVM not found, downloading prebuilt LLVM" ) ;
81
+ let mut url = tracked_env_var_os ( "PREBUILT_LLVM_URL" )
82
+ . map ( |x| x. to_string_lossy ( ) . to_string ( ) )
83
+ . unwrap_or_else ( || PREBUILT_LLVM_URL . to_string ( ) ) ;
84
+
85
+ let prebuilt_name = target_to_llvm_prebuilt ( target) ;
86
+ url = format ! ( "{}{}" , url, prebuilt_name) ;
87
+
88
+ let out = env:: var ( "OUT_DIR" ) . expect ( "OUT_DIR was not set" ) ;
89
+ let mut easy = Easy :: new ( ) ;
90
+
91
+ easy. url ( & url) . unwrap ( ) ;
92
+ let _redirect = easy. follow_location ( true ) . unwrap ( ) ;
93
+ let mut xz_encoded = Vec :: with_capacity ( 20_000_000 ) ; // 20mb
94
+ {
95
+ let mut transfer = easy. transfer ( ) ;
96
+ transfer
97
+ . write_function ( |data| {
98
+ xz_encoded. extend_from_slice ( data) ;
99
+ Ok ( data. len ( ) )
100
+ } )
101
+ . expect ( "Failed to download prebuilt LLVM" ) ;
102
+ transfer
103
+ . perform ( )
104
+ . expect ( "Failed to download prebuilt LLVM" ) ;
105
+ }
106
+
107
+ let decompressor = XzDecoder :: new ( xz_encoded. as_slice ( ) ) ;
108
+ let mut ar = Archive :: new ( decompressor) ;
109
+
110
+ ar. unpack ( & out) . expect ( "Failed to unpack LLVM to LLVM dir" ) ;
111
+ let out_path = PathBuf :: from ( out) . join ( prebuilt_name. strip_suffix ( ".tar.xz" ) . unwrap ( ) ) ;
112
+
113
+ println ! ( "cargo:rerun-if-changed={}" , out_path. display( ) ) ;
114
+
115
+ out_path
116
+ . join ( "bin" )
117
+ . join ( format ! ( "llvm-config{}" , std:: env:: consts:: EXE_SUFFIX ) )
118
+ }
119
+
43
120
fn detect_llvm_link ( ) -> ( & ' static str , & ' static str ) {
44
121
// Force the link mode we want, preferring static by default, but
45
122
// possibly overridden by `configure --enable-llvm-link-shared`.
@@ -57,62 +134,13 @@ pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString>
57
134
58
135
fn rustc_llvm_build ( ) {
59
136
let target = env:: var ( "TARGET" ) . expect ( "TARGET was not set" ) ;
60
- let llvm_config = tracked_env_var_os ( "LLVM_CONFIG" )
61
- . map ( |x| Some ( PathBuf :: from ( x) ) )
62
- . unwrap_or_else ( || {
63
- if let Some ( dir) = tracked_env_var_os ( "CARGO_TARGET_DIR" ) . map ( PathBuf :: from) {
64
- let to_test = dir
65
- . parent ( )
66
- . unwrap ( )
67
- . parent ( )
68
- . unwrap ( )
69
- . join ( & target)
70
- . join ( "llvm/bin/llvm-config" ) ;
71
- if Command :: new ( & to_test) . output ( ) . is_ok ( ) {
72
- return Some ( to_test) ;
73
- }
74
- }
75
- None
76
- } ) ;
137
+ let llvm_config = find_llvm_config ( & target) ;
77
138
78
- if let Some ( llvm_config) = & llvm_config {
79
- println ! ( "cargo:rerun-if-changed={}" , llvm_config. display( ) ) ;
80
- }
81
- let llvm_config = llvm_config. unwrap_or_else ( || PathBuf :: from ( "llvm-config" ) ) ;
82
-
83
- let optional_components = & [
84
- "x86" ,
85
- "arm" ,
86
- "aarch64" ,
87
- "amdgpu" ,
88
- "avr" ,
89
- "mips" ,
90
- "powerpc" ,
91
- "systemz" ,
92
- "jsbackend" ,
93
- "webassembly" ,
94
- "msp430" ,
95
- "sparc" ,
96
- "nvptx" ,
97
- "hexagon" ,
98
- "riscv" ,
99
- "bpf" ,
100
- ] ;
101
-
102
- let required_components = & [
103
- "ipo" ,
104
- "bitreader" ,
105
- "bitwriter" ,
106
- "linker" ,
107
- "asmparser" ,
108
- "lto" ,
109
- "coverage" ,
110
- "instrumentation" ,
111
- ] ;
139
+ let required_components = & [ "ipo" , "bitreader" , "bitwriter" , "lto" , "nvptx" ] ;
112
140
113
141
let components = output ( Command :: new ( & llvm_config) . arg ( "--components" ) ) ;
114
142
let mut components = components. split_whitespace ( ) . collect :: < Vec < _ > > ( ) ;
115
- components. retain ( |c| optional_components . contains ( c ) || required_components. contains ( c) ) ;
143
+ components. retain ( |c| required_components. contains ( c) ) ;
116
144
117
145
for component in required_components {
118
146
if !components. contains ( component) {
@@ -134,6 +162,16 @@ fn rustc_llvm_build() {
134
162
if flag. starts_with ( "-flto" ) {
135
163
continue ;
136
164
}
165
+ // ignore flags that aren't supported in gcc 8
166
+ if flag == "-Wcovered-switch-default" {
167
+ continue ;
168
+ }
169
+ if flag == "-Wstring-conversion" {
170
+ continue ;
171
+ }
172
+ if flag == "-Werror=unguarded-availability-new" {
173
+ continue ;
174
+ }
137
175
138
176
cfg. flag ( flag) ;
139
177
}
@@ -151,7 +189,7 @@ fn rustc_llvm_build() {
151
189
build_helper:: rerun_if_changed ( Path :: new ( "rustc_llvm_wrapper" ) ) ;
152
190
cfg. file ( "rustc_llvm_wrapper/RustWrapper.cpp" )
153
191
. file ( "rustc_llvm_wrapper/PassWrapper.cpp" )
154
- . include ( "rustc_llvm_wrapper/rustllvm.h " )
192
+ . include ( "rustc_llvm_wrapper" )
155
193
. cpp ( true )
156
194
. cpp_link_stdlib ( None ) // we handle this below
157
195
. compile ( "llvm-wrapper" ) ;
@@ -209,7 +247,7 @@ fn rustc_llvm_build() {
209
247
210
248
// Link in the system libraries that LLVM depends on
211
249
#[ cfg( not( target_os = "windows" ) ) ]
212
- link_llvm_system_libs ( & llvm_config) ;
250
+ link_llvm_system_libs ( & llvm_config, required_components ) ;
213
251
214
252
// LLVM ldflags
215
253
//
@@ -298,10 +336,14 @@ fn rustc_llvm_build() {
298
336
}
299
337
300
338
#[ cfg( not( target_os = "windows" ) ) ]
301
- fn link_llvm_system_libs ( llvm_config : & Path ) {
339
+ fn link_llvm_system_libs ( llvm_config : & Path , components : & [ & str ] ) {
302
340
let mut cmd = Command :: new ( & llvm_config) ;
303
341
cmd. arg ( "--system-libs" ) ;
304
342
343
+ for comp in components {
344
+ cmd. arg ( comp) ;
345
+ }
346
+
305
347
for lib in output ( & mut cmd) . split_whitespace ( ) {
306
348
let name = if let Some ( stripped) = lib. strip_prefix ( "-l" ) {
307
349
stripped
0 commit comments