From 724afc78ae39709697eefa5b60914409da9f092c Mon Sep 17 00:00:00 2001 From: "Evgeniy A. Dushistov" Date: Sat, 9 May 2020 18:17:28 +0300 Subject: [PATCH] Implement autodetection for default compiler from NDK ref #459 --- src/lib.rs | 104 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index caf4f13e9..a479b2307 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1370,6 +1370,12 @@ impl Build { cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); } + if cmd.family == ToolFamily::Clang && target.contains("android") { + for arg in defines_for_android_compiler(&cmd.path).into_iter() { + cmd.push_cc_arg(arg.into()); + } + } + if !target.contains("-ios") { cmd.push_cc_arg("-ffunction-sections".into()); cmd.push_cc_arg("-fdata-sections".into()); @@ -1974,29 +1980,7 @@ impl Build { format!("{}.exe", gnu) } } else if target.contains("android") { - let target = target - .replace("armv7neon", "arm") - .replace("armv7", "arm") - .replace("thumbv7neon", "arm") - .replace("thumbv7", "arm"); - let gnu_compiler = format!("{}-{}", target, gnu); - let clang_compiler = format!("{}-{}", target, clang); - // On Windows, the Android clang compiler is provided as a `.cmd` file instead - // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the - // `.cmd` is explicitly appended to the command name, so we do that here. - let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); - - // Check if gnu compiler is present - // if not, use clang - if Command::new(&gnu_compiler).output().is_ok() { - gnu_compiler - } else if host.contains("windows") - && Command::new(&clang_compiler_cmd).output().is_ok() - { - clang_compiler_cmd - } else { - clang_compiler - } + autodetect_android_compiler(&target, &host, gnu, clang) } else if target.contains("cloudabi") { format!("{}-{}", target, traditional) } else if target == "wasm32-wasi" @@ -2722,3 +2706,77 @@ fn command_add_output_file( cmd.arg("-o").arg(&dst); } } + +static NEW_STANDALONE_ANDROID_COMPILERS: [&str; 4] = [ + "aarch64-linux-android21-clang", + "armv7a-linux-androideabi16-clang", + "i686-linux-android16-clang", + "x86_64-linux-android21-clang", +]; + +fn defines_for_android_compiler(clang_path: &Path) -> Vec<&'static str> { + match NEW_STANDALONE_ANDROID_COMPILERS.iter().find(|x| { + let x: &OsStr = x.as_ref(); + x == clang_path.as_os_str() + }) { + Some(new_clang) => { + let mut ret = Vec::with_capacity(2); + ret.push("-DANDROID"); + if new_clang.contains("android21") { + ret.push("-D__ANDROID_API__=21"); + } else if new_clang.contains("android16") || new_clang.contains("androideabi16") { + ret.push("-D__ANDROID_API__=16"); + } + + ret + } + None => Vec::new(), + } +} + +fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { + let new_clang_key = match target { + "aarch64-linux-android" => Some("aarch64"), + "armv7-linux-androideabi" => Some("armv7a"), + "i686-linux-android" => Some("i686"), + "x86_64-linux-android" => Some("x86_64"), + _ => None, + }; + + let new_clang = new_clang_key + .map(|key| { + NEW_STANDALONE_ANDROID_COMPILERS + .iter() + .find(|x| x.starts_with(key)) + }) + .unwrap_or(None); + + if let Some(new_clang) = new_clang { + if Command::new(new_clang).output().is_ok() { + return (*new_clang).into(); + } + } + + let target = target + .replace("armv7neon", "arm") + .replace("armv7", "arm") + .replace("thumbv7neon", "arm") + .replace("thumbv7", "arm"); + let gnu_compiler = format!("{}-{}", target, gnu); + let clang_compiler = format!("{}-{}", target, clang); + + // On Windows, the Android clang compiler is provided as a `.cmd` file instead + // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the + // `.cmd` is explicitly appended to the command name, so we do that here. + let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); + + // Check if gnu compiler is present + // if not, use clang + if Command::new(&gnu_compiler).output().is_ok() { + gnu_compiler + } else if host.contains("windows") && Command::new(&clang_compiler_cmd).output().is_ok() { + clang_compiler_cmd + } else { + clang_compiler + } +}