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 ANDROID_ARCHS="arm x86 mips"
    143 
    144 BUILD_TYPES=
    145 for ARCH in $ANDROID_ARCHS; do
    146   BUILD_TYPES="$BUILD_TYPES android-$ARCH"
    147 done
    148 ANDROID_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.
    152 HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64"
    153 
    154 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES"
    155 
    156 # Parse command-line
    157 DO_HELP=
    158 SRC_DIR=$(cd $PROGDIR && pwd)
    159 OUT_DIR=out
    160 BUILD_DIR=
    161 BUILD_TYPES=
    162 NUM_JOBS=$NUM_CORES
    163 ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd)
    164 for 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
    191 done
    192 
    193 # Print help when needed.
    194 if [ "$DO_HELP" ]; then
    195   echo \
    196 "Usage: $PROGNAME [options] [<build-type> ...]
    197 
    198 This script is used to ensure that all OpenSSL build variants compile
    199 properly. It can be used after modifying external/openssl/openssl.config
    200 and re-running import_openssl.sh to check that any changes didn't break
    201 the build.
    202 
    203 A <build-type> is a description of a given build of the library and its
    204 program. Its format is:
    205 
    206   <compiler>-<system>-<arch>
    207 
    208 Where: <compiler> is either 'gcc' or 'clang'.
    209        <system>   is 'android', 'linux' or 'darwin'.
    210        <arch>     is 'arm', 'x86'  or 'mips'.
    211 
    212 By 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 
    221 This scripts generates a custom Makefile in a temporary directory, then
    222 launches 'make' in it to build all binaries in parallel. In case of
    223 problem, you can use the --build-dir=<path> option to specify a custom
    224 build-directory, which will _not_ be removed when the script exits.
    225 
    226 For example, to better see why a build fails:
    227 
    228    ./$PROGNAME --build-dir=/tmp/mydir
    229    make -C /tmp/mydir V=1
    230 
    231 Valid 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
    241 fi
    242 
    243 log "Host OS: $HOST_OS"
    244 log "Host arch: $HOST_ARCH"
    245 log "Host CPU count: $NUM_CORES"
    246 
    247 if [ -z "$BUILD_TYPES" ]; then
    248   BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES"
    249 fi
    250 log "Build types: $BUILD_TYPES"
    251 
    252 if [ -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"
    264 else
    265   log "Using user build directory: $BUILD_DIR"
    266 fi
    267 
    268 mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/*
    269 
    270 MAKEFILE=$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.
    275 get_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.
    288 get_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)
    297 get_module_c_includes () {
    298   var_value OPENSSL_$1_INCLUDES
    299 }
    300 
    301 # $1: build type (e.g. gcc-android-arm)
    302 # Out: build arch.
    303 get_build_arch () {
    304   echo "$1" | cut -d- -f3
    305 }
    306 
    307 # $1: build arch
    308 # Out: GNU configuration target (e.g. arm-linux-androideabi)
    309 get_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 
    326 GCC_VERSION=4.7
    327 CLANG_VERSION=3.1
    328 
    329 get_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 
    335 get_prebuilt_clang () {
    336   echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clang"
    337 }
    338 
    339 get_prebuilt_ndk_sysroot_for_arch () {
    340   echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1"
    341 }
    342 
    343 get_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)
    351 get_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.
    396 get_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.
    415 get_build_linker () {
    416   get_build_compiler $1
    417 }
    418 
    419 clear_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
    427 build_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.
    491 build_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')
    531 build_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 
    559 ALL_BUILDS=
    560 
    561 generate_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 
    571 generate_makefile () {
    572   echo \
    573 "# Auto-generated by $PROGDIR - do not edit
    574 
    575 .PHONY: openssl_all
    576 
    577 all: openssl_all
    578 
    579 # Use 'make V=1' to print build commands.
    580 ifeq (1,\$(V))
    581 hide :=
    582 else
    583 hide := @
    584 endif
    585 
    586 SRC_DIR=$SRC_DIR
    587 OUT_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 
    604 dump "Generating Makefile"
    605 log "Makefile path: $MAKEFILE"
    606 generate_makefile > $MAKEFILE
    607 
    608 dump "Building libraries with $NUM_JOBS jobs"
    609 dump "For the following builds:"
    610 for BUILD in $ALL_BUILDS; do
    611   dump "  $BUILD"
    612 done
    613 MAKE_FLAGS="-j$NUM_JOBS"
    614 if [ "$VERBOSE" -gt 2 ]; then
    615   MAKE_FLAGS="$MAKE_FLAGS V=1"
    616 fi
    617 run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR"
    618 case $? 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     ;;
    628 esac
    629