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