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