@@ -26,7 +26,7 @@ use std::path::{Path, PathBuf};
2626use std:: process:: Command ;
2727use std:: { env, iter} ;
2828
29- use crate :: config:: { Target , TargetSelection } ;
29+ use crate :: config:: TargetSelection ;
3030use crate :: util:: output;
3131use crate :: { Build , CLang , GitRepo } ;
3232
@@ -100,10 +100,11 @@ pub fn find(build: &mut Build) {
100100 for target in targets. into_iter ( ) {
101101 let mut cfg = new_cc_build ( build, target) ;
102102 let config = build. config . target_config . get ( & target) ;
103- if let Some ( cc) = config. and_then ( |c| c. cc . as_ref ( ) ) {
103+ if let Some ( cc) = config
104+ . and_then ( |c| c. cc . clone ( ) )
105+ . or_else ( || default_compiler ( & mut cfg, Language :: C , target, build) )
106+ {
104107 cfg. compiler ( cc) ;
105- } else {
106- set_compiler ( & mut cfg, Language :: C , target, config, build) ;
107108 }
108109
109110 let compiler = cfg. get_compiler ( ) ;
@@ -120,12 +121,12 @@ pub fn find(build: &mut Build) {
120121 // We'll need one anyways if the target triple is also a host triple
121122 let mut cfg = new_cc_build ( build, target) ;
122123 cfg. cpp ( true ) ;
123- let cxx_configured = if let Some ( cxx) = config. and_then ( |c| c. cxx . as_ref ( ) ) {
124+ let cxx_configured = if let Some ( cxx) = config
125+ . and_then ( |c| c. cxx . clone ( ) )
126+ . or_else ( || default_compiler ( & mut cfg, Language :: CPlusPlus , target, build) )
127+ {
124128 cfg. compiler ( cxx) ;
125129 true
126- } else if build. hosts . contains ( & target) || build. build == target {
127- set_compiler ( & mut cfg, Language :: CPlusPlus , target, config, build) ;
128- true
129130 } else {
130131 // Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
131132 cfg. try_get_compiler ( ) . is_ok ( )
@@ -155,68 +156,70 @@ pub fn find(build: &mut Build) {
155156 }
156157}
157158
158- fn set_compiler (
159+ fn default_compiler (
159160 cfg : & mut cc:: Build ,
160161 compiler : Language ,
161162 target : TargetSelection ,
162- config : Option < & Target > ,
163163 build : & Build ,
164- ) {
164+ ) -> Option < PathBuf > {
165165 match & * target. triple {
166166 // When compiling for android we may have the NDK configured in the
167167 // config.toml in which case we look there. Otherwise the default
168168 // compiler already takes into account the triple in question.
169- t if t. contains ( "android" ) => {
170- if let Some ( ndk ) = config . and_then ( |c| c . ndk . as_ref ( ) ) {
171- cfg . compiler ( ndk_compiler ( compiler , & * target . triple , ndk ) ) ;
172- }
173- }
169+ t if t. contains ( "android" ) => build
170+ . config
171+ . android_ndk
172+ . as_ref ( )
173+ . map ( |ndk| ndk_compiler ( compiler , & * target . triple , ndk ) ) ,
174174
175175 // The default gcc version from OpenBSD may be too old, try using egcc,
176176 // which is a gcc version from ports, if this is the case.
177177 t if t. contains ( "openbsd" ) => {
178178 let c = cfg. get_compiler ( ) ;
179179 let gnu_compiler = compiler. gcc ( ) ;
180180 if !c. path ( ) . ends_with ( gnu_compiler) {
181- return ;
181+ return None ;
182182 }
183183
184184 let output = output ( c. to_command ( ) . arg ( "--version" ) ) ;
185- let i = match output. find ( " 4." ) {
186- Some ( i) => i,
187- None => return ,
188- } ;
185+ let i = output. find ( " 4." ) ?;
189186 match output[ i + 3 ..] . chars ( ) . next ( ) . unwrap ( ) {
190187 '0' ..='6' => { }
191- _ => return ,
188+ _ => return None ,
192189 }
193190 let alternative = format ! ( "e{}" , gnu_compiler) ;
194191 if Command :: new ( & alternative) . output ( ) . is_ok ( ) {
195- cfg. compiler ( alternative) ;
192+ Some ( PathBuf :: from ( alternative) )
193+ } else {
194+ None
196195 }
197196 }
198197
199198 "mips-unknown-linux-musl" => {
200199 if cfg. get_compiler ( ) . path ( ) . to_str ( ) == Some ( "gcc" ) {
201- cfg. compiler ( "mips-linux-musl-gcc" ) ;
200+ Some ( PathBuf :: from ( "mips-linux-musl-gcc" ) )
201+ } else {
202+ None
202203 }
203204 }
204205 "mipsel-unknown-linux-musl" => {
205206 if cfg. get_compiler ( ) . path ( ) . to_str ( ) == Some ( "gcc" ) {
206- cfg. compiler ( "mipsel-linux-musl-gcc" ) ;
207+ Some ( PathBuf :: from ( "mipsel-linux-musl-gcc" ) )
208+ } else {
209+ None
207210 }
208211 }
209212
210213 t if t. contains ( "musl" ) => {
211214 if let Some ( root) = build. musl_root ( target) {
212215 let guess = root. join ( "bin/musl-gcc" ) ;
213- if guess. exists ( ) {
214- cfg . compiler ( guess ) ;
215- }
216+ if guess. exists ( ) { Some ( guess ) } else { None }
217+ } else {
218+ None
216219 }
217220 }
218221
219- _ => { }
222+ _ => None ,
220223 }
221224}
222225
@@ -237,7 +240,18 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path
237240 let api_level =
238241 if triple. contains ( "aarch64" ) || triple. contains ( "x86_64" ) { "21" } else { "19" } ;
239242 let compiler = format ! ( "{}{}-{}" , triple_translated, api_level, compiler. clang( ) ) ;
240- ndk. join ( "bin" ) . join ( compiler)
243+ let host_tag = if cfg ! ( target_os = "macos" ) {
244+ // The NDK uses universal binaries, so this is correct even on ARM.
245+ "darwin-x86_64"
246+ } else if cfg ! ( target_os = "windows" ) {
247+ "windows-x86_64"
248+ } else {
249+ // NDK r25b only has official releases for macOS, Windows and Linux.
250+ // Try the Linux directory everywhere else, on the assumption that the OS has an
251+ // emulation layer that can cope (e.g. BSDs).
252+ "linux-x86_64"
253+ } ;
254+ ndk. join ( "toolchains" ) . join ( "llvm" ) . join ( "prebuilt" ) . join ( host_tag) . join ( "bin" ) . join ( compiler)
241255}
242256
243257/// The target programming language for a native compiler.
0 commit comments