Home | History | Annotate | Download | only in openssl
      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