1#!/bin/sh 2# 3 4set -e 5export LANG=C 6export LC_ALL=C 7 8PROGDIR=$(dirname "$0") 9PROGNAME=$(basename "$0") 10 11panic () { 12 echo "ERROR: $@" 13 exit 1 14} 15 16VERBOSE=1 17 18# Dump message is $VERBOSE >= $1 19# $1+: message. 20dump_n () { 21 local LOG_LEVEL=$1 22 shift 23 if [ "$VERBOSE" -ge "$LOG_LEVEL" ]; then 24 printf "%s\n" "$@" 25 fi 26} 27 28# Dump a message unless --quiet is used. 29# $1+: message. 30dump () { 31 dump_n 1 "$@" 32} 33 34# Dump a message if --verbose is used only. 35# $1+: message. 36log () { 37 dump_n 2 "$@" 38} 39 40# Run a command silently, unless --verbose or '--verbose --verbose' 41# is used. 42# $1+: Command 43# Return: command status. 44run () { 45 log "COMMAND: $*" 46 case $VERBOSE in 47 0) 48 "$@" >/dev/null 2>&1 || return $? 49 ;; 50 1) 51 "$@" >/dev/null || return $? 52 ;; 53 *) 54 "$@" || return $? 55 ;; 56 esac 57} 58 59# $1: string 60# Out: input string, with capital letters replaced by small ones. 61tolower () { 62 echo "$1" | tr '[A-Z]' '[a-z]' 63} 64 65# Return value of a given variable. 66# $1: Variable name 67var_value () { 68 eval printf \"%s\" \"\$$1\" 69} 70 71# Remove some items from a list 72# $1: input space-separated list 73# $2: space-separated list of items to remove from 1 74# Out: items of $1 without items of $2 75filter_out () { 76 local TMP=$(mktemp) 77 local RESULT 78 printf "" > $TMP 79 echo "$2" | tr ' ' '\n' > $TMP 80 RESULT=$(echo "$1" | tr ' ' '\n' | fgrep -x -v -f $TMP | tr '\n' ' ') 81 rm -f $TMP 82 echo "$RESULT" 83} 84 85src_to_obj () { 86 case $1 in 87 *.c) 88 echo ${1%%.c}.o 89 ;; 90 *.S) 91 echo ${1%%.S}.o 92 ;; 93 *) 94 echo $1 95 ;; 96 esac 97} 98 99# Determine host operating system. 100HOST_OS=$(uname -s) 101case $HOST_OS in 102 Linux) 103 HOST_OS=linux 104 ;; 105 Darwin) 106 HOST_OS=darwin 107 ;; 108esac 109 110# Determine host architecture 111HOST_ARCH=$(uname -m) 112case $HOST_ARCH in 113 i?86) 114 HOST_ARCH=x86 115 ;; 116esac 117 118ANDROID_HOST_TAG=$HOST_OS-$HOST_ARCH 119 120case $ANDROID_HOST_TAG in 121 linux-x86_64|darwin-x86-64) 122 ANDROID_HOST_TAG=$HOST_OS-x86 123 ;; 124 *) 125 panic "Sorry, this script can only run on 64-bit Linux or Darwin" 126esac 127 128# Determine number of cores 129case $HOST_OS in 130 linux) 131 NUM_CORES=$(grep -c "processor" /proc/cpuinfo) 132 ;; 133 darwin) 134 NUM_CORES=$(sysctl -n hw.ncpu) 135 ;; 136 *) 137 NUM_CORES=1 138 ;; 139esac 140 141# The list of supported Android target architectures. 142 143# NOTE: x86_64 is not ready yet, while the toolchain is in 144# prebuilts/ it doesn't have a sysroot which means it requires 145# a platform build to get Bionic and stuff. 146ANDROID_ARCHS="arm arm64 x86 x86_64 mips" 147 148BUILD_TYPES= 149for ARCH in $ANDROID_ARCHS; do 150 BUILD_TYPES="$BUILD_TYPES android-$ARCH" 151done 152ANDROID_BUILD_TYPES=$BUILD_TYPES 153 154HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64" 155HOST_BUILD_TYPES="$HOST_BUILD_TYPES $HOST_OS-x86_64" 156 157BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 158 159# Parse command-line 160DO_HELP= 161SRC_DIR=$(cd $PROGDIR && pwd) 162OUT_DIR=out 163BUILD_DIR= 164BUILD_TYPES= 165NUM_JOBS=$NUM_CORES 166ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd) 167for OPT; do 168 case $OPT in 169 --help|-h|-?) 170 DO_HELP=true 171 ;; 172 --build-dir=*) 173 BUILD_DIR=${OPT##--build-dir=} 174 ;; 175 --verbose) 176 VERBOSE=$(( $VERBOSE + 1 )) 177 ;; 178 --jobs=*) 179 NUM_JOBS=${OPT##--jobs=} 180 ;; 181 --quiet) 182 VERBOSE=$(( $VERBOSE - 1 )) 183 ;; 184 -j*) 185 NUM_JOBS=${OPT##-j} 186 ;; 187 -*) 188 panic "Unknown option '$OPT', see --help for details." 189 ;; 190 *) 191 BUILD_TYPES="$BUILD_TYPES $OPT" 192 ;; 193 esac 194done 195 196# Print help when needed. 197if [ "$DO_HELP" ]; then 198 echo \ 199"Usage: $PROGNAME [options] [<build-type> ...] 200 201This script is used to ensure that all OpenSSL build variants compile 202properly. It can be used after modifying external/openssl/openssl.config 203and re-running import_openssl.sh to check that any changes didn't break 204the build. 205 206A <build-type> is a description of a given build of the library and its 207program. Its format is: 208 209 <compiler>-<system>-<arch> 210 211Where: <compiler> is either 'gcc' or 'clang'. 212 <system> is 'android', 'linux' or 'darwin'. 213 <arch> is 'arm', 'x86' or 'mips'. 214 215By default, it rebuilds the sources for the following build types: 216" 217 for BUILD_TYPE in $BUILD_TYPES; do 218 echo " $BUILD_TYPE" 219 done 220 221 echo \ 222"However, you can pass custom values on the command-line instead. 223 224This scripts generates a custom Makefile in a temporary directory, then 225launches 'make' in it to build all binaries in parallel. In case of 226problem, you can use the --build-dir=<path> option to specify a custom 227build-directory, which will _not_ be removed when the script exits. 228 229For example, to better see why a build fails: 230 231 ./$PROGNAME --build-dir=/tmp/mydir 232 make -C /tmp/mydir V=1 233 234Valid options: 235 236 --help|-h|-? Print this message. 237 --build-dir=<path> Specify build directory. 238 --jobs=<count> Run <count> parallel build jobs [$NUM_JOBS]. 239 -j<count> Same as --jobs=<count>. 240 --verbose Increase verbosity. 241 --quiet Decrease verbosity. 242" 243 exit 0 244fi 245 246log "Host OS: $HOST_OS" 247log "Host arch: $HOST_ARCH" 248log "Host CPU count: $NUM_CORES" 249 250if [ -z "$BUILD_TYPES" ]; then 251 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 252fi 253log "Build types: $BUILD_TYPES" 254 255if [ -z "$BUILD_DIR" ]; then 256 # Create a temporary directory, ensure it gets destroyed properly 257 # when the script exits. 258 BUILD_DIR=$(mktemp -d) 259 clean_build_dir () { 260 log "Cleaning up temporary directory: $BUILD_DIR" 261 rm -rf "$BUILD_DIR" 262 exit $1 263 } 264 trap "clean_build_dir 0" EXIT 265 trap "clean_build_dir \$?" INT HUP QUIT TERM 266 log "Using temporary build directory: $BUILD_DIR" 267else 268 log "Using user build directory: $BUILD_DIR" 269fi 270 271mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/* 272 273MAKEFILE=$BUILD_DIR/GNUmakefile 274 275# Return source files for a given module and architecture. 276# $1: module prefix (e.g. CRYPTO) 277# $2: build arch. 278get_module_src_files_for_arch () { 279 local prefix=$1 280 local arch=$2 281 local src_files="$(var_value OPENSSL_${prefix}_SOURCES)" 282 src_files="$src_files $(var_value OPENSSL_${prefix}_SOURCES_${arch})" 283 local exclude_files="$(var_value OPENSSL_${prefix}_SOURCES_EXCLUDES_${arch})" 284 src_files=$(filter_out "$src_files" "$exclude_files") 285 echo "$src_files" 286} 287 288# Return the compiler defines for a given module and architecture 289# $1: module prefix (e.g. CRYPTO) 290# $2 build arch. 291get_module_defines_for_arch () { 292 local prefix=$1 293 local arch=$2 294 local defines="$(var_value OPENSSL_${prefix}_DEFINES)" 295 defines="$defines $(var_value OPENSSL_${prefix}_DEFINES_${arch})" 296 echo "$defines" 297} 298 299# $1: module prefix (e.g. CRYPTO) 300get_module_c_includes () { 301 var_value OPENSSL_$1_INCLUDES 302} 303 304# $1: build type (e.g. gcc-android-arm) 305# Out: build arch. 306get_build_arch () { 307 echo "$1" | cut -d- -f3 308} 309 310# $1: build arch 311# Out: GNU configuration target (e.g. arm-linux-androideabi) 312get_build_arch_target () { 313 case $1 in 314 arm64) 315 echo "aarch64-linux-android" 316 ;; 317 arm) 318 echo "arm-linux-androideabi" 319 ;; 320 x86) 321 echo "x86_64-linux-android" 322 ;; 323 x86_64) 324 echo "x86_64-linux-android" 325 ;; 326 mips) 327 echo "mipsel-linux-android" 328 ;; 329 *) 330 echo "$1-linux-android" 331 ;; 332 esac 333} 334 335GCC_VERSION=4.8 336CLANG_VERSION=3.2 337 338get_prebuilt_gcc_dir_for_arch () { 339 local arch=$1 340 local target=$(get_build_arch_target $arch) 341 # Adjust $arch for x86_64 because the prebuilts are actually 342 # under prebuilts/gcc/<host>/x86/ 343 case $arch in 344 x86_64) 345 arch=x86 346 ;; 347 arm64) 348 arch=aarch64 349 ;; 350 esac 351 echo "$ANDROID_BUILD_TOP/prebuilts/gcc/$ANDROID_HOST_TAG/$arch/$target-$GCC_VERSION" 352} 353 354get_prebuilt_clang () { 355 echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clang" 356} 357 358get_prebuilt_ndk_sysroot_for_arch () { 359 echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1" 360} 361 362get_c_runtime_file () { 363 local build_type=$1 364 local arch=$(get_build_arch $build_type) 365 local filename=$2 366 echo "$(get_prebuilt_ndk_sysroot_for_arch $arch)/usr/lib/$filename" 367} 368 369# $1: build type (e.g. gcc-android-arm) 370get_build_compiler () { 371 local arch=$(get_build_arch $1) 372 local target=$(get_build_arch_target $arch) 373 local gcc_dir=$(get_prebuilt_gcc_dir_for_arch $arch); 374 local result 375 376 # Get the toolchain binary. 377 case $1 in 378 gcc-android-*) 379 result="$gcc_dir/bin/$target-gcc" 380 ;; 381 clang-android-*) 382 result="$(get_prebuilt_clang) -target $target -B$gcc_dir/$target/bin -I$gcc_dir/lib/gcc/$target/$GCC_VERSION/include" 383 ;; 384 gcc-*) 385 result=gcc 386 ;; 387 clang-*) # Must have host clang compiler. 388 result=clang 389 ;; 390 esac 391 392 compiler_check=$(which $result 2>/dev/null || echo "") 393 if [ -z "$compiler_check" ]; then 394 panic "Could not find compiler: $result" 395 fi 396 397 # Get the Android sysroot if needed. 398 case $1 in 399 *-android-*) 400 result="$result --sysroot=$(get_prebuilt_ndk_sysroot_for_arch $arch)" 401 ;; 402 esac 403 404 # Force -m32 flag when needed for 32-bit builds. 405 case $1 in 406 *-x86|*-generic32) 407 result="$result -m32" 408 ;; 409 esac 410 echo "$result" 411} 412 413# $1: build type. 414# Out: common compiler flags for this build. 415get_build_c_flags () { 416 local result="-O2 -fPIC" 417 case $1 in 418 *-android-arm) 419 result="$result -march=armv7-a -mfpu=vfpv3-d16" 420 ;; 421 esac 422 423 case $1 in 424 *-generic32|*-generic64) 425 # Generic builds do not compile without this flag. 426 result="$result -DOPENSSL_NO_ASM" 427 ;; 428 esac 429 echo "$result" 430} 431 432# $1: build type. 433# Out: linker for this build. 434get_build_linker () { 435 get_build_compiler $1 436} 437 438clear_sources () { 439 g_all_objs="" 440} 441 442# Generate build instructions to compile source files. 443# Also update g_all_objs. 444# $1: module prefix (e.g. CRYPTO) 445# $2: build type 446build_sources () { 447 local prefix=$1 448 local build_type=$2 449 echo "## build_sources prefix='$prefix' build_type='$build_type'" 450 local arch=$(get_build_arch $build_type) 451 local src_files=$(get_module_src_files_for_arch $prefix $arch) 452 local c_defines=$(get_module_defines_for_arch $prefix $arch) 453 local c_includes=$(get_module_c_includes $prefix "$SRC_DIR") 454 local build_cc=$(get_build_compiler $build_type) 455 local build_cflags=$(get_build_c_flags $build_type) 456 local build_linker=$(get_build_linker $build_type) 457 local src obj def inc 458 459 printf "OUT_DIR := $OUT_DIR/$build_type\n\n" 460 printf "BUILD_CC := $build_cc\n\n" 461 printf "BUILD_LINKER := $build_linker\n\n" 462 printf "BUILD_CFLAGS := $build_cflags" 463 for inc in $c_includes; do 464 printf " -I\$(SRC_DIR)/$inc" 465 done 466 for def in $c_defines; do 467 printf " -D$def" 468 done 469 printf "\n\n" 470 printf "BUILD_OBJECTS :=\n\n" 471 472 case $build_type in 473 clang-android-*) 474 # The version of clang that comes with the platform build doesn't 475 # support simple linking of shared libraries and executables. One 476 # has to provide the C runtime files explicitely. 477 local crtbegin_so=$(get_c_runtime_file $build_type crtbegin_so.o) 478 local crtend_so=$(get_c_runtime_file $build_type crtend_so.o) 479 local crtbegin_exe=$(get_c_runtime_file $build_type crtbegin_dynamic.o) 480 local crtend_exe=$(get_c_runtime_file $build_type crtend_android.o) 481 printf "CRTBEGIN_SO := $crtbegin_so\n" 482 printf "CRTEND_SO := $crtend_so\n" 483 printf "CRTBEGIN_EXE := $crtbegin_exe\n" 484 printf "CRTEND_EXE := $crtend_exe\n" 485 printf "\n" 486 ;; 487 esac 488 489 for src in $src_files; do 490 obj=$(src_to_obj $src) 491 g_all_objs="$g_all_objs $obj" 492 printf "OBJ := \$(OUT_DIR)/$obj\n" 493 printf "BUILD_OBJECTS += \$(OBJ)\n" 494 printf "\$(OBJ): PRIVATE_CC := \$(BUILD_CC)\n" 495 printf "\$(OBJ): PRIVATE_CFLAGS := \$(BUILD_CFLAGS)\n" 496 printf "\$(OBJ): \$(SRC_DIR)/$src\n" 497 printf "\t@echo [$build_type] CC $src\n" 498 printf "\t@mkdir -p \$\$(dirname \$@)\n" 499 printf "\t\$(hide) \$(PRIVATE_CC) \$(PRIVATE_CFLAGS) -c -o \$@ \$<\n" 500 printf "\n" 501 done 502 printf "\n" 503} 504 505# $1: library name (e.g. crypto). 506# $2: module prefix (e.g. CRYPTO). 507# $3: build type. 508# $4: source directory. 509# $5: output directory. 510build_shared_library () { 511 local name=$1 512 local prefix=$2 513 local build_type=$3 514 local src_dir="$4" 515 local out_dir="$5" 516 local shlib="lib${name}.so" 517 local build_linker=$(get_build_linker $build_type) 518 clear_sources 519 build_sources $prefix $build_type 520 521 # TODO(digit): Make the clang build link properly. 522 printf "SHLIB=\$(OUT_DIR)/$shlib\n" 523 printf "\$(SHLIB): PRIVATE_LINKER := \$(BUILD_LINKER)\n" 524 case $build_type in 525 clang-android-*) 526 printf "\$(SHLIB): PRIVATE_CRTBEGIN := \$(CRTBEGIN_SO)\n" 527 printf "\$(SHLIB): PRIVATE_CRTEND := \$(CRTEND_SO)\n" 528 ;; 529 esac 530 printf "\$(SHLIB): \$(BUILD_OBJECTS)\n" 531 printf "\t@echo [$build_type] SHARED_LIBRARY $(basename $shlib)\n" 532 printf "\t@mkdir -p \$\$(dirname \$@)\n" 533 case $build_type in 534 clang-android-*) 535 printf "\t\$(hide) \$(PRIVATE_LINKER) -nostdlib -shared -o \$@ \$(PRIVATE_CRTBEGIN) \$^ \$(PRIVATE_CRTEND)\n" 536 ;; 537 *) 538 printf "\t\$(hide) \$(PRIVATE_LINKER) -shared -o \$@ \$^\n" 539 ;; 540 esac 541 printf "\n" 542} 543 544# $1: executable name. 545# $2: module prefix (e.g. APPS). 546# $3: build type. 547# $4: source directory. 548# $5: output directory. 549# $6: dependent shared libraries (e.g. 'crypto ssl') 550build_executable () { 551 local name=$1 552 local prefix=$2 553 local build_type=$3 554 local src_dir="$4" 555 local out_dir="$5" 556 local shlibs="$6" 557 local build_linker=$(get_build_linker $build_type) 558 clear_sources 559 build_sources $prefix $build_type 560 561 # TODO(digit): Make the clang build link properly. 562 exec=$name 563 all_shlibs= 564 printf "EXEC := \$(OUT_DIR)/$name\n" 565 printf "openssl_all: \$(EXEC)\n" 566 printf "\$(EXEC): PRIVATE_LINKER := \$(BUILD_LINKER)\n" 567 printf "\$(EXEC): \$(BUILD_OBJECTS)" 568 for lib in $shlibs; do 569 printf " \$(OUT_DIR)/lib${lib}.so" 570 done 571 printf "\n" 572 printf "\t@echo [$build_type] EXECUTABLE $name\n" 573 printf "\t@mkdir -p \$\$(dirname \$@)\n" 574 printf "\t\$(hide) \$(PRIVATE_LINKER) -o \$@ \$^\n" 575 printf "\n" 576} 577 578ALL_BUILDS= 579 580generate_openssl_build () { 581 local build_type=$1 582 local out="$OUT_DIR/$build_type" 583 ALL_BUILDS="$ALL_BUILDS $build_type" 584 echo "# Build type: $build_type" 585 build_shared_library crypto CRYPTO $build_type "$SRC_DIR" "$out" 586 build_shared_library ssl SSL $build_type "$SRC_DIR" "$out" 587 build_executable openssl APPS $build_type "$SRC_DIR" "$out" "crypto ssl" 588} 589 590generate_makefile () { 591 echo \ 592"# Auto-generated by $PROGDIR - do not edit 593 594.PHONY: openssl_all 595 596all: openssl_all 597 598# Use 'make V=1' to print build commands. 599ifeq (1,\$(V)) 600hide := 601else 602hide := @ 603endif 604 605SRC_DIR=$SRC_DIR 606OUT_DIR=$OUT_DIR 607" 608 609 for BUILD_TYPE in $BUILD_TYPES; do 610 generate_openssl_build gcc-$BUILD_TYPE 611 done 612 613# TODO(digit): Make the Clang build run. 614# for BUILD_TYPE in $ANDROID_BUILD_TYPES; do 615# generate_openssl_build clang-$BUILD_TYPE 616# done 617} 618 619. $SRC_DIR/openssl.config 620 621 622 623dump "Generating Makefile" 624log "Makefile path: $MAKEFILE" 625generate_makefile > $MAKEFILE 626 627dump "Building libraries with $NUM_JOBS jobs" 628dump "For the following builds:" 629for BUILD in $ALL_BUILDS; do 630 dump " $BUILD" 631done 632MAKE_FLAGS="-j$NUM_JOBS" 633if [ "$VERBOSE" -gt 2 ]; then 634 MAKE_FLAGS="$MAKE_FLAGS V=1" 635fi 636run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR" 637case $? in 638 0) 639 dump "All OK, congratulations!" 640 ;; 641 *) 642 dump "Error, try doing the following to inspect the issues:" 643 dump " $PROGNAME --build-dir=/tmp/mybuild" 644 dump " make -C /tmp/mybuild V=1" 645 dump " " 646 ;; 647esac 648