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 7OS=$1 8ARCH=$2 9 10if [[ $# < 2 ]]; then 11 echo "No arguments provided. This script is intended to be run from Maven." 12 exit 1 13fi 14 15# Under Cygwin, bash doesn't have these in PATH when called from Maven which 16# runs in Windows version of Java. 17export PATH="/bin:/usr/bin:$PATH" 18 19############################################################################ 20# Helper functions 21############################################################################ 22E_PARAM_ERR=98 23E_ASSERT_FAILED=99 24 25# Usage: 26fail() 27{ 28 echo "ERROR: $1" 29 echo 30 exit $E_ASSERT_FAILED 31} 32 33# Usage: assertEq VAL1 VAL2 $LINENO 34assertEq () 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> 51checkArch () 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> 95checkDependencies () 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 129echo "Building protoc, OS=$OS ARCH=$ARCH" 130 131# Nested double quotes are unintuitive, but it works. 132cd "$(dirname "$0")" 133 134WORKING_DIR=$(pwd) 135CONFIGURE_ARGS="--disable-shared" 136 137MAKE_TARGET="protoc" 138if [[ "$OS" == windows ]]; then 139 MAKE_TARGET="${MAKE_TARGET}.exe" 140fi 141 142# Override the default value set in configure.ac that has '-g' which produces 143# huge binary. 144CXXFLAGS="-DNDEBUG" 145LDFLAGS="" 146 147if [[ "$(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 158elif [[ "$(uname)" == MINGW32* ]]; then 159 assertEq "$OS" windows $LINENO 160 assertEq "$ARCH" x86_32 $LINENO 161elif [[ "$(uname)" == MINGW64* ]]; then 162 assertEq "$OS" windows $LINENO 163 assertEq "$ARCH" x86_64 $LINENO 164elif [[ "$(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 188elif [[ "$(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 199else 200 fail "Unsupported system: $(uname)" 201fi 202 203# Statically link libgcc and libstdc++. 204# -s to produce stripped binary. 205# And they don't work under Mac. 206if [[ "$OS" != osx ]]; then 207 LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++ -s" 208fi 209 210export CXXFLAGS LDFLAGS 211 212TARGET_FILE=target/protoc.exe 213 214cd "$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 220if [[ "$OS" == osx ]]; then 221 # Since Mac linker doesn't accept "-s", we need to run strip 222 strip $TARGET_FILE || exit 1 223fi 224 225checkArch $TARGET_FILE && checkDependencies $TARGET_FILE 226