Home | History | Annotate | Download | only in protoc-artifacts
      1 #!/bin/bash
      2 
      3 # Builds protoc executable into target/protoc.exe
      4 # To be run from Maven.
      5 # Usage: build-protoc.sh <OS> <ARCH>
      6 # <OS> and <ARCH> are ${os.detected.name} and ${os.detected.arch} from os-maven-plugin
      7 OS=$1
      8 ARCH=$2
      9 
     10 if [[ $# < 2 ]]; then
     11   echo "No arguments provided. This script is intended to be run from Maven."
     12   exit 1
     13 fi
     14 
     15 # Under Cygwin, bash doesn't have these in PATH when called from Maven which
     16 # runs in Windows version of Java.
     17 export PATH="/bin:/usr/bin:$PATH"
     18 
     19 ############################################################################
     20 # Helper functions
     21 ############################################################################
     22 E_PARAM_ERR=98
     23 E_ASSERT_FAILED=99
     24 
     25 # Usage:
     26 fail()
     27 {
     28   echo "ERROR: $1"
     29   echo
     30   exit $E_ASSERT_FAILED
     31 }
     32 
     33 # Usage: assertEq VAL1 VAL2 $LINENO
     34 assertEq ()
     35 {
     36   lineno=$3
     37   if [ -z "$lineno" ]; then
     38     echo "lineno not given"
     39     exit $E_PARAM_ERR
     40   fi
     41 
     42   if [[ "$1" != "$2" ]]; then
     43     echo "Assertion failed:  \"$1\" == \"$2\""
     44     echo "File \"$0\", line $lineno"    # Give name of file and line number.
     45     exit $E_ASSERT_FAILED
     46   fi
     47 }
     48 
     49 # Checks the artifact is for the expected architecture
     50 # Usage: checkArch <path-to-protoc>
     51 checkArch ()
     52 {
     53   echo
     54   echo "Checking file format ..."
     55   if [[ "$OS" == windows || "$OS" == linux ]]; then
     56     format="$(objdump -f "$1" | grep -o "file format .*$" | grep -o "[^ ]*$")"
     57     echo Format=$format
     58     if [[ "$OS" == linux ]]; then
     59       if [[ "$ARCH" == x86_32 ]]; then
     60         assertEq $format "elf32-i386" $LINENO
     61       elif [[ "$ARCH" == x86_64 ]]; then
     62         assertEq $format "elf64-x86-64" $LINENO
     63       else
     64         fail "Unsupported arch: $ARCH"
     65       fi
     66     else
     67       # $OS == windows
     68       if [[ "$ARCH" == x86_32 ]]; then
     69         assertEq $format "pei-i386" $LINENO
     70       elif [[ "$ARCH" == x86_64 ]]; then
     71         assertEq $format "pei-x86-64" $LINENO
     72       else
     73         fail "Unsupported arch: $ARCH"
     74       fi
     75     fi
     76   elif [[ "$OS" == osx ]]; then
     77     format="$(file -b "$1" | grep -o "[^ ]*$")"
     78     echo Format=$format
     79     if [[ "$ARCH" == x86_32 ]]; then
     80       assertEq $format "i386" $LINENO
     81     elif [[ "$ARCH" == x86_64 ]]; then
     82       assertEq $format "x86_64" $LINENO
     83     else
     84       fail "Unsupported arch: $ARCH"
     85     fi
     86   else
     87     fail "Unsupported system: $OS"
     88   fi
     89   echo
     90 }
     91 
     92 # Checks the dependencies of the artifact. Artifacts should only depend on
     93 # system libraries.
     94 # Usage: checkDependencies <path-to-protoc>
     95 checkDependencies ()
     96 {
     97   if [[ "$OS" == windows ]]; then
     98     dump_cmd='objdump -x '"$1"' | fgrep "DLL Name"'
     99     white_list="KERNEL32\.dll\|msvcrt\.dll"
    100   elif [[ "$OS" == linux ]]; then
    101     dump_cmd='ldd '"$1"
    102     if [[ "$ARCH" == x86_32 ]]; then
    103       white_list="linux-gate\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux\.so\.2"
    104     elif [[ "$ARCH" == x86_64 ]]; then
    105       white_list="linux-vdso\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux-x86-64\.so\.2"
    106     fi
    107   elif [[ "$OS" == osx ]]; then
    108     dump_cmd='otool -L '"$1"' | fgrep dylib'
    109     white_list="libz\.1\.dylib\|libstdc++\.6\.dylib\|libSystem\.B\.dylib"
    110   fi
    111   if [[ -z "$white_list" || -z "$dump_cmd" ]]; then
    112     fail "Unsupported platform $OS-$ARCH."
    113   fi
    114   echo "Checking for expected dependencies ..."
    115   eval $dump_cmd | grep -i "$white_list" || fail "doesn't show any expected dependencies"
    116   echo "Checking for unexpected dependencies ..."
    117   eval $dump_cmd | grep -i -v "$white_list"
    118   ret=$?
    119   if [[ $ret == 0 ]]; then
    120     fail "found unexpected dependencies (listed above)."
    121   elif [[ $ret != 1 ]]; then
    122     fail "Error when checking dependencies."
    123   fi  # grep returns 1 when "not found", which is what we expect
    124   echo "Dependencies look good."
    125   echo
    126 }
    127 ############################################################################
    128 
    129 echo "Building protoc, OS=$OS ARCH=$ARCH"
    130 
    131 # Nested double quotes are unintuitive, but it works.
    132 cd "$(dirname "$0")"
    133 
    134 WORKING_DIR=$(pwd)
    135 CONFIGURE_ARGS="--disable-shared"
    136 
    137 MAKE_TARGET="protoc"
    138 if [[ "$OS" == windows ]]; then
    139   MAKE_TARGET="${MAKE_TARGET}.exe"
    140 fi
    141 
    142 # Override the default value set in configure.ac that has '-g' which produces
    143 # huge binary.
    144 CXXFLAGS="-DNDEBUG"
    145 LDFLAGS=""
    146 
    147 if [[ "$(uname)" == CYGWIN* ]]; then
    148   assertEq "$OS" windows $LINENO
    149   # Use mingw32 compilers because executables produced by Cygwin compiler
    150   # always have dependency on Cygwin DLL.
    151   if [[ "$ARCH" == x86_64 ]]; then
    152     CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
    153   elif [[ "$ARCH" == x86_32 ]]; then
    154     CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-pc-mingw32"
    155   else
    156     fail "Unsupported arch by CYGWIN: $ARCH"
    157   fi
    158 elif [[ "$(uname)" == MINGW32* ]]; then
    159   assertEq "$OS" windows $LINENO
    160   assertEq "$ARCH" x86_32 $LINENO
    161 elif [[ "$(uname)" == MINGW64* ]]; then
    162   assertEq "$OS" windows $LINENO
    163   assertEq "$ARCH" x86_64 $LINENO
    164 elif [[ "$(uname)" == Linux* ]]; then
    165   if [[ "$OS" == linux ]]; then
    166     if [[ "$ARCH" == x86_64 ]]; then
    167       CXXFLAGS="$CXXFLAGS -m64"
    168     elif [[ "$ARCH" == x86_32 ]]; then
    169       CXXFLAGS="$CXXFLAGS -m32"
    170     else
    171       fail "Unsupported arch: $ARCH"
    172     fi
    173   elif [[ "$OS" == windows ]]; then
    174     # Cross-compilation for Windows
    175     # TODO(zhangkun83) MinGW 64 always adds dependency on libwinpthread-1.dll,
    176     # which is undesirable for repository deployment.
    177     CONFIGURE_ARGS="$CONFIGURE_ARGS"
    178     if [[ "$ARCH" == x86_64 ]]; then
    179       CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
    180     elif [[ "$ARCH" == x86_32 ]]; then
    181       CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-w64-mingw32"
    182     else
    183       fail "Unsupported arch: $ARCH"
    184     fi
    185   else
    186     fail "Cannot build $OS on $(uname)"
    187   fi
    188 elif [[ "$(uname)" == Darwin* ]]; then
    189   assertEq "$OS" osx $LINENO
    190   # Make the binary compatible with OSX 10.7 and later
    191   CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.7"
    192   if [[ "$ARCH" == x86_64 ]]; then
    193     CXXFLAGS="$CXXFLAGS -m64"
    194   elif [[ "$ARCH" == x86_32 ]]; then
    195     CXXFLAGS="$CXXFLAGS -m32"
    196   else
    197     fail "Unsupported arch: $ARCH"
    198   fi
    199 else
    200   fail "Unsupported system: $(uname)"
    201 fi
    202 
    203 # Statically link libgcc and libstdc++.
    204 # -s to produce stripped binary.
    205 # And they don't work under Mac.
    206 if [[ "$OS" != osx ]]; then
    207   LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++ -s"
    208 fi
    209 
    210 export CXXFLAGS LDFLAGS
    211 
    212 TARGET_FILE=target/protoc.exe
    213 
    214 cd "$WORKING_DIR"/.. && ./configure $CONFIGURE_ARGS &&
    215   cd src && make clean && make $MAKE_TARGET &&
    216   cd "$WORKING_DIR" && mkdir -p target &&
    217   (cp ../src/protoc $TARGET_FILE || cp ../src/protoc.exe $TARGET_FILE) ||
    218   exit 1
    219 
    220 if [[ "$OS" == osx ]]; then
    221   # Since Mac linker doesn't accept "-s", we need to run strip
    222   strip $TARGET_FILE || exit 1
    223 fi
    224 
    225 checkArch $TARGET_FILE && checkDependencies $TARGET_FILE
    226