• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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