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. 142ANDROID_ARCHS="arm x86 mips" 143 144BUILD_TYPES= 145for ARCH in $ANDROID_ARCHS; do 146 BUILD_TYPES="$BUILD_TYPES android-$ARCH" 147done 148ANDROID_BUILD_TYPES=$BUILD_TYPES 149 150# NOTE: The $HOST_OS-x86_64 is currently broken because the single 151# <openssl/opensslconf.h> header is tailored for 32-bits. 152HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64" 153 154BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 155 156# Parse command-line 157DO_HELP= 158SRC_DIR=$(cd $PROGDIR && pwd) 159OUT_DIR=out 160BUILD_DIR= 161BUILD_TYPES= 162NUM_JOBS=$NUM_CORES 163ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd) 164for OPT; do 165 case $OPT in 166 --help|-h|-?) 167 DO_HELP=true 168 ;; 169 --build-dir=*) 170 BUILD_DIR=${OPT##--build-dir=} 171 ;; 172 --verbose) 173 VERBOSE=$(( $VERBOSE + 1 )) 174 ;; 175 --jobs=*) 176 NUM_JOBS=${OPT##--jobs=} 177 ;; 178 --quiet) 179 VERBOSE=$(( $VERBOSE - 1 )) 180 ;; 181 -j*) 182 NUM_JOBS=${OPT##-j} 183 ;; 184 -*) 185 panic "Unknown option '$OPT', see --help for details." 186 ;; 187 *) 188 BUILD_TYPES="$BUILD_TYPES $OPT" 189 ;; 190 esac 191done 192 193# Print help when needed. 194if [ "$DO_HELP" ]; then 195 echo \ 196"Usage: $PROGNAME [options] [<build-type> ...] 197 198This script is used to ensure that all OpenSSL build variants compile 199properly. It can be used after modifying external/openssl/openssl.config 200and re-running import_openssl.sh to check that any changes didn't break 201the build. 202 203A <build-type> is a description of a given build of the library and its 204program. Its format is: 205 206 <compiler>-<system>-<arch> 207 208Where: <compiler> is either 'gcc' or 'clang'. 209 <system> is 'android', 'linux' or 'darwin'. 210 <arch> is 'arm', 'x86' or 'mips'. 211 212By default, it rebuilds the sources for the following build types: 213" 214 for BUILD_TYPE in $BUILD_TYPES; do 215 echo " $BUILD_TYPE" 216 done 217 218 echo \ 219"However, you can pass custom values on the command-line instead. 220 221This scripts generates a custom Makefile in a temporary directory, then 222launches 'make' in it to build all binaries in parallel. In case of 223problem, you can use the --build-dir=<path> option to specify a custom 224build-directory, which will _not_ be removed when the script exits. 225 226For example, to better see why a build fails: 227 228 ./$PROGNAME --build-dir=/tmp/mydir 229 make -C /tmp/mydir V=1 230 231Valid options: 232 233 --help|-h|-? Print this message. 234 --build-dir=<path> Specify build directory. 235 --jobs=<count> Run <count> parallel build jobs [$NUM_JOBS]. 236 -j<count> Same as --jobs=<count>. 237 --verbose Increase verbosity. 238 --quiet Decrease verbosity. 239" 240 exit 0 241fi 242 243log "Host OS: $HOST_OS" 244log "Host arch: $HOST_ARCH" 245log "Host CPU count: $NUM_CORES" 246 247if [ -z "$BUILD_TYPES" ]; then 248 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 249fi 250log "Build types: $BUILD_TYPES" 251 252if [ -z "$BUILD_DIR" ]; then 253 # Create a temporary directory, ensure it gets destroyed properly 254 # when the script exits. 255 BUILD_DIR=$(mktemp -d) 256 clean_build_dir () { 257 log "Cleaning up temporary directory: $BUILD_DIR" 258 rm -rf "$BUILD_DIR" 259 exit $1 260 } 261 trap "clean_build_dir 0" EXIT 262 trap "clean_build_dir \$?" INT HUP QUIT TERM 263 log "Using temporary build directory: $BUILD_DIR" 264else 265 log "Using user build directory: $BUILD_DIR" 266fi 267 268mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/* 269 270MAKEFILE=$BUILD_DIR/GNUmakefile 271 272# Return source files for a given module and architecture. 273# $1: module prefix (e.g. CRYPTO) 274# $2: build arch. 275get_module_src_files_for_arch () { 276 local prefix=$1 277 local arch=$2 278 local src_files="$(var_value OPENSSL_${prefix}_SOURCES)" 279 src_files="$src_files $(var_value OPENSSL_${prefix}_SOURCES_${arch})" 280 local exclude_files="$(var_value OPENSSL_${prefix}_SOURCES_EXCLUDES_${arch})" 281 src_files=$(filter_out "$src_files" "$exclude_files") 282 echo "$src_files" 283} 284 285# Return the compiler defines for a given module and architecture 286# $1: module prefix (e.g. CRYPTO) 287# $2 build arch. 288get_module_defines_for_arch () { 289 local prefix=$1 290 local arch=$2 291 local defines="$(var_value OPENSSL_${prefix}_DEFINES)" 292 defines="$defines $(var_value OPENSSL_${prefix}_DEFINES_${arch})" 293 echo "$defines" 294} 295 296# $1: module prefix (e.g. CRYPTO) 297get_module_c_includes () { 298 var_value OPENSSL_$1_INCLUDES 299} 300 301# $1: build type (e.g. gcc-android-arm) 302# Out: build arch. 303get_build_arch () { 304 echo "$1" | cut -d- -f3 305} 306 307# $1: build arch 308# Out: GNU configuration target (e.g. arm-linux-androideabi) 309get_build_arch_target () { 310 case $1 in 311 arm) 312 echo "arm-linux-androideabi" 313 ;; 314 x86) 315 echo "i686-linux-android" 316 ;; 317 mips) 318 echo "mipsel-linux-android" 319 ;; 320 *) 321 echo "$1-linux-android" 322 ;; 323 esac 324} 325 326GCC_VERSION=4.7 327CLANG_VERSION=3.1 328 329get_prebuilt_gcc_dir_for_arch () { 330 local arch=$1 331 local target=$(get_build_arch_target $arch) 332 echo "$ANDROID_BUILD_TOP/prebuilts/gcc/$ANDROID_HOST_TAG/$arch/$target-$GCC_VERSION" 333} 334 335get_prebuilt_clang () { 336 echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clang" 337} 338 339get_prebuilt_ndk_sysroot_for_arch () { 340 echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1" 341} 342 343get_c_runtime_file () { 344 local build_type=$1 345 local arch=$(get_build_arch $build_type) 346 local filename=$2 347 echo "$(get_prebuilt_ndk_sysroot_for_arch $arch)/usr/lib/$filename" 348} 349 350# $1: build type (e.g. gcc-android-arm) 351get_build_compiler () { 352 local arch=$(get_build_arch $1) 353 local target=$(get_build_arch_target $arch) 354 local gcc_dir=$(get_prebuilt_gcc_dir_for_arch $arch); 355 local result 356 357 # Get the toolchain binary. 358 case $1 in 359 gcc-android-*) 360 result="$gcc_dir/bin/$target-gcc" 361 ;; 362 clang-android-*) 363 result="$(get_prebuilt_clang) -target $target -B$gcc_dir/$target/bin -I$gcc_dir/lib/gcc/$target/$GCC_VERSION/include" 364 ;; 365 gcc-*) 366 result=gcc 367 ;; 368 clang-*) # Must have host clang compiler. 369 result=clang 370 ;; 371 esac 372 373 compiler_check=$(which $result 2>/dev/null || echo "") 374 if [ -z "$compiler_check" ]; then 375 panic "Could not find compiler: $result" 376 fi 377 378 # Get the Android sysroot if needed. 379 case $1 in 380 *-android-*) 381 result="$result --sysroot=$(get_prebuilt_ndk_sysroot_for_arch $arch)" 382 ;; 383 esac 384 385 # Force -m32 flag when needed for 32-bit builds. 386 case $1 in 387 *-linux-x86|*-darwin-x86|*-generic32) 388 result="$result -m32" 389 ;; 390 esac 391 echo "$result" 392} 393 394# $1: build type. 395# Out: common compiler flags for this build. 396get_build_c_flags () { 397 local result="-O2 -fPIC" 398 case $1 in 399 *-android-arm) 400 result="$result -march=armv7-a -mfpu=vfpv3-d16" 401 ;; 402 esac 403 404 case $1 in 405 *-generic32|*-generic64) 406 # Generic builds do not compile without this flag. 407 result="$result -DOPENSSL_NO_ASM" 408 ;; 409 esac 410 echo "$result" 411} 412 413# $1: build type. 414# Out: linker for this build. 415get_build_linker () { 416 get_build_compiler $1 417} 418 419clear_sources () { 420 g_all_objs="" 421} 422 423# Generate build instructions to compile source files. 424# Also update g_all_objs. 425# $1: module prefix (e.g. CRYPTO) 426# $2: build type 427build_sources () { 428 local prefix=$1 429 local build_type=$2 430 echo "## build_sources prefix='$prefix' build_type='$build_type'" 431 local arch=$(get_build_arch $build_type) 432 local src_files=$(get_module_src_files_for_arch $prefix $arch) 433 local c_defines=$(get_module_defines_for_arch $prefix $arch) 434 local c_includes=$(get_module_c_includes $prefix "$SRC_DIR") 435 local build_cc=$(get_build_compiler $build_type) 436 local build_cflags=$(get_build_c_flags $build_type) 437 local build_linker=$(get_build_linker $build_type) 438 local src obj def inc 439 440 printf "OUT_DIR := $OUT_DIR/$build_type\n\n" 441 printf "BUILD_CC := $build_cc\n\n" 442 printf "BUILD_LINKER := $build_linker\n\n" 443 printf "BUILD_CFLAGS := $build_cflags" 444 for inc in $c_includes; do 445 printf " -I\$(SRC_DIR)/$inc" 446 done 447 for def in $c_defines; do 448 printf " -D$def" 449 done 450 printf "\n\n" 451 printf "BUILD_OBJECTS :=\n\n" 452 453 case $build_type in 454 clang-android-*) 455 # The version of clang that comes with the platform build doesn't 456 # support simple linking of shared libraries and executables. One 457 # has to provide the C runtime files explicitely. 458 local crtbegin_so=$(get_c_runtime_file $build_type crtbegin_so.o) 459 local crtend_so=$(get_c_runtime_file $build_type crtend_so.o) 460 local crtbegin_exe=$(get_c_runtime_file $build_type crtbegin_dynamic.o) 461 local crtend_exe=$(get_c_runtime_file $build_type crtend_android.o) 462 printf "CRTBEGIN_SO := $crtbegin_so\n" 463 printf "CRTEND_SO := $crtend_so\n" 464 printf "CRTBEGIN_EXE := $crtbegin_exe\n" 465 printf "CRTEND_EXE := $crtend_exe\n" 466 printf "\n" 467 ;; 468 esac 469 470 for src in $src_files; do 471 obj=$(src_to_obj $src) 472 g_all_objs="$g_all_objs $obj" 473 printf "OBJ := \$(OUT_DIR)/$obj\n" 474 printf "BUILD_OBJECTS += \$(OBJ)\n" 475 printf "\$(OBJ): PRIVATE_CC := \$(BUILD_CC)\n" 476 printf "\$(OBJ): PRIVATE_CFLAGS := \$(BUILD_CFLAGS)\n" 477 printf "\$(OBJ): \$(SRC_DIR)/$src\n" 478 printf "\t@echo [$build_type] CC $src\n" 479 printf "\t@mkdir -p \$\$(dirname \$@)\n" 480 printf "\t\$(hide) \$(PRIVATE_CC) \$(PRIVATE_CFLAGS) -c -o \$@ \$<\n" 481 printf "\n" 482 done 483 printf "\n" 484} 485 486# $1: library name (e.g. crypto). 487# $2: module prefix (e.g. CRYPTO). 488# $3: build type. 489# $4: source directory. 490# $5: output directory. 491build_shared_library () { 492 local name=$1 493 local prefix=$2 494 local build_type=$3 495 local src_dir="$4" 496 local out_dir="$5" 497 local shlib="lib${name}.so" 498 local build_linker=$(get_build_linker $build_type) 499 clear_sources 500 build_sources $prefix $build_type 501 502 # TODO(digit): Make the clang build link properly. 503 printf "SHLIB=\$(OUT_DIR)/$shlib\n" 504 printf "\$(SHLIB): PRIVATE_LINKER := \$(BUILD_LINKER)\n" 505 case $build_type in 506 clang-android-*) 507 printf "\$(SHLIB): PRIVATE_CRTBEGIN := \$(CRTBEGIN_SO)\n" 508 printf "\$(SHLIB): PRIVATE_CRTEND := \$(CRTEND_SO)\n" 509 ;; 510 esac 511 printf "\$(SHLIB): \$(BUILD_OBJECTS)\n" 512 printf "\t@echo [$build_type] SHARED_LIBRARY $(basename $shlib)\n" 513 printf "\t@mkdir -p \$\$(dirname \$@)\n" 514 case $build_type in 515 clang-android-*) 516 printf "\t\$(hide) \$(PRIVATE_LINKER) -nostdlib -shared -o \$@ \$(PRIVATE_CRTBEGIN) \$^ \$(PRIVATE_CRTEND)\n" 517 ;; 518 *) 519 printf "\t\$(hide) \$(PRIVATE_LINKER) -shared -o \$@ \$^\n" 520 ;; 521 esac 522 printf "\n" 523} 524 525# $1: executable name. 526# $2: module prefix (e.g. APPS). 527# $3: build type. 528# $4: source directory. 529# $5: output directory. 530# $6: dependent shared libraries (e.g. 'crypto ssl') 531build_executable () { 532 local name=$1 533 local prefix=$2 534 local build_type=$3 535 local src_dir="$4" 536 local out_dir="$5" 537 local shlibs="$6" 538 local build_linker=$(get_build_linker $build_type) 539 clear_sources 540 build_sources $prefix $build_type 541 542 # TODO(digit): Make the clang build link properly. 543 exec=$name 544 all_shlibs= 545 printf "EXEC := \$(OUT_DIR)/$name\n" 546 printf "openssl_all: \$(EXEC)\n" 547 printf "\$(EXEC): PRIVATE_LINKER := \$(BUILD_LINKER)\n" 548 printf "\$(EXEC): \$(BUILD_OBJECTS)" 549 for lib in $shlibs; do 550 printf " \$(OUT_DIR)/lib${lib}.so" 551 done 552 printf "\n" 553 printf "\t@echo [$build_type] EXECUTABLE $name\n" 554 printf "\t@mkdir -p \$\$(dirname \$@)\n" 555 printf "\t\$(hide) \$(PRIVATE_LINKER) -o \$@ \$^\n" 556 printf "\n" 557} 558 559ALL_BUILDS= 560 561generate_openssl_build () { 562 local build_type=$1 563 local out="$OUT_DIR/$build_type" 564 ALL_BUILDS="$ALL_BUILDS $build_type" 565 echo "# Build type: $build_type" 566 build_shared_library crypto CRYPTO $build_type "$SRC_DIR" "$out" 567 build_shared_library ssl SSL $build_type "$SRC_DIR" "$out" 568 build_executable openssl APPS $build_type "$SRC_DIR" "$out" "crypto ssl" 569} 570 571generate_makefile () { 572 echo \ 573"# Auto-generated by $PROGDIR - do not edit 574 575.PHONY: openssl_all 576 577all: openssl_all 578 579# Use 'make V=1' to print build commands. 580ifeq (1,\$(V)) 581hide := 582else 583hide := @ 584endif 585 586SRC_DIR=$SRC_DIR 587OUT_DIR=$OUT_DIR 588" 589 590 for BUILD_TYPE in $BUILD_TYPES; do 591 generate_openssl_build gcc-$BUILD_TYPE 592 done 593 594# TODO(digit): Make the Clang build run. 595# for BUILD_TYPE in $ANDROID_BUILD_TYPES; do 596# generate_openssl_build clang-$BUILD_TYPE 597# done 598} 599 600. $SRC_DIR/openssl.config 601 602 603 604dump "Generating Makefile" 605log "Makefile path: $MAKEFILE" 606generate_makefile > $MAKEFILE 607 608dump "Building libraries with $NUM_JOBS jobs" 609dump "For the following builds:" 610for BUILD in $ALL_BUILDS; do 611 dump " $BUILD" 612done 613MAKE_FLAGS="-j$NUM_JOBS" 614if [ "$VERBOSE" -gt 2 ]; then 615 MAKE_FLAGS="$MAKE_FLAGS V=1" 616fi 617run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR" 618case $? in 619 0) 620 dump "All OK, congratulations!" 621 ;; 622 *) 623 dump "Error, try doing the following to inspect the issues:" 624 dump " $PROGNAME --build-dir=/tmp/mybuild" 625 dump " make -C /tmp/mybuild V=1" 626 dump "" 627 ;; 628esac 629