1#!/bin/bash 2# 3# Copyright (C) 2008 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# Stop if something fails. 18set -e 19 20# Set default values for directories. 21if [ -d smali ]; then 22 HAS_SMALI=true 23else 24 HAS_SMALI=false 25fi 26 27# .j files in jasmin get compiled into classes.jar 28if [ -d jasmin ]; then 29 HAS_JASMIN=true 30else 31 HAS_JASMIN=false 32fi 33 34if [ -d src ]; then 35 HAS_SRC=true 36else 37 HAS_SRC=false 38fi 39 40# .java files in src-art get compiled with libcore on the bootclasspath 41if [ -d src-art ]; then 42 HAS_SRC_ART=true 43else 44 HAS_SRC_ART=false 45fi 46 47if [ -d src2 ]; then 48 HAS_SRC2=true 49else 50 HAS_SRC2=false 51fi 52 53if [ -d src-multidex ]; then 54 HAS_SRC_MULTIDEX=true 55else 56 HAS_SRC_MULTIDEX=false 57fi 58 59if [ -d smali-multidex ]; then 60 HAS_SMALI_MULTIDEX=true 61else 62 HAS_SMALI_MULTIDEX=false 63fi 64 65# .j files in jasmin-multidex get compiled into classes2.jar 66if [ -d jasmin-multidex ]; then 67 HAS_JASMIN_MULTIDEX=true 68else 69 HAS_JASMIN_MULTIDEX=false 70fi 71 72if [ -d src-ex ]; then 73 HAS_SRC_EX=true 74else 75 HAS_SRC_EX=false 76fi 77 78if [ -d src-dex2oat-unresolved ]; then 79 HAS_SRC_DEX2OAT_UNRESOLVED=true 80else 81 HAS_SRC_DEX2OAT_UNRESOLVED=false 82fi 83 84# DESUGAR=false run-test... will disable desugar. 85if [[ "$DESUGAR" == false ]]; then 86 USE_DESUGAR=false 87fi 88 89# Allow overriding ZIP_COMPRESSION_METHOD with e.g. 'store' 90ZIP_COMPRESSION_METHOD="deflate" 91# Align every ZIP file made by calling $ZIPALIGN command? 92WITH_ZIP_ALIGN=false 93ZIP_ALIGN_BYTES="-1" 94 95DX_FLAGS="--min-sdk-version=24" 96DX_VM_FLAGS="" 97EXPERIMENTAL="" 98 99BUILD_MODE="target" 100DEV_MODE="no" 101 102# The key for default arguments if no experimental things are enabled. 103DEFAULT_EXPERIMENT="no-experiment" 104 105# Setup experimental flag mappings in a bash associative array. 106declare -A JACK_EXPERIMENTAL_ARGS 107JACK_EXPERIMENTAL_ARGS["agents"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" 108JACK_EXPERIMENTAL_ARGS["default-methods"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" 109JACK_EXPERIMENTAL_ARGS["lambdas"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" 110JACK_EXPERIMENTAL_ARGS["method-handles"]="-D jack.java.source.version=1.7 -D jack.android.min-api-level=o-b1" 111JACK_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" 112 113declare -A SMALI_EXPERIMENTAL_ARGS 114SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api 24" 115SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api 26" 116SMALI_EXPERIMENTAL_ARGS["agents"]="--api 26" 117 118declare -A JAVAC_EXPERIMENTAL_ARGS 119JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" 120JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" 121JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" 122# We need to leave javac at default 1.7 so that dx will continue to work 123JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" 124JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" 125 126declare -A DX_EXPERIMENTAL_ARGS 127DX_EXPERIMENTAL_ARGS["method-handles"]="--min-sdk-version=26" 128 129while true; do 130 if [ "x$1" = "x--dx-option" ]; then 131 shift 132 option="$1" 133 DX_FLAGS="${DX_FLAGS} $option" 134 shift 135 elif [ "x$1" = "x--dx-vm-option" ]; then 136 shift 137 option="$1" 138 DX_VM_FLAGS="${DX_VM_FLAGS} $option" 139 shift 140 elif [ "x$1" = "x--jvm" ]; then 141 shift 142 elif [ "x$1" = "x--no-src" ]; then 143 HAS_SRC=false 144 shift 145 elif [ "x$1" = "x--no-src2" ]; then 146 HAS_SRC2=false 147 shift 148 elif [ "x$1" = "x--no-src-multidex" ]; then 149 HAS_SRC_MULTIDEX=false 150 shift 151 elif [ "x$1" = "x--no-smali-multidex" ]; then 152 HAS_SMALI_MULTIDEX=false 153 shift 154 elif [ "x$1" = "x--no-src-ex" ]; then 155 HAS_SRC_EX=false 156 shift 157 elif [ "x$1" = "x--no-smali" ]; then 158 HAS_SMALI=false 159 shift 160 elif [ "x$1" = "x--experimental" ]; then 161 shift 162 # We have a specific experimental configuration so don't use the default. 163 DEFAULT_EXPERIMENT="" 164 EXPERIMENTAL="${EXPERIMENTAL} $1" 165 shift 166 elif [ "x$1" = "x--zip-compression-method" ]; then 167 # Allow using different zip compression method, e.g. 'store' 168 shift 169 ZIP_COMPRESSION_METHOD="$1" 170 shift 171 elif [ "x$1" = "x--zip-align" ]; then 172 # Align ZIP entries to some # of bytes. 173 shift 174 WITH_ZIP_ALIGN=true 175 ZIP_ALIGN_BYTES="$1" 176 shift 177 elif [ "x$1" = "x--host" ]; then 178 BUILD_MODE="host" 179 shift 180 elif [ "x$1" = "x--target" ]; then 181 BUILD_MODE="target" 182 shift 183 elif [ "x$1" = "x--dev" ]; then 184 DEV_MODE="yes" 185 shift 186 elif expr "x$1" : "x--" >/dev/null 2>&1; then 187 echo "unknown $0 option: $1" 1>&2 188 exit 1 189 else 190 break 191 fi 192done 193 194# Be sure to get any default arguments if not doing any experiments. 195EXPERIMENTAL="${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}" 196 197if [ "${JACK_SERVER}" = "false" ]; then 198 # Run in single-threaded mode for the continuous buildbot. 199 JACK_ARGS="${JACK_ARGS} -D sched.runner=single-threaded" 200else 201 # Run with 4 threads to reduce memory footprint and thread contention. 202 JACK_ARGS="${JACK_ARGS} -D sched.runner=multi-threaded" 203 JACK_ARGS="${JACK_ARGS} -D sched.runner.thread.kind=fixed" 204 JACK_ARGS="${JACK_ARGS} -D sched.runner.thread.fixed.count=4" 205fi 206 207# Add args from the experimental mappings. 208for experiment in ${EXPERIMENTAL}; do 209 JACK_ARGS="${JACK_ARGS} ${JACK_EXPERIMENTAL_ARGS[${experiment}]}" 210 SMALI_ARGS="${SMALI_ARGS} ${SMALI_EXPERIMENTAL_ARGS[${experiment}]}" 211 JAVAC_ARGS="${JAVAC_ARGS} ${JAVAC_EXPERIMENTAL_ARGS[${experiment}]}" 212 DX_FLAGS="${DX_FLAGS} ${DX_EXPERIMENTAL_ARGS[${experiment}]}" 213done 214 215######################################### 216 217# Catch all commands to 'ZIP' and prepend extra flags. 218# Optionally, zipalign results to some alignment. 219function zip() { 220 local zip_target="$1" 221 local entry_src="$2" 222 shift 2 223 224 command zip --compression-method "$ZIP_COMPRESSION_METHOD" "$zip_target" "$entry_src" "$@" 225 226 if "$WITH_ZIP_ALIGN"; then 227 # zipalign does not operate in-place, so write results to a temp file. 228 local tmp_file="$(mktemp)" 229 "$ZIPALIGN" -f "$ZIP_ALIGN_BYTES" "$zip_target" "$tmp_file" 230 # replace original zip target with our temp file. 231 mv "$tmp_file" "$zip_target" 232 fi 233} 234 235function make_jasmin() { 236 local out_directory="$1" 237 shift 238 local jasmin_sources=("$@") 239 240 mkdir -p "$out_directory" 241 242 if [[ $DEV_MODE == yes ]]; then 243 echo ${JASMIN} -d "$out_directory" "${jasmin_sources[@]}" 244 ${JASMIN} -d "$out_directory" "${jasmin_sources[@]}" 245 else 246 ${JASMIN} -d "$out_directory" "${jasmin_sources[@]}" >/dev/null 247 fi 248} 249 250function desugar() { 251 local desugar_args=--mode=host 252 if [[ $BUILD_MODE == target ]]; then 253 desugar_args=--mode=target 254 fi 255 256 if [[ $DEV_MODE == yes ]]; then 257 desugar_args="$desugar_args --show-commands" 258 fi 259 260 "$DESUGAR" --core-only $desugar_args "$@" 261} 262 263# Like regular javac but includes libcore on the bootclasspath. 264function javac_with_bootclasspath { 265 local javac_args=--mode=host 266 if [[ $BUILD_MODE == target ]]; then 267 javac_args=--mode=target 268 fi 269 270 if [[ $DEV_MODE == yes ]]; then 271 javac_args="$javac_args --show-commands" 272 fi 273 274 "$ANDROID_BUILD_TOP/art/tools/javac-helper.sh" --core-only $javac_args "$@" 275} 276 277# Make a "dex" file given a directory of classes in $1. 278# Also calls desugar on the classes first to convert lambdas. 279function make_dex() { 280 local name="$1" 281 282 local dx_input 283 if [[ "$USE_DESUGAR" == "true" ]]; then 284 # Make a jar first so desugar doesn't need every .class file individually. 285 jar cf "$name.before-desugar.jar" -C "$name" . 286 287 dx_input="${name}.desugar.jar" 288 289 # Make desugared JAR. 290 desugar --input "$name.before-desugar.jar" --output "$dx_input" 291 else 292 dx_input="${name}" 293 fi 294 295 # Make dex file from desugared JAR. 296 ${DX} -JXmx256m ${DX_VM_FLAGS} --debug --dex --dump-to=${name}.lst --output=${name}.dex --dump-width=1000 ${DX_FLAGS} "${dx_input}" 297} 298 299# Merge all the dex files in $1..$N into $1. Skip non-existing files, but at least 1 file must exist. 300function make_dexmerge() { 301 # Dex file that acts as the destination. 302 local dst_file="$1" 303 304 # Dex files that act as the source. 305 local dex_files_to_merge=() 306 307 # Skip any non-existing files. 308 while [[ $# -gt 0 ]]; do 309 if [[ -e "$1" ]]; then 310 dex_files_to_merge+=("$1") 311 fi 312 shift 313 done 314 315 # Should have at least 1 dex_files_to_merge here, otherwise dxmerger will print the help. 316 ${DXMERGER} "$dst_file" "${dex_files_to_merge[@]}" 317} 318 319# Print the directory name only if it exists. 320function maybe_dir() { 321 local dirname="$1" 322 if [[ -d "$dirname" ]]; then 323 echo "$dirname" 324 fi 325} 326 327if [ -e classes.dex ]; then 328 zip $TEST_NAME.jar classes.dex 329 exit 0 330fi 331 332if [ ${HAS_SRC_DEX2OAT_UNRESOLVED} = "true" ]; then 333 mkdir classes 334 mkdir classes-ex 335 ${JAVAC} ${JAVAC_ARGS} -implicit:none -sourcepath src-dex2oat-unresolved -d classes `find src -name '*.java'` 336 ${JAVAC} ${JAVAC_ARGS} -implicit:none -sourcepath src -d classes-ex `find src-dex2oat-unresolved -name '*.java'` 337 if [ ${USE_JACK} = "true" ]; then 338 jar cf classes.jill.jar -C classes . 339 jar cf classes-ex.jill.jar -C classes-ex . 340 341 ${JACK} --import classes-ex.jill.jar --output-dex . 342 zip ${TEST_NAME}-ex.jar classes.dex 343 ${JACK} --import classes.jill.jar --output-dex . 344 else 345 if [ ${NEED_DEX} = "true" ]; then 346 make_dex classes-ex 347 mv classes-ex.dex classes.dex # rename it so it shows up as "classes.dex" in the zip file. 348 zip ${TEST_NAME}-ex.jar classes.dex 349 make_dex classes 350 fi 351 fi 352else 353 if [ ${USE_JACK} = "true" ]; then 354 # Jack toolchain 355 if [[ "$HAS_SRC" == true || "$HAS_SRC_ART" == true ]]; then 356 if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then 357 # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning 358 # when creating the output .dex file. 359 ${JACK} ${JACK_ARGS} --output-jack src.jack $(maybe_dir src) src-multidex $(maybe_dir src-art) 360 jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex" 361 jack_extra_args="${jack_extra_args} -D jack.preprocessor=true" 362 jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp" 363 else 364 ${JACK} ${JACK_ARGS} --output-jack src.jack $(maybe_dir src) $(maybe_dir src-art) 365 fi 366 jack_extra_args="${jack_extra_args} --import src.jack" 367 fi 368 369 if [ "${HAS_SRC2}" = "true" ]; then 370 ${JACK} ${JACK_ARGS} --output-jack src2.jack src2 371 # In case of duplicate classes, we want to take into account the classes from src2. Therefore 372 # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file. 373 jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first" 374 jack_extra_args="--import src2.jack ${jack_extra_args}" 375 fi 376 377 # Compile jack files into a DEX file. 378 if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ] || [ "${HAS_SRC_ART}" = "true" ]; then 379 ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex . 380 fi 381 else 382 # Legacy toolchain with javac+dx 383 if [ "${HAS_SRC}" = "true" ]; then 384 mkdir classes 385 ${JAVAC} ${JAVAC_ARGS} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'` 386 fi 387 388 if [ "${HAS_SRC_ART}" = "true" ]; then 389 mkdir -p classes 390 javac_with_bootclasspath ${JAVAC_ARGS} -implicit:none -classpath src-multidex -d classes `find src-art -name '*.java'` 391 fi 392 393 if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then 394 mkdir classes2 395 ${JAVAC} ${JAVAC_ARGS} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'` 396 if [ ${NEED_DEX} = "true" ]; then 397 make_dex classes2 398 fi 399 fi 400 401 if [ "${HAS_SRC2}" = "true" ]; then 402 mkdir -p classes 403 ${JAVAC} ${JAVAC_ARGS} -d classes `find src2 -name '*.java'` 404 fi 405 406 if [[ "${HAS_SRC}" == "true" || "${HAS_SRC2}" == "true" || "${HAS_SRC_ART}" == "true" ]]; then 407 if [ ${NEED_DEX} = "true" ]; then 408 make_dex classes 409 fi 410 fi 411 fi 412fi 413 414if [[ "${HAS_JASMIN}" == true ]]; then 415 # Compile Jasmin classes as if they were part of the classes.dex file. 416 make_jasmin jasmin_classes $(find 'jasmin' -name '*.j') 417 if [[ "${NEED_DEX}" == "true" ]]; then 418 # Disable desugar because it won't handle intentional linkage errors. 419 USE_DESUGAR=false make_dex jasmin_classes 420 make_dexmerge classes.dex jasmin_classes.dex 421 else 422 # Move jasmin classes into classes directory so that they are picked up with -cp classes. 423 mkdir -p classes 424 mv jasmin_classes/* classes 425 fi 426fi 427 428if [ "${HAS_SMALI}" = "true" -a ${NEED_DEX} = "true" ]; then 429 # Compile Smali classes 430 ${SMALI} -JXmx512m assemble ${SMALI_ARGS} --output smali_classes.dex `find smali -name '*.smali'` 431 432 # Merge smali files into classes.dex, this takes priority over any jasmin files. 433 make_dexmerge classes.dex smali_classes.dex 434fi 435 436# Compile Jasmin classes in jasmin-multidex as if they were part of the classes2.jar 437if [[ "$HAS_JASMIN_MULTIDEX" == true ]]; then 438 make_jasmin jasmin_classes2 $(find 'jasmin-multidex' -name '*.j') 439 440 if [[ "${NEED_DEX}" == "true" ]]; then 441 # Disable desugar because it won't handle intentional linkage errors. 442 USE_DESUGAR=false make_dex jasmin_classes2 443 444 # Merge jasmin_classes2.dex into classes2.dex 445 make_dexmerge classes2.dex jasmin_classes2.dex 446 else 447 # Move jasmin classes into classes2 directory so that they are picked up with -cp classes2. 448 mkdir -p classes2 449 mv jasmin_classes2/* classes2 450 fi 451fi 452 453if [ "${HAS_SMALI_MULTIDEX}" = "true" -a ${NEED_DEX} = "true" ]; then 454 # Compile Smali classes 455 ${SMALI} -JXmx512m assemble ${SMALI_ARGS} --output smali_classes2.dex `find smali-multidex -name '*.smali'` 456 457 # Merge smali_classes2.dex into classes2.dex 458 make_dexmerge classes2.dex smali_classes2.dex 459fi 460 461 462if [ ${HAS_SRC_EX} = "true" ]; then 463 if [ ${USE_JACK} = "true" ]; then 464 # Rename previous "classes.dex" so it is not overwritten. 465 mv classes.dex classes-1.dex 466 #TODO find another way to append src.jack to the jack classpath 467 ${JACK}:src.jack ${JACK_ARGS} --output-dex . src-ex 468 zip $TEST_NAME-ex.jar classes.dex 469 # Restore previous "classes.dex" so it can be zipped. 470 mv classes-1.dex classes.dex 471 else 472 # Build src-ex into classes-ex. 473 # Includes 'src', 'src-art' source when compiling classes-ex, but exclude their .class files. 474 if [[ "${HAS_SRC}" == "true" ]]; then 475 mkdir -p classes-tmp-for-ex 476 ${JAVAC} ${JAVAC_ARGS} -d classes-tmp-for-ex `find src -name '*.java'` 477 src_tmp_for_ex="-cp classes-tmp-for-ex" 478 fi 479 if [[ "${HAS_SRC_ART}" == "true" ]]; then 480 mkdir -p classes-tmp-for-ex 481 javac_with_bootclasspath ${JAVAC_ARGS} -d classes-tmp-for-ex `find src-art -name '*.java'` 482 src_tmp_for_ex="-cp classes-tmp-for-ex" 483 fi 484 mkdir classes-ex 485 ${JAVAC} ${JAVAC_ARGS} -d classes-ex $src_tmp_for_ex `find src-ex -name '*.java'` 486 if [ ${NEED_DEX} = "true" ]; then 487 make_dex classes-ex 488 489 # quick shuffle so that the stored name is "classes.dex" 490 mv classes.dex classes-1.dex 491 mv classes-ex.dex classes.dex 492 zip $TEST_NAME-ex.jar classes.dex 493 mv classes.dex classes-ex.dex 494 mv classes-1.dex classes.dex 495 fi 496 fi 497fi 498 499# Create a single dex jar with two dex files for multidex. 500if [ ${NEED_DEX} = "true" ]; then 501 if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_JASMIN_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then 502 zip $TEST_NAME.jar classes.dex classes2.dex 503 else 504 zip $TEST_NAME.jar classes.dex 505 fi 506fi 507