@@ -26,7 +26,7 @@ use std::path::{Path, PathBuf};
2626use std:: process:: Command ;
2727use std:: { env, iter} ;
2828
29- use crate :: core:: config:: { Target , TargetSelection } ;
29+ use crate :: core:: config:: TargetSelection ;
3030use crate :: utils:: helpers:: output;
3131use crate :: { Build , CLang , GitRepo } ;
3232
@@ -107,10 +107,11 @@ pub fn find(build: &Build) {
107107pub fn find_target ( build : & Build , target : TargetSelection ) {
108108 let mut cfg = new_cc_build ( build, target) ;
109109 let config = build. config . target_config . get ( & target) ;
110- if let Some ( cc) = config. and_then ( |c| c. cc . as_ref ( ) ) {
110+ if let Some ( cc) = config
111+ . and_then ( |c| c. cc . clone ( ) )
112+ . or_else ( || default_compiler ( & mut cfg, Language :: C , target, build) )
113+ {
111114 cfg. compiler ( cc) ;
112- } else {
113- set_compiler ( & mut cfg, Language :: C , target, config, build) ;
114115 }
115116
116117 let compiler = cfg. get_compiler ( ) ;
@@ -127,12 +128,12 @@ pub fn find_target(build: &Build, target: TargetSelection) {
127128 // We'll need one anyways if the target triple is also a host triple
128129 let mut cfg = new_cc_build ( build, target) ;
129130 cfg. cpp ( true ) ;
130- let cxx_configured = if let Some ( cxx) = config. and_then ( |c| c. cxx . as_ref ( ) ) {
131+ let cxx_configured = if let Some ( cxx) = config
132+ . and_then ( |c| c. cxx . clone ( ) )
133+ . or_else ( || default_compiler ( & mut cfg, Language :: CPlusPlus , target, build) )
134+ {
131135 cfg. compiler ( cxx) ;
132136 true
133- } else if build. hosts . contains ( & target) || build. build == target {
134- set_compiler ( & mut cfg, Language :: CPlusPlus , target, config, build) ;
135- true
136137 } else {
137138 // Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
138139 cfg. try_get_compiler ( ) . is_ok ( )
@@ -161,68 +162,70 @@ pub fn find_target(build: &Build, target: TargetSelection) {
161162 }
162163}
163164
164- fn set_compiler (
165+ fn default_compiler (
165166 cfg : & mut cc:: Build ,
166167 compiler : Language ,
167168 target : TargetSelection ,
168- config : Option < & Target > ,
169169 build : & Build ,
170- ) {
170+ ) -> Option < PathBuf > {
171171 match & * target. triple {
172172 // When compiling for android we may have the NDK configured in the
173173 // config.toml in which case we look there. Otherwise the default
174174 // compiler already takes into account the triple in question.
175- t if t. contains ( "android" ) => {
176- if let Some ( ndk ) = config . and_then ( |c| c . ndk . as_ref ( ) ) {
177- cfg . compiler ( ndk_compiler ( compiler , & * target . triple , ndk ) ) ;
178- }
179- }
175+ t if t. contains ( "android" ) => build
176+ . config
177+ . android_ndk
178+ . as_ref ( )
179+ . map ( |ndk| ndk_compiler ( compiler , & * target . triple , ndk ) ) ,
180180
181181 // The default gcc version from OpenBSD may be too old, try using egcc,
182182 // which is a gcc version from ports, if this is the case.
183183 t if t. contains ( "openbsd" ) => {
184184 let c = cfg. get_compiler ( ) ;
185185 let gnu_compiler = compiler. gcc ( ) ;
186186 if !c. path ( ) . ends_with ( gnu_compiler) {
187- return ;
187+ return None ;
188188 }
189189
190190 let output = output ( c. to_command ( ) . arg ( "--version" ) ) ;
191- let i = match output. find ( " 4." ) {
192- Some ( i) => i,
193- None => return ,
194- } ;
191+ let i = output. find ( " 4." ) ?;
195192 match output[ i + 3 ..] . chars ( ) . next ( ) . unwrap ( ) {
196193 '0' ..='6' => { }
197- _ => return ,
194+ _ => return None ,
198195 }
199196 let alternative = format ! ( "e{gnu_compiler}" ) ;
200197 if Command :: new ( & alternative) . output ( ) . is_ok ( ) {
201- cfg. compiler ( alternative) ;
198+ Some ( PathBuf :: from ( alternative) )
199+ } else {
200+ None
202201 }
203202 }
204203
205- "mips-unknown-linux-musl" => {
204+ "mips-unknown-linux-musl" if compiler == Language :: C => {
206205 if cfg. get_compiler ( ) . path ( ) . to_str ( ) == Some ( "gcc" ) {
207- cfg. compiler ( "mips-linux-musl-gcc" ) ;
206+ Some ( PathBuf :: from ( "mips-linux-musl-gcc" ) )
207+ } else {
208+ None
208209 }
209210 }
210- "mipsel-unknown-linux-musl" => {
211+ "mipsel-unknown-linux-musl" if compiler == Language :: C => {
211212 if cfg. get_compiler ( ) . path ( ) . to_str ( ) == Some ( "gcc" ) {
212- cfg. compiler ( "mipsel-linux-musl-gcc" ) ;
213+ Some ( PathBuf :: from ( "mipsel-linux-musl-gcc" ) )
214+ } else {
215+ None
213216 }
214217 }
215218
216- t if t. contains ( "musl" ) => {
219+ t if t. contains ( "musl" ) && compiler == Language :: C => {
217220 if let Some ( root) = build. musl_root ( target) {
218221 let guess = root. join ( "bin/musl-gcc" ) ;
219- if guess. exists ( ) {
220- cfg . compiler ( guess ) ;
221- }
222+ if guess. exists ( ) { Some ( guess ) } else { None }
223+ } else {
224+ None
222225 }
223226 }
224227
225- _ => { }
228+ _ => None ,
226229 }
227230}
228231
@@ -243,10 +246,22 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path
243246 let api_level =
244247 if triple. contains ( "aarch64" ) || triple. contains ( "x86_64" ) { "21" } else { "19" } ;
245248 let compiler = format ! ( "{}{}-{}" , triple_translated, api_level, compiler. clang( ) ) ;
246- ndk. join ( "bin" ) . join ( compiler)
249+ let host_tag = if cfg ! ( target_os = "macos" ) {
250+ // The NDK uses universal binaries, so this is correct even on ARM.
251+ "darwin-x86_64"
252+ } else if cfg ! ( target_os = "windows" ) {
253+ "windows-x86_64"
254+ } else {
255+ // NDK r25b only has official releases for macOS, Windows and Linux.
256+ // Try the Linux directory everywhere else, on the assumption that the OS has an
257+ // emulation layer that can cope (e.g. BSDs).
258+ "linux-x86_64"
259+ } ;
260+ ndk. join ( "toolchains" ) . join ( "llvm" ) . join ( "prebuilt" ) . join ( host_tag) . join ( "bin" ) . join ( compiler)
247261}
248262
249263/// The target programming language for a native compiler.
264+ #[ derive( PartialEq ) ]
250265pub ( crate ) enum Language {
251266 /// The compiler is targeting C.
252267 C ,
0 commit comments