1 #!/bin/sh 2 # 3 4 set -e 5 export LANG=C 6 export LC_ALL=C 7 8 PROGDIR=$(dirname "$0") 9 PROGNAME=$(basename "$0") 10 11 panic () { 12 echo "ERROR: $@" 13 exit 1 14 } 15 16 VERBOSE=1 17 18 # Dump message is $VERBOSE >= $1 19 # $1+: message. 20 dump_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. 30 dump () { 31 dump_n 1 "$@" 32 } 33 34 # Dump a message if --verbose is used only. 35 # $1+: message. 36 log () { 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. 44 run () { 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. 61 tolower () { 62 echo "$1" | tr '[A-Z]' '[a-z]' 63 } 64 65 # Return value of a given variable. 66 # $1: Variable name 67 var_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 75 filter_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 85 src_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. 100 HOST_OS=$(uname -s) 101 case $HOST_OS in 102 Linux) 103 HOST_OS=linux 104 ;; 105 Darwin) 106 HOST_OS=darwin 107 ;; 108 esac 109 110 # Determine host architecture 111 HOST_ARCH=$(uname -m) 112 case $HOST_ARCH in 113 i?86) 114 HOST_ARCH=x86 115 ;; 116 esac 117 118 ANDROID_HOST_TAG=$HOST_OS-$HOST_ARCH 119 120 case $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" 126 esac 127 128 # Determine number of cores 129 case $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 ;; 139 esac 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. 146 ANDROID_ARCHS="arm arm64 x86 x86_64 mips" 147 148 BUILD_TYPES= 149 for ARCH in $ANDROID_ARCHS; do 150 BUILD_TYPES="$BUILD_TYPES android-$ARCH" 151 done 152 ANDROID_BUILD_TYPES=$BUILD_TYPES 153 154 HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64" 155 HOST_BUILD_TYPES="$HOST_BUILD_TYPES $HOST_OS-x86_64" 156 157 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 158 159 # Parse command-line 160 DO_HELP= 161 SRC_DIR=$(cd $PROGDIR && pwd) 162 OUT_DIR=out 163 BUILD_DIR= 164 BUILD_TYPES= 165 NUM_JOBS=$NUM_CORES 166 ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd) 167 for 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 194 done 195 196 # Print help when needed. 197 if [ "$DO_HELP" ]; then 198 echo \ 199 "Usage: $PROGNAME [options] [<build-type> ...] 200 201 This script is used to ensure that all OpenSSL build variants compile 202 properly. It can be used after modifying external/openssl/openssl.config 203 and re-running import_openssl.sh to check that any changes didn't break 204 the build. 205 206 A <build-type> is a description of a given build of the library and its 207 program. Its format is: 208 209 <compiler>-<system>-<arch> 210 211 Where: <compiler> is either 'gcc' or 'clang'. 212 <system> is 'android', 'linux' or 'darwin'. 213 <arch> is 'arm', 'x86' or 'mips'. 214 215 By 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 224 This scripts generates a custom Makefile in a temporary directory, then 225 launches 'make' in it to build all binaries in parallel. In case of 226 problem, you can use the --build-dir=<path> option to specify a custom 227 build-directory, which will _not_ be removed when the script exits. 228 229 For example, to better see why a build fails: 230 231 ./$PROGNAME --build-dir=/tmp/mydir 232 make -C /tmp/mydir V=1 233 234 Valid 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 244 fi 245 246 log "Host OS: $HOST_OS" 247 log "Host arch: $HOST_ARCH" 248 log "Host CPU count: $NUM_CORES" 249 250 if [ -z "$BUILD_TYPES" ]; then 251 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" 252 fi 253 log "Build types: $BUILD_TYPES" 254 255 if [ -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" 267 else 268 log "Using user build directory: $BUILD_DIR" 269 fi 270 271 mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/* 272 273 MAKEFILE=$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. 278 get_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. 291 get_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) 300 get_module_c_includes () { 301 var_value OPENSSL_$1_INCLUDES 302 } 303 304 # $1: build type (e.g. gcc-android-arm) 305 # Out: build arch. 306 get_build_arch () { 307 echo "$1" | cut -d- -f3 308 } 309 310 # $1: build arch 311 # Out: GNU configuration target (e.g. arm-linux-androideabi) 312 get_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 335 GCC_VERSION=4.8 336 CLANG_VERSION=3.2 337 338 get_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 354 get_prebuilt_clang () { 355 echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clang" 356 } 357 358 get_prebuilt_ndk_sysroot_for_arch () { 359 echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1" 360 } 361 362 get_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) 370 get_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. 415 get_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. 434 get_build_linker () { 435 get_build_compiler $1 436 } 437 438 clear_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 446 build_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. 510 build_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') 550 build_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 578 ALL_BUILDS= 579 580 generate_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 590 generate_makefile () { 591 echo \ 592 "# Auto-generated by $PROGDIR - do not edit 593 594 .PHONY: openssl_all 595 596 all: openssl_all 597 598 # Use 'make V=1' to print build commands. 599 ifeq (1,\$(V)) 600 hide := 601 else 602 hide := @ 603 endif 604 605 SRC_DIR=$SRC_DIR 606 OUT_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 623 dump "Generating Makefile" 624 log "Makefile path: $MAKEFILE" 625 generate_makefile > $MAKEFILE 626 627 dump "Building libraries with $NUM_JOBS jobs" 628 dump "For the following builds:" 629 for BUILD in $ALL_BUILDS; do 630 dump " $BUILD" 631 done 632 MAKE_FLAGS="-j$NUM_JOBS" 633 if [ "$VERBOSE" -gt 2 ]; then 634 MAKE_FLAGS="$MAKE_FLAGS V=1" 635 fi 636 run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR" 637 case $? 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 ;; 647 esac 648