blob: 2f67c5083720dbda0db6081daf5afe313dbcc527 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001#!/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 google/protobuf/stubs/pbconfig.h $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