1*e0c4386eSCy Schubert#### Android... 2*e0c4386eSCy Schubert# 3*e0c4386eSCy Schubert# See NOTES-Android.md for details, and don't miss platform-specific 4*e0c4386eSCy Schubert# comments below... 5*e0c4386eSCy Schubert 6*e0c4386eSCy Schubert{ 7*e0c4386eSCy Schubert use File::Spec::Functions; 8*e0c4386eSCy Schubert 9*e0c4386eSCy Schubert my $android_ndk = {}; 10*e0c4386eSCy Schubert my %triplet = ( 11*e0c4386eSCy Schubert arm => "arm-linux-androideabi", 12*e0c4386eSCy Schubert arm64 => "aarch64-linux-android", 13*e0c4386eSCy Schubert mips => "mipsel-linux-android", 14*e0c4386eSCy Schubert mips64 => "mips64el-linux-android", 15*e0c4386eSCy Schubert x86 => "i686-linux-android", 16*e0c4386eSCy Schubert x86_64 => "x86_64-linux-android", 17*e0c4386eSCy Schubert ); 18*e0c4386eSCy Schubert 19*e0c4386eSCy Schubert sub android_ndk { 20*e0c4386eSCy Schubert unless (%$android_ndk) { 21*e0c4386eSCy Schubert if ($now_printing =~ m|^android|) { 22*e0c4386eSCy Schubert return $android_ndk = { bn_ops => "BN_AUTO" }; 23*e0c4386eSCy Schubert } 24*e0c4386eSCy Schubert 25*e0c4386eSCy Schubert my $ndk_var; 26*e0c4386eSCy Schubert my $ndk; 27*e0c4386eSCy Schubert foreach (qw(ANDROID_NDK_ROOT ANDROID_NDK)) { 28*e0c4386eSCy Schubert $ndk_var = $_; 29*e0c4386eSCy Schubert $ndk = $ENV{$ndk_var}; 30*e0c4386eSCy Schubert last if defined $ndk; 31*e0c4386eSCy Schubert } 32*e0c4386eSCy Schubert die "\$ANDROID_NDK_ROOT is not defined" if (!$ndk); 33*e0c4386eSCy Schubert my $is_standalone_toolchain = -f "$ndk/AndroidVersion.txt"; 34*e0c4386eSCy Schubert my $ndk_src_props = "$ndk/source.properties"; 35*e0c4386eSCy Schubert my $is_ndk = -f $ndk_src_props; 36*e0c4386eSCy Schubert if ($is_ndk == $is_standalone_toolchain) { 37*e0c4386eSCy Schubert die "\$ANDROID_NDK_ROOT=$ndk is invalid"; 38*e0c4386eSCy Schubert } 39*e0c4386eSCy Schubert $ndk = canonpath($ndk); 40*e0c4386eSCy Schubert 41*e0c4386eSCy Schubert my $ndkver = undef; 42*e0c4386eSCy Schubert 43*e0c4386eSCy Schubert if (open my $fh, "<$ndk_src_props") { 44*e0c4386eSCy Schubert local $_; 45*e0c4386eSCy Schubert while(<$fh>) { 46*e0c4386eSCy Schubert if (m|Pkg\.Revision\s*=\s*([0-9]+)|) { 47*e0c4386eSCy Schubert $ndkver = $1; 48*e0c4386eSCy Schubert last; 49*e0c4386eSCy Schubert } 50*e0c4386eSCy Schubert } 51*e0c4386eSCy Schubert close $fh; 52*e0c4386eSCy Schubert } 53*e0c4386eSCy Schubert 54*e0c4386eSCy Schubert my ($sysroot, $api, $arch); 55*e0c4386eSCy Schubert 56*e0c4386eSCy Schubert $config{target} =~ m|[^-]+-([^-]+)$|; # split on dash 57*e0c4386eSCy Schubert $arch = $1; 58*e0c4386eSCy Schubert 59*e0c4386eSCy Schubert if ($sysroot = $ENV{CROSS_SYSROOT}) { 60*e0c4386eSCy Schubert $sysroot =~ m|/android-([0-9]+)/arch-(\w+)/?$|; 61*e0c4386eSCy Schubert ($api, $arch) = ($1, $2); 62*e0c4386eSCy Schubert } elsif ($is_standalone_toolchain) { 63*e0c4386eSCy Schubert $sysroot = "$ndk/sysroot"; 64*e0c4386eSCy Schubert } else { 65*e0c4386eSCy Schubert $api = "*"; 66*e0c4386eSCy Schubert 67*e0c4386eSCy Schubert # see if user passed -D__ANDROID_API__=N 68*e0c4386eSCy Schubert foreach (@{$useradd{CPPDEFINES}}, @{$user{CPPFLAGS}}) { 69*e0c4386eSCy Schubert if (m|__ANDROID_API__=([0-9]+)|) { 70*e0c4386eSCy Schubert $api = $1; 71*e0c4386eSCy Schubert last; 72*e0c4386eSCy Schubert } 73*e0c4386eSCy Schubert } 74*e0c4386eSCy Schubert 75*e0c4386eSCy Schubert if (-d "$ndk/platforms") { 76*e0c4386eSCy Schubert # list available platforms (numerically) 77*e0c4386eSCy Schubert my @platforms = sort { $a =~ m/-([0-9]+)$/; my $aa = $1; 78*e0c4386eSCy Schubert $b =~ m/-([0-9]+)$/; $aa <=> $1; 79*e0c4386eSCy Schubert } glob("$ndk/platforms/android-$api"); 80*e0c4386eSCy Schubert die "no $ndk/platforms/android-$api" if ($#platforms < 0); 81*e0c4386eSCy Schubert 82*e0c4386eSCy Schubert $sysroot = "@platforms[$#platforms]/arch-$arch"; 83*e0c4386eSCy Schubert $sysroot =~ m|/android-([0-9]+)/arch-$arch|; 84*e0c4386eSCy Schubert $api = $1; 85*e0c4386eSCy Schubert } elsif ($api eq "*") { 86*e0c4386eSCy Schubert # r22 Removed platforms dir, use this JSON file 87*e0c4386eSCy Schubert my $path = "$ndk/meta/platforms.json"; 88*e0c4386eSCy Schubert open my $fh, $path or die "Could not open '$path' $!"; 89*e0c4386eSCy Schubert while (<$fh>) { 90*e0c4386eSCy Schubert if (/"max": (\d+),/) { 91*e0c4386eSCy Schubert $api = $1; 92*e0c4386eSCy Schubert last; 93*e0c4386eSCy Schubert } 94*e0c4386eSCy Schubert } 95*e0c4386eSCy Schubert close $fh; 96*e0c4386eSCy Schubert } 97*e0c4386eSCy Schubert die "Could not get default API Level" if ($api eq "*"); 98*e0c4386eSCy Schubert } 99*e0c4386eSCy Schubert die "no sysroot=$sysroot" if (length $sysroot && !-d $sysroot); 100*e0c4386eSCy Schubert 101*e0c4386eSCy Schubert my $triarch = $triplet{$arch}; 102*e0c4386eSCy Schubert my $cflags; 103*e0c4386eSCy Schubert my $cppflags; 104*e0c4386eSCy Schubert 105*e0c4386eSCy Schubert # see if there is NDK clang on $PATH, "universal" or "standalone" 106*e0c4386eSCy Schubert if (which("clang") =~ m|^$ndk/.*/prebuilt/([^/]+)/|) { 107*e0c4386eSCy Schubert my $host=$1; 108*e0c4386eSCy Schubert # harmonize with gcc default 109*e0c4386eSCy Schubert my $arm = $ndkver > 16 ? "armv7a" : "armv5te"; 110*e0c4386eSCy Schubert (my $tridefault = $triarch) =~ s/^arm-/$arm-/; 111*e0c4386eSCy Schubert (my $tritools = $triarch) =~ s/(?:x|i6)86(_64)?-.*/x86$1/; 112*e0c4386eSCy Schubert if (length $sysroot) { 113*e0c4386eSCy Schubert $cflags .= " -target $tridefault " 114*e0c4386eSCy Schubert . "-gcc-toolchain \$($ndk_var)/toolchains" 115*e0c4386eSCy Schubert . "/$tritools-4.9/prebuilt/$host"; 116*e0c4386eSCy Schubert $user{CC} = "clang" if ($user{CC} !~ m|clang|); 117*e0c4386eSCy Schubert } else { 118*e0c4386eSCy Schubert $user{CC} = "$tridefault$api-clang"; 119*e0c4386eSCy Schubert } 120*e0c4386eSCy Schubert $user{CROSS_COMPILE} = undef; 121*e0c4386eSCy Schubert if (which("llvm-ar") =~ m|^$ndk/.*/prebuilt/([^/]+)/|) { 122*e0c4386eSCy Schubert $user{AR} = "llvm-ar"; 123*e0c4386eSCy Schubert $user{ARFLAGS} = [ "rs" ]; 124*e0c4386eSCy Schubert $user{RANLIB} = ":"; 125*e0c4386eSCy Schubert } 126*e0c4386eSCy Schubert } elsif ($is_standalone_toolchain) { 127*e0c4386eSCy Schubert my $cc = $user{CC} // "clang"; 128*e0c4386eSCy Schubert # One can probably argue that both clang and gcc should be 129*e0c4386eSCy Schubert # probed, but support for "standalone toolchain" was added 130*e0c4386eSCy Schubert # *after* announcement that gcc is being phased out, so 131*e0c4386eSCy Schubert # favouring clang is considered adequate. Those who insist 132*e0c4386eSCy Schubert # have option to enforce test for gcc with CC=gcc. 133*e0c4386eSCy Schubert if (which("$triarch-$cc") !~ m|^$ndk|) { 134*e0c4386eSCy Schubert die "no NDK $triarch-$cc on \$PATH"; 135*e0c4386eSCy Schubert } 136*e0c4386eSCy Schubert $user{CC} = $cc; 137*e0c4386eSCy Schubert $user{CROSS_COMPILE} = "$triarch-"; 138*e0c4386eSCy Schubert } elsif ($user{CC} eq "clang") { 139*e0c4386eSCy Schubert die "no NDK clang on \$PATH"; 140*e0c4386eSCy Schubert } else { 141*e0c4386eSCy Schubert if (which("$triarch-gcc") !~ m|^$ndk/.*/prebuilt/([^/]+)/|) { 142*e0c4386eSCy Schubert die "no NDK $triarch-gcc on \$PATH"; 143*e0c4386eSCy Schubert } 144*e0c4386eSCy Schubert $cflags .= " -mandroid"; 145*e0c4386eSCy Schubert $user{CROSS_COMPILE} = "$triarch-"; 146*e0c4386eSCy Schubert } 147*e0c4386eSCy Schubert 148*e0c4386eSCy Schubert if (length $sysroot) { 149*e0c4386eSCy Schubert if (!-d "$sysroot/usr/include") { 150*e0c4386eSCy Schubert my $incroot = "$ndk/sysroot/usr/include"; 151*e0c4386eSCy Schubert die "no $incroot" if (!-d $incroot); 152*e0c4386eSCy Schubert die "no $incroot/$triarch" if (!-d "$incroot/$triarch"); 153*e0c4386eSCy Schubert $incroot =~ s|^$ndk/||; 154*e0c4386eSCy Schubert $cppflags = "-D__ANDROID_API__=$api"; 155*e0c4386eSCy Schubert $cppflags .= " -isystem \$($ndk_var)/$incroot/$triarch"; 156*e0c4386eSCy Schubert $cppflags .= " -isystem \$($ndk_var)/$incroot"; 157*e0c4386eSCy Schubert } 158*e0c4386eSCy Schubert $sysroot =~ s|^$ndk/||; 159*e0c4386eSCy Schubert $sysroot = " --sysroot=\$($ndk_var)/$sysroot"; 160*e0c4386eSCy Schubert } 161*e0c4386eSCy Schubert $android_ndk = { 162*e0c4386eSCy Schubert cflags => $cflags . $sysroot, 163*e0c4386eSCy Schubert cppflags => $cppflags, 164*e0c4386eSCy Schubert bn_ops => $arch =~ m/64$/ ? "SIXTY_FOUR_BIT_LONG" 165*e0c4386eSCy Schubert : "BN_LLONG", 166*e0c4386eSCy Schubert }; 167*e0c4386eSCy Schubert } 168*e0c4386eSCy Schubert 169*e0c4386eSCy Schubert return $android_ndk; 170*e0c4386eSCy Schubert } 171*e0c4386eSCy Schubert} 172*e0c4386eSCy Schubert 173*e0c4386eSCy Schubertmy %targets = ( 174*e0c4386eSCy Schubert "android" => { 175*e0c4386eSCy Schubert inherit_from => [ "linux-generic32" ], 176*e0c4386eSCy Schubert template => 1, 177*e0c4386eSCy Schubert ################################################################ 178*e0c4386eSCy Schubert # Special note about -pie. The underlying reason is that 179*e0c4386eSCy Schubert # Lollipop refuses to run non-PIE. But what about older systems 180*e0c4386eSCy Schubert # and NDKs? -fPIC was never problem, so the only concern is -pie. 181*e0c4386eSCy Schubert # Older toolchains, e.g. r4, appear to handle it and binaries 182*e0c4386eSCy Schubert # turn out mostly functional. "Mostly" means that oldest 183*e0c4386eSCy Schubert # Androids, such as Froyo, fail to handle executable, but newer 184*e0c4386eSCy Schubert # systems are perfectly capable of executing binaries targeting 185*e0c4386eSCy Schubert # Froyo. Keep in mind that in the nutshell Android builds are 186*e0c4386eSCy Schubert # about JNI, i.e. shared libraries, not applications. 187*e0c4386eSCy Schubert cflags => add(sub { android_ndk()->{cflags} }), 188*e0c4386eSCy Schubert cppflags => add(sub { android_ndk()->{cppflags} }), 189*e0c4386eSCy Schubert cxxflags => add(sub { android_ndk()->{cflags} }), 190*e0c4386eSCy Schubert bn_ops => sub { android_ndk()->{bn_ops} }, 191*e0c4386eSCy Schubert bin_cflags => "-fPIE", 192*e0c4386eSCy Schubert bin_lflags => "-pie", 193*e0c4386eSCy Schubert enable => [ ], 194*e0c4386eSCy Schubert shared_extension => ".so", 195*e0c4386eSCy Schubert }, 196*e0c4386eSCy Schubert "android-arm" => { 197*e0c4386eSCy Schubert ################################################################ 198*e0c4386eSCy Schubert # Contemporary Android applications can provide multiple JNI 199*e0c4386eSCy Schubert # providers in .apk, targeting multiple architectures. Among 200*e0c4386eSCy Schubert # them there is "place" for two ARM flavours: generic eabi and 201*e0c4386eSCy Schubert # armv7-a/hard-float. However, it should be noted that OpenSSL's 202*e0c4386eSCy Schubert # ability to engage NEON is not constrained by ABI choice, nor 203*e0c4386eSCy Schubert # is your ability to call OpenSSL from your application code 204*e0c4386eSCy Schubert # compiled with floating-point ABI other than default 'soft'. 205*e0c4386eSCy Schubert # (Latter thanks to __attribute__((pcs("aapcs"))) declaration.) 206*e0c4386eSCy Schubert # This means that choice of ARM libraries you provide in .apk 207*e0c4386eSCy Schubert # is driven by application needs. For example if application 208*e0c4386eSCy Schubert # itself benefits from NEON or is floating-point intensive, then 209*e0c4386eSCy Schubert # it might be appropriate to provide both libraries. Otherwise 210*e0c4386eSCy Schubert # just generic eabi would do. But in latter case it would be 211*e0c4386eSCy Schubert # appropriate to 212*e0c4386eSCy Schubert # 213*e0c4386eSCy Schubert # ./Configure android-arm -D__ARM_MAX_ARCH__=8 214*e0c4386eSCy Schubert # 215*e0c4386eSCy Schubert # in order to build "universal" binary and allow OpenSSL take 216*e0c4386eSCy Schubert # advantage of NEON when it's available. 217*e0c4386eSCy Schubert # 218*e0c4386eSCy Schubert # Keep in mind that (just like with linux-armv4) we rely on 219*e0c4386eSCy Schubert # compiler defaults, which is not necessarily what you had 220*e0c4386eSCy Schubert # in mind, in which case you would have to pass additional 221*e0c4386eSCy Schubert # -march and/or -mfloat-abi flags. NDK defaults to armv5te. 222*e0c4386eSCy Schubert # Newer NDK versions reportedly require additional -latomic. 223*e0c4386eSCy Schubert # 224*e0c4386eSCy Schubert inherit_from => [ "android" ], 225*e0c4386eSCy Schubert bn_ops => add("RC4_CHAR"), 226*e0c4386eSCy Schubert asm_arch => 'armv4', 227*e0c4386eSCy Schubert perlasm_scheme => "void", 228*e0c4386eSCy Schubert }, 229*e0c4386eSCy Schubert "android-arm64" => { 230*e0c4386eSCy Schubert inherit_from => [ "android" ], 231*e0c4386eSCy Schubert bn_ops => add("RC4_CHAR"), 232*e0c4386eSCy Schubert asm_arch => 'aarch64', 233*e0c4386eSCy Schubert perlasm_scheme => "linux64", 234*e0c4386eSCy Schubert }, 235*e0c4386eSCy Schubert 236*e0c4386eSCy Schubert "android-mips" => { 237*e0c4386eSCy Schubert inherit_from => [ "android" ], 238*e0c4386eSCy Schubert bn_ops => add("RC4_CHAR"), 239*e0c4386eSCy Schubert asm_arch => 'mips32', 240*e0c4386eSCy Schubert perlasm_scheme => "o32", 241*e0c4386eSCy Schubert }, 242*e0c4386eSCy Schubert "android-mips64" => { 243*e0c4386eSCy Schubert ################################################################ 244*e0c4386eSCy Schubert # You are more than likely have to specify target processor 245*e0c4386eSCy Schubert # on ./Configure command line. Trouble is that toolchain's 246*e0c4386eSCy Schubert # default is MIPS64r6 (at least in r10d), but there are no 247*e0c4386eSCy Schubert # such processors around (or they are too rare to spot one). 248*e0c4386eSCy Schubert # Actual problem is that MIPS64r6 is binary incompatible 249*e0c4386eSCy Schubert # with previous MIPS ISA versions, in sense that unlike 250*e0c4386eSCy Schubert # prior versions original MIPS binary code will fail. 251*e0c4386eSCy Schubert # 252*e0c4386eSCy Schubert inherit_from => [ "android" ], 253*e0c4386eSCy Schubert bn_ops => add("RC4_CHAR"), 254*e0c4386eSCy Schubert asm_arch => 'mips64', 255*e0c4386eSCy Schubert perlasm_scheme => "64", 256*e0c4386eSCy Schubert }, 257*e0c4386eSCy Schubert 258*e0c4386eSCy Schubert "android-x86" => { 259*e0c4386eSCy Schubert inherit_from => [ "android" ], 260*e0c4386eSCy Schubert CFLAGS => add(picker(release => "-fomit-frame-pointer")), 261*e0c4386eSCy Schubert bn_ops => add("RC4_INT"), 262*e0c4386eSCy Schubert asm_arch => 'x86', 263*e0c4386eSCy Schubert perlasm_scheme => "android", 264*e0c4386eSCy Schubert ex_libs => add(threads("-latomic")), 265*e0c4386eSCy Schubert }, 266*e0c4386eSCy Schubert "android-x86_64" => { 267*e0c4386eSCy Schubert inherit_from => [ "android" ], 268*e0c4386eSCy Schubert bn_ops => add("RC4_INT"), 269*e0c4386eSCy Schubert asm_arch => 'x86_64', 270*e0c4386eSCy Schubert perlasm_scheme => "elf", 271*e0c4386eSCy Schubert }, 272*e0c4386eSCy Schubert 273*e0c4386eSCy Schubert #################################################################### 274*e0c4386eSCy Schubert # Backward compatible targets, (might) require $CROSS_SYSROOT 275*e0c4386eSCy Schubert # 276*e0c4386eSCy Schubert "android-armeabi" => { 277*e0c4386eSCy Schubert inherit_from => [ "android-arm" ], 278*e0c4386eSCy Schubert }, 279*e0c4386eSCy Schubert "android64" => { 280*e0c4386eSCy Schubert inherit_from => [ "android" ], 281*e0c4386eSCy Schubert }, 282*e0c4386eSCy Schubert "android64-aarch64" => { 283*e0c4386eSCy Schubert inherit_from => [ "android-arm64" ], 284*e0c4386eSCy Schubert }, 285*e0c4386eSCy Schubert "android64-x86_64" => { 286*e0c4386eSCy Schubert inherit_from => [ "android-x86_64" ], 287*e0c4386eSCy Schubert }, 288*e0c4386eSCy Schubert "android64-mips64" => { 289*e0c4386eSCy Schubert inherit_from => [ "android-mips64" ], 290*e0c4386eSCy Schubert }, 291*e0c4386eSCy Schubert); 292