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