Home | History | Annotate | Download | only in openssl
      1 #!/bin/sh
      2 #
      3 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # Sanitize environment.
      8 set -e
      9 export LANG=C
     10 export LC_ALL=C
     11 
     12 PROGDIR=$(dirname "$0")
     13 PROGNAME=$(basename "$0")
     14 
     15 # Defaults
     16 VERBOSE=1
     17 
     18 . "$PROGDIR/openssl-chromium.config"
     19 
     20 # Print error message and exit script.
     21 # $1+: Error message.
     22 panic () {
     23   echo "ERROR: $@"
     24   exit 1
     25 }
     26 
     27 # $1: Variable name
     28 # Output: variable value.
     29 var_value () {
     30   # NOTE: Don't use 'echo' here, it is sensitive to options like -n.
     31   eval printf \"%s\\n\" \$$1
     32 }
     33 
     34 # Print a message if verbosity is sufficiently high.
     35 # $1: Verbosity threshold, only if '$VERBOSE > $1' does this print.
     36 # $2+: Message.
     37 dump_n () {
     38   local LEVEL=$1
     39   shift
     40   if [ "$VERBOSE" -gt "$LEVEL" ]; then
     41     printf "%s\n" "$@"
     42   fi
     43 }
     44 
     45 # Print a message, unless --quiet was used.
     46 dump () {
     47   dump_n 0 "$@"
     48 }
     49 
     50 # Print a message if --verbose was used.
     51 log () {
     52   dump_n 1 "$@"
     53 }
     54 
     55 # Print a message if --verbose --verbose was used.
     56 log2 () {
     57   dump_n 2 "$@"
     58 }
     59 
     60 # Run a command silently, unless --verbose is used.
     61 # More specifically:
     62 #  - By default, this runs the command but redirects its stdout/stderr
     63 #    to /dev/null to avoid printing anything.
     64 #  - If --verbose is used, this prints the command's name, and stderr
     65 #    will not be redirected.
     66 #  - If '--verbose --verbose' is used, this prints the commands and its
     67 #    complete output.
     68 # $1+: Command
     69 # Return: Command status
     70 run () {
     71   if [ "$VERBOSE" -gt 1 ]; then
     72     echo "COMMAND: $@"
     73   fi
     74   case $VERBOSE in
     75     0)
     76         "$@" > /dev/null 2>&1
     77         ;;
     78     1)
     79         "$@" > /dev/null
     80         ;;
     81     *)
     82         "$@"
     83         ;;
     84   esac
     85 }
     86 
     87 # Support cleaning up stuff when the script exits, even in case of
     88 # error.
     89 _ALL_CLEANUPS=
     90 
     91 clean_atexit () {
     92   local CLEANUPS CLEANUP
     93   CLEANUPS=$_ALL_CLEANUPS
     94   _ALL_CLEANUPS=
     95   for CLEANUP in $CLEANUPS; do
     96     ($CLEANUP)
     97   done
     98   exit $1
     99 }
    100 
    101 trap "clean_atexit 0" EXIT
    102 trap "clean_atexit \$?" HUP INT QUIT TERM
    103 
    104 # Add a cleanup function to the list of cleanups that will be run when
    105 # the script exits.
    106 atexit () {
    107     # Prepend to ensure that the cleanup steps are performed in reverse
    108     # order or registration.
    109     _ALL_CLEANUPS="$* $_ALL_CLEANUPS"
    110 }
    111 
    112 # Support code to write into a gyp file
    113 _GYP_MARGIN=""
    114 
    115 # Increment margin of gyp printer.
    116 incr_gyp_margin () {
    117   _GYP_MARGIN="$_GYP_MARGIN  "
    118 }
    119 
    120 decr_gyp_margin () {
    121   _GYP_MARGIN=$(echo "$_GYP_MARGIN" | cut --bytes=3-)
    122 }
    123 
    124 print_gyp () {
    125   printf "%s%s\n" "$_GYP_MARGIN" "$@"
    126 }
    127 
    128 # This prints a list variable definition in a gyp file.
    129 # $1: Variable name (e.g. 'openssl_common_defines')
    130 # $2+: List items (e.g. defines)
    131 print_gyp_variable () {
    132   local VARNAME=$1
    133   local VALUE
    134   shift
    135   print_gyp "'$VARNAME': ["
    136   for VALUE; do
    137     print_gyp "  '$VALUE',"
    138   done
    139   print_gyp "],"
    140 }
    141 
    142 # Same as print_gyp_variable, but for source file lists, this
    143 # prepends openssl/ as required by the Chromium build to each item
    144 # in the list.
    145 # $1: Variable name (e.g. 'openssl_common_sources')
    146 # $2+: List items (source file names).
    147 print_gyp_source_variable () {
    148   local VARNAME=$1
    149   local VALUE
    150   shift
    151   print_gyp "'$VARNAME': ["
    152   for VALUE; do
    153     print_gyp "  'openssl/$VALUE',"
    154   done
    155   print_gyp "],"
    156 }
    157 
    158 # Print usage instructions.
    159 usage () {
    160     echo \
    161 "Usage: $PROGNAME [options]
    162 
    163 This script is used to regenerate the content of the Chromium
    164 third_party/openssl/ directory according to the configuration file
    165 named 'openssl-chromium.config'.
    166 
    167 In particular, it will perform the following steps:
    168 
    169   1) Download the Android sources from the AOSP git servers.
    170 
    171   2) Add Chromium-specific patches to the Android source tree.
    172      (they must be under patches.chromium/ in $PROGDIR).
    173 
    174   3) Download a versioned openssl package from the official OpenSSL
    175      servers, and check its MD5. The version is taken from the
    176      'openssl.version' file in the Android source tree.
    177 
    178   4) Run the Android 'import_openssl.sh' script that rebuilds all sources
    179      from a clean slate.
    180 
    181   5) Generate the 'openssl.gypi' that contains gyp-specific declarations
    182      for the library.
    183 
    184   6) Generate 64-bit compatible opensslconf.h header.
    185 
    186 Valid options are the following (defaults are in brackets):
    187 
    188   --help|-h|-?          Display this message.
    189   --aosp-git=<url>      Change git source for Android repository.
    190                         [$ANDROID_OPENSSL_GIT_SOURCE]
    191   --aosp-commit=<name>  Specify git commit or branch name [$ANDROID_OPENSSL_GIT_COMMIT]
    192   --temp-dir=<path>     Specify temporary directory, will not be cleaned.
    193                         [<random-temp-file-cleaned-on-exit>]
    194   --verbose             Increase verbosity.
    195   --quiet               Decrease verbosity.
    196 "
    197   exit 1
    198 }
    199 
    200 # Parse command-line.
    201 DO_HELP=
    202 
    203 for OPT; do
    204   OPTARG=$()
    205   case $OPT in
    206     --help|-h|-?)
    207         DO_HELP=true
    208         ;;
    209     --aosp-commit=*)
    210         ANDROID_OPENSSL_GIT_COMMIT=${OPT#--aosp-commit=}
    211         if [ -z "$ANDROID_OPENSSL_GIT_COMMIT" ]; then
    212             panic "Missing option value: $OPT"
    213         fi
    214         ;;
    215     --aosp-git=*)
    216         ANDROID_OPENSSL_GIT_SOURCE=${OPT#--aosp-git=}
    217         if [ -z "$ANDROID_OPENSSL_GIT_SOURCE" ]; then
    218             panic "Missing option value: $OPT"
    219         fi
    220         ;;
    221     --temp-dir=*)
    222         TEMP_DIR=${OPT#--temp-dir=}
    223         if [ -z "$TEMP_DIR" ]; then
    224             panic "Missing option value: $OPT"
    225         fi
    226         ;;
    227     --quiet)
    228         VERBOSE=$(( $VERBOSE - 1 ))
    229         ;;
    230     --verbose)
    231         VERBOSE=$(( $VERBOSE + 1 ))
    232         ;;
    233     -*)
    234         panic "Invalid option '$OPT', see --help for details."
    235         ;;
    236     *)
    237         panic "This script doesn't take parameters. See --help for details."
    238         ;;
    239   esac
    240 done
    241 
    242 if [ "$DO_HELP" ]; then
    243   usage
    244 fi
    245 
    246 # Create temporary directory. Ensure it's always cleaned up on exit.
    247 if [ -z "$TEMP_DIR" ]; then
    248   TEMP_DIR=$(mktemp -d)
    249   clean_tempdir () {
    250     rm -rf "$TEMP_DIR"
    251   }
    252   atexit clean_tempdir
    253   log "Temporary directory created: $TEMP_DIR"
    254 else
    255   log "Using user-provided temp directory: $TEMP_DIR"
    256 fi
    257 
    258 GIT_FLAGS=
    259 case $VERBOSE in
    260   0|1)
    261     GIT_CLONE_FLAGS="--quiet"
    262     GIT_CHECKOUT_FLAGS="--quiet"
    263     CURL_FLAGS="-s"
    264     ;;
    265   2)
    266     GIT_CLONE_FLAGS=""
    267     GIT_CHECKOUT_FLAGS=""
    268     CURL_FLAGS=""
    269     ;;
    270   *)
    271     GIT_CLONE_FLAGS="--verbose"
    272     GIT_CHECKOUT_FLAGS=""
    273     CURL_FLAGS=""
    274     ;;
    275 esac
    276 
    277 BUILD_DIR=$TEMP_DIR/build
    278 mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/*
    279 
    280 # Download the Android sources.
    281 ANDROID_SRC_DIR=$BUILD_DIR/android-openssl
    282 dump "Downloading Android sources"
    283 log "Downloading branch $ANDROID_OPENSSL_GIT_COMMIT from: $ANDROID_OPENSSL_GIT_SOURCE"
    284 (
    285   run mkdir -p $ANDROID_SRC_DIR
    286   run cd $ANDROID_SRC_DIR
    287   run git clone $GIT_CLONE_FLAGS $ANDROID_OPENSSL_GIT_SOURCE .
    288   run git checkout $GIT_CHECKOUT_FLAGS $ANDROID_OPENSSL_GIT_COMMIT
    289   run rm -rf .git
    290 )
    291 
    292 # Apply chromium-specific patches located in patches.chromium
    293 CHROMIUM_PATCHES_DIR=$PROGDIR/patches.chromium
    294 if [ ! -d "$CHROMIUM_PATCHES_DIR" ]; then
    295   dump "No Chromium-specific patches to apply."
    296 else
    297   dump "Applying Chromium-specific patches:"
    298   CHROMIUM_PATCHES=$(/bin/ls $CHROMIUM_PATCHES_DIR/*.patch 2>/dev/null)
    299   for CHROMIUM_PATCH in $CHROMIUM_PATCHES; do
    300     dump "Applying: $CHROMIUM_PATCH"
    301     (cd $ANDROID_SRC_DIR && run patch -p1) < $CHROMIUM_PATCH
    302   done
    303 fi
    304 
    305 # Get the openssl version
    306 . $ANDROID_SRC_DIR/openssl.version
    307 if [ -z "$OPENSSL_VERSION" ]; then
    308   panic "Could not find OPENSSL_VERSION definition from $ANDROID_SRC_DIR!"
    309 fi
    310 dump "Found OpenSSL version: $OPENSSL_VERSION"
    311 
    312 # Download OpenSSL package
    313 DOWNLOAD_DIR=$BUILD_DIR/download
    314 mkdir -p "$DOWNLOAD_DIR"
    315 
    316 OPENSSL_PACKAGE=openssl-$OPENSSL_VERSION.tar.gz
    317 dump "Downloading $OPENSSL_PACKAGE from $OPENSSL_TAR_SOURCE"
    318 run curl $CURL_FLAGS -o $DOWNLOAD_DIR/$OPENSSL_PACKAGE $OPENSSL_TAR_SOURCE/$OPENSSL_PACKAGE
    319 run curl $CURL_FLAGS -o $DOWNLOAD_DIR/$OPENSSL_PACKAGE.md5 $OPENSSL_TAR_SOURCE/$OPENSSL_PACKAGE.md5
    320 
    321 OPENSSL_SHA1_DOWNLOADED=$(sha1sum $DOWNLOAD_DIR/$OPENSSL_PACKAGE | cut -d" " -f1)
    322 OPENSSL_SHA1_EXPECTED=$OPENSSL_TAR_SHA1
    323 if [ "$OPENSSL_SHA1_DOWNLOADED" != "$OPENSSL_SHA1_EXPECTED" ]; then
    324   echo "ERROR: Content mismatch for downloaded OpenSSL package:"
    325   echo "       Downloaded SHA-1: $OPENSSL_SHA1_DOWNLOADED"
    326   echo "       Expected SHA-1  : $OPENSSL_SHA1_EXPECTED"
    327   exit 1
    328 fi
    329 dump "Checking content of downloaded package: ok"
    330 
    331 # The import_openssl.sh script will really remove the existing 'openssl'
    332 # directory and replace it with something completely new. This is a problem
    333 # when using subversion because this also gets rid of all .svn
    334 # subdirectories. This makes it impossible to commit the right set of
    335 # changes with "gcl commit".
    336 #
    337 # To work-around this, copy all the .svn subdirectories into a temporary
    338 # tarball, which will be extracted after the import process.
    339 #
    340 dump "Saving .svn subdirectories"
    341 SVN_LIST_FILE=$BUILD_DIR/svn-subdirs
    342 run find . -type d -name ".svn" > $SVN_LIST_FILE
    343 SAVED_SVN_TARBALL=$BUILD_DIR/saved-svn-subdirs.tar.gz
    344 run tar czf $SAVED_SVN_TARBALL -T $SVN_LIST_FILE
    345 
    346 # Re-run the import_openssl.sh script.
    347 dump "Re-running the 'import_openssl.sh' script to reconfigure all sources."
    348 (
    349   cd $ANDROID_SRC_DIR
    350   run ./import_openssl.sh import $DOWNLOAD_DIR/$OPENSSL_PACKAGE
    351 )
    352 
    353 dump "Copying new Android sources to final location."
    354 clean_openssl_new () {
    355   rm -rf "$PROGDIR/openssl.new"
    356 }
    357 atexit clean_openssl_new
    358 
    359 run cp -rp "$ANDROID_SRC_DIR" "$PROGDIR/openssl.new"
    360 run mv "$PROGDIR/openssl" "$PROGDIR/openssl.old"
    361 run mv "$PROGDIR/openssl.new" "$PROGDIR/openssl"
    362 run rm -rf "$PROGDIR/openssl.old"
    363 
    364 dump "Restoring .svn subdirectores"
    365 run tar xzf $SAVED_SVN_TARBALL
    366 
    367 # Extract list of source files or compiler defines from openssl.config
    368 # variable definition. This assumes that the lists are in variables that
    369 # are named as <prefix><suffix> or <prefix><suffix><arch>.
    370 #
    371 # A few examples:
    372 #   get_gyp_list "FOO BAR" _SOURCES
    373 #     -> returns '$FOO_SOURCES $BAR_SOURCES'
    374 #
    375 #   get_gyp_list FOO _SOURCES_ "arm x86"
    376 #     -> returns '$FOO_SOURCES_arm $FOO_SOURCES_x86"
    377 #
    378 #   get_gyp_list "FOO BAR" _SOURCES_ "arm x86"
    379 #     -> returns '$FOO_SOURCES_arm $FOO_SOURCES_x86 $BAR_SOURCES_arm $BAR_SOURCES_x86'
    380 #
    381 # $1: list of variable prefixes
    382 # $2: variable suffix
    383 # $3: optional list of architectures.
    384 get_gyp_list () {
    385   local ALL_PREFIXES="$1"
    386   local SUFFIX="$2"
    387   local ALL_ARCHS="$3"
    388   local LIST PREFIX ARCH
    389   for PREFIX in $ALL_PREFIXES; do
    390     if [ "$ALL_ARCHS" ]; then
    391       for ARCH in $ALL_ARCHS; do
    392         LIST="$LIST $(var_value ${PREFIX}${SUFFIX}${ARCH})"
    393       done
    394     else
    395       LIST="$LIST $(var_value ${PREFIX}${SUFFIX})"
    396     fi
    397   done
    398   echo "$LIST"
    399 }
    400 
    401 generate_gyp_file () {
    402   echo "# Auto-generated file - DO NOT EDIT"
    403   echo "# To regenerate - run import_from_android.sh."
    404   echo "# See 'import_from_android.sh --help' for details."
    405 
    406   local ALL_PREFIXES="OPENSSL_CRYPTO OPENSSL_SSL"
    407   local ALL_ARCHS="arm mips x86 x86_64 mac_ia32"
    408   local PREFIX ARCH LIST
    409 
    410   print_gyp "{"
    411   incr_gyp_margin
    412 
    413     print_gyp "'variables': {"
    414     incr_gyp_margin
    415 
    416       # First, the common sources and defines
    417       print_gyp_source_variable "openssl_common_sources" \
    418           $(get_gyp_list "$ALL_PREFIXES" _SOURCES)
    419 
    420       print_gyp_variable "openssl_common_defines" \
    421           $(get_gyp_list "$ALL_PREFIXES" _DEFINES)
    422 
    423       # Now, conditions section with add architecture-specific sub-sections.
    424       for ARCH in $ALL_ARCHS; do
    425         # Convert ARCH to gyp-specific architecture name
    426         case $ARCH in
    427           x86)
    428             GYP_ARCH=ia32
    429             ;;
    430           x86_64)
    431             GYP_ARCH=x64
    432             ;;
    433           *)
    434             GYP_ARCH=$ARCH
    435             ;;
    436         esac
    437 
    438         print_gyp_source_variable "openssl_${ARCH}_source_excludes" \
    439             $(get_gyp_list "$ALL_PREFIXES" _SOURCES_EXCLUDES_ $ARCH)
    440 
    441         print_gyp_source_variable "openssl_${ARCH}_sources" \
    442             $(get_gyp_list "$ALL_PREFIXES" _SOURCES_ $ARCH)
    443 
    444         print_gyp_variable "openssl_${ARCH}_defines" \
    445             $(get_gyp_list "$ALL_PREFIXES" _DEFINES_ $ARCH)
    446 
    447       done # for ARCH
    448 
    449     decr_gyp_margin
    450     print_gyp "}"  # variables
    451 
    452   decr_gyp_margin
    453   print_gyp "}"  # top-level dict.
    454 }
    455 
    456 dump "Generating 64-bit configuration header file."
    457 mkdir -p $PROGDIR/config/x64/openssl/
    458 sed \
    459   -e 's|^#define RC4_INT unsigned char|#define RC4_INT unsigned int|g' \
    460   -e 's|^#define BN_LLONG|#undef BN_LLONG|g' \
    461   -e 's|^#define THIRTY_TWO_BIT|#undef THIRTY_TWO_BIT|g' \
    462   -e 's|^#undef SIXTY_FOUR_BIT_LONG|#define SIXTY_FOUR_BIT_LONG|g' \
    463   -e 's|^#define BF_PTR|#undef BF_PTR|g' \
    464   $PROGDIR/openssl/include/openssl/opensslconf.h \
    465   > $PROGDIR/config/x64/openssl/opensslconf.h
    466 
    467 dump "Generating OS X 32-bit configuration header file."
    468 mkdir -p $PROGDIR/config/mac/ia32/openssl/
    469 sed \
    470   -e '4a#ifndef OPENSSL_SYSNAME_MACOSX\n# define OPENSSL_SYSNAME_MACOSX\n#endif' \
    471   -e 's|^#define RC4_INT unsigned char|#define RC4_INT unsigned int|g' \
    472   -e 's|^#define DES_LONG unsigned int|#define DES_LONG unsigned long|g' \
    473   $PROGDIR/openssl/include/openssl/opensslconf.h \
    474   > $PROGDIR/config/mac/ia32/openssl/opensslconf.h
    475 
    476 dump "Generating .gypi file."
    477 . $ANDROID_SRC_DIR/openssl.config
    478 generate_gyp_file > $PROGDIR/openssl.gypi.new
    479 run mv $PROGDIR/openssl.gypi $PROGDIR/openssl.gypi.old
    480 run mv $PROGDIR/openssl.gypi.new $PROGDIR/openssl.gypi
    481 run rm $PROGDIR/openssl.gypi.old
    482 
    483 dump "Done."
    484