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