11use std:: env;
2+ use std:: ffi:: { OsStr , OsString } ;
3+ use std:: fmt:: Display ;
24use std:: path:: { Path , PathBuf } ;
3- use std:: process:: Command ;
4-
5- use build_helper:: { output, tracked_env_var_os} ;
5+ use std:: process:: { Command , Stdio } ;
66
77fn detect_llvm_link ( ) -> ( & ' static str , & ' static str ) {
88 // Force the link mode we want, preferring static by default, but
@@ -14,13 +14,74 @@ fn detect_llvm_link() -> (&'static str, &'static str) {
1414 }
1515}
1616
17+ // Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
18+ // break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
19+ // shared library, which means that when our freshly built llvm-config goes to load it's
20+ // associated LLVM, it actually loads the compiler's LLVM. In particular when building the first
21+ // compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from
22+ // the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't
23+ // perfect -- we might actually want to see something from Cargo's added library paths -- but
24+ // for now it works.
25+ fn restore_library_path ( ) {
26+ let key = tracked_env_var_os ( "REAL_LIBRARY_PATH_VAR" ) . expect ( "REAL_LIBRARY_PATH_VAR" ) ;
27+ if let Some ( env) = tracked_env_var_os ( "REAL_LIBRARY_PATH" ) {
28+ env:: set_var ( & key, & env) ;
29+ } else {
30+ env:: remove_var ( & key) ;
31+ }
32+ }
33+
34+ /// Reads an environment variable and adds it to dependencies.
35+ /// Supposed to be used for all variables except those set for build scripts by cargo
36+ /// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
37+ fn tracked_env_var_os < K : AsRef < OsStr > + Display > ( key : K ) -> Option < OsString > {
38+ println ! ( "cargo:rerun-if-env-changed={}" , key) ;
39+ env:: var_os ( key)
40+ }
41+
42+ fn rerun_if_changed_anything_in_dir ( dir : & Path ) {
43+ let mut stack = dir
44+ . read_dir ( )
45+ . unwrap ( )
46+ . map ( |e| e. unwrap ( ) )
47+ . filter ( |e| & * e. file_name ( ) != ".git" )
48+ . collect :: < Vec < _ > > ( ) ;
49+ while let Some ( entry) = stack. pop ( ) {
50+ let path = entry. path ( ) ;
51+ if entry. file_type ( ) . unwrap ( ) . is_dir ( ) {
52+ stack. extend ( path. read_dir ( ) . unwrap ( ) . map ( |e| e. unwrap ( ) ) ) ;
53+ } else {
54+ println ! ( "cargo:rerun-if-changed={}" , path. display( ) ) ;
55+ }
56+ }
57+ }
58+
59+ #[ track_caller]
60+ fn output ( cmd : & mut Command ) -> String {
61+ let output = match cmd. stderr ( Stdio :: inherit ( ) ) . output ( ) {
62+ Ok ( status) => status,
63+ Err ( e) => {
64+ println ! ( "\n \n failed to execute command: {:?}\n error: {}\n \n " , cmd, e) ;
65+ std:: process:: exit ( 1 ) ;
66+ }
67+ } ;
68+ if !output. status . success ( ) {
69+ panic ! (
70+ "command did not execute successfully: {:?}\n \
71+ expected success, got: {}",
72+ cmd, output. status
73+ ) ;
74+ }
75+ String :: from_utf8 ( output. stdout ) . unwrap ( )
76+ }
77+
1778fn main ( ) {
1879 if tracked_env_var_os ( "RUST_CHECK" ) . is_some ( ) {
1980 // If we're just running `check`, there's no need for LLVM to be built.
2081 return ;
2182 }
2283
23- build_helper :: restore_library_path ( ) ;
84+ restore_library_path ( ) ;
2485
2586 let target = env:: var ( "TARGET" ) . expect ( "TARGET was not set" ) ;
2687 let llvm_config =
@@ -160,7 +221,7 @@ fn main() {
160221 cfg. debug ( false ) ;
161222 }
162223
163- build_helper :: rerun_if_changed_anything_in_dir ( Path :: new ( "llvm-wrapper" ) ) ;
224+ rerun_if_changed_anything_in_dir ( Path :: new ( "llvm-wrapper" ) ) ;
164225 cfg. file ( "llvm-wrapper/PassWrapper.cpp" )
165226 . file ( "llvm-wrapper/RustWrapper.cpp" )
166227 . file ( "llvm-wrapper/ArchiveWrapper.cpp" )
0 commit comments